]> git.saurik.com Git - apple/ld64.git/blobdiff - src/ld/Resolver.cpp
ld64-274.2.tar.gz
[apple/ld64.git] / src / ld / Resolver.cpp
index 588def7be0f2857c60a099425e40700a7f987134..1c8f16e041bdcc99c210757518feca3b0bbd479a 100644 (file)
 #include <vector>
 #include <list>
 #include <algorithm>
-#include <ext/hash_map>
-#include <ext/hash_set>
 #include <dlfcn.h>
 #include <AvailabilityMacros.h>
 
 #include "Options.h"
 
 #include "ld.hpp"
+#include "Bitcode.hpp"
 #include "InputFiles.h"
 #include "SymbolTable.h"
 #include "Resolver.h"
@@ -131,6 +130,11 @@ public:
        virtual ld::Atom::UnwindInfo::iterator  endUnwind() const       { return NULL; }
        virtual ld::Atom::LineInfo::iterator    beginLineInfo() const { return  NULL; }
        virtual ld::Atom::LineInfo::iterator    endLineInfo() const { return NULL; }
+
+       void                                                                    setFinalAliasOf() const {
+                                                                                               (const_cast<AliasAtom*>(this))->setAttributesFromAtom(_aliasOf);
+                                                                                               (const_cast<AliasAtom*>(this))->setScope(ld::Atom::scopeGlobal);
+                                                                                       }
                                                                                                                        
 private:
        const char*                                                     _name;
@@ -279,13 +283,23 @@ void Resolver::initializeState()
                _internal.objcObjectConstraint = ld::File::objcConstraintGC;
        
        _internal.cpuSubType = _options.subArchitecture();
+       _internal.minOSVersion = _options.minOSversion();
+       _internal.derivedPlatformLoadCommand = 0;
+       
+       // In -r mode, look for -linker_option additions
+       if ( _options.outputKind() == Options::kObjectFile ) {
+               ld::relocatable::File::LinkerOptionsList lo = _options.linkerOptions();
+               for (relocatable::File::LinkerOptionsList::const_iterator it=lo.begin(); it != lo.end(); ++it) {
+                       doLinkerOption(*it, "command line");
+               }
+       }
 }
 
 void Resolver::buildAtomList()
 {
        // each input files contributes initial atoms
        _atoms.reserve(1024);
-       _inputFiles.forEachInitialAtom(*this);
+       _inputFiles.forEachInitialAtom(*this, _internal);
     
        _completedInitialObjectFiles = true;
        
@@ -293,12 +307,119 @@ void Resolver::buildAtomList()
 }
 
 
+void Resolver::doLinkerOption(const std::vector<const char*>& linkerOption, const char* fileName)
+{
+       if ( linkerOption.size() == 1 ) {
+               const char* lo1 = linkerOption.front();
+               if ( strncmp(lo1, "-l", 2) == 0) {
+                       if (_internal.linkerOptionLibraries.count(&lo1[2]) == 0) {
+                               _internal.unprocessedLinkerOptionLibraries.insert(&lo1[2]);
+                       }
+               }
+               else {
+                       warning("unknown linker option from object file ignored: '%s' in %s", lo1, fileName);
+               }
+       }
+       else if ( linkerOption.size() == 2 ) {
+               const char* lo2a = linkerOption[0];
+               const char* lo2b = linkerOption[1];
+               if ( strcmp(lo2a, "-framework") == 0) {
+                       if (_internal.linkerOptionFrameworks.count(lo2b) == 0) {
+                               _internal.unprocessedLinkerOptionFrameworks.insert(lo2b);
+                       }
+               }
+               else {
+                       warning("unknown linker option from object file ignored: '%s' '%s' from %s", lo2a, lo2b, fileName);
+               }
+       }
+       else {
+               warning("unknown linker option from object file ignored, starting with: '%s' from %s", linkerOption.front(), fileName);
+       }
+}
+
+static void userReadableSwiftVersion(uint8_t value, char versionString[64])
+{
+       switch (value) {
+               case 1:
+                       strcpy(versionString, "1.0");
+                       break;
+               case 2:
+                       strcpy(versionString, "1.1");
+                       break;
+               case 3:
+                       strcpy(versionString, "2.0");
+                       break;
+               case 4:
+                       strcpy(versionString, "3.0");
+                       break;
+               default:
+                       sprintf(versionString, "unknown ABI version 0x%02X", value);
+       }
+}
+
 void Resolver::doFile(const ld::File& file)
 {
        const ld::relocatable::File* objFile = dynamic_cast<const ld::relocatable::File*>(&file);
        const ld::dylib::File* dylibFile = dynamic_cast<const ld::dylib::File*>(&file);
 
        if ( objFile != NULL ) {
+               // if file has linker options, process them
+               ld::relocatable::File::LinkerOptionsList* lo = objFile->linkerOptions();
+               if ( lo != NULL && !_options.ignoreAutoLink() ) {
+                       for (relocatable::File::LinkerOptionsList::const_iterator it=lo->begin(); it != lo->end(); ++it) {
+                               this->doLinkerOption(*it, file.path());
+                       }
+                       // <rdar://problem/23053404> process any additional linker-options introduced by this new archive member being loaded
+                       if ( _completedInitialObjectFiles ) {
+                               _inputFiles.addLinkerOptionLibraries(_internal, *this);
+                               _inputFiles.createIndirectDylibs();
+                       }
+               }
+               // Resolve bitcode section in the object file
+               if ( _options.bundleBitcode() ) {
+                       if ( objFile->getBitcode() == NULL ) {
+                               // No bitcode section, figure out if the object file comes from LTO/compiler static library
+                               if (objFile->sourceKind() != ld::relocatable::File::kSourceLTO &&
+                                       objFile->sourceKind() != ld::relocatable::File::kSourceCompilerArchive ) {
+                                       switch ( _options.platform() ) {
+                                       case Options::kPlatformOSX:
+                                       case Options::kPlatformUnknown:
+                                               warning("all bitcode will be dropped because '%s' was built without bitcode. "
+                                                               "You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target. ", file.path());
+                                               _internal.filesWithBitcode.clear();
+                                               _internal.dropAllBitcode = true;
+                                               break;
+                                       case Options::kPlatformiOS:
+                                               throwf("'%s' does not contain bitcode. "
+                                                          "You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target.", file.path());
+                                               break;
+                                       case Options::kPlatformWatchOS:
+#if SUPPORT_APPLE_TV
+                                       case Options::kPlatform_tvOS:
+#endif
+                                               throwf("'%s' does not contain bitcode. "
+                                                               "You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE) or obtain an updated library from the vendor", file.path());
+                                               break;
+                                       }
+                               }
+                       } else {
+                               // contains bitcode, check if it is just a marker
+                               if ( objFile->getBitcode()->isMarker() ) {
+                                       // if -bitcode_verify_bundle is used, check if all the object files participate in the linking have full bitcode embedded.
+                                       // error on any marker encountered.
+                                       if ( _options.verifyBitcode() )
+                                               throwf("bitcode bundle could not be generated because '%s' was built without full bitcode. "
+                                                          "All object files and libraries for bitcode must be generated from Xcode Archive or Install build",
+                                                          objFile->path());
+                                       // update the internal state that marker is encountered.
+                                       _internal.embedMarkerOnly = true;
+                                       _internal.filesWithBitcode.clear();
+                                       _internal.dropAllBitcode = true;
+                               } else if ( !_internal.dropAllBitcode )
+                                       _internal.filesWithBitcode.push_back(objFile);
+                       }
+               }
+
                // update which form of ObjC is being used
                switch ( file.objCConstraint() ) {
                        case ld::File::objcConstraintNone:
@@ -310,19 +431,55 @@ void Resolver::doFile(const ld::File& file)
                                        throwf("command line specified -objc_gc_only, but file is retain/release based: %s", file.path());
                                if ( _options.objcGc() )
                                        throwf("command line specified -objc_gc, but file is retain/release based: %s", file.path());
-                               _internal.objcObjectConstraint = ld::File::objcConstraintRetainRelease;
+                               if ( !_options.targetIOSSimulator() && (_internal.objcObjectConstraint != ld::File::objcConstraintRetainReleaseForSimulator) )
+                                       _internal.objcObjectConstraint = ld::File::objcConstraintRetainRelease;
                                break;
                        case ld::File::objcConstraintRetainReleaseOrGC:
                                if ( _internal.objcObjectConstraint == ld::File::objcConstraintNone )
                                        _internal.objcObjectConstraint = ld::File::objcConstraintRetainReleaseOrGC;
+                               if ( _options.targetIOSSimulator() )
+                                       warning("linking ObjC for iOS Simulator, but object file (%s) was compiled for MacOSX", file.path());
                                break;
                        case ld::File::objcConstraintGC:
                                if ( _internal.objcObjectConstraint == ld::File::objcConstraintRetainRelease )
                                        throwf("%s built with incompatible Garbage Collection settings to link with previous .o files", file.path());
                                _internal.objcObjectConstraint = ld::File::objcConstraintGC;
+                               if ( _options.targetIOSSimulator() )
+                                       warning("linking ObjC for iOS Simulator, but object file (%s) was compiled for MacOSX", file.path());
+                               break;
+                       case ld::File::objcConstraintRetainReleaseForSimulator:
+                               if ( _internal.objcObjectConstraint == ld::File::objcConstraintNone ) {
+                                       if ( !_options.targetIOSSimulator() && (_options.outputKind() != Options::kObjectFile) )
+                                               warning("ObjC object file (%s) was compiled for iOS Simulator, but linking for MacOSX", file.path());
+                                       _internal.objcObjectConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
+                               }
+                               else if ( _internal.objcObjectConstraint != ld::File::objcConstraintRetainReleaseForSimulator ) {
+                                       _internal.objcObjectConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
+                               }
                                break;
                }
        
+               // verify all files use same version of Swift language
+               if ( file.swiftVersion() != 0 ) {
+                       if ( _internal.swiftVersion == 0 ) {
+                               _internal.swiftVersion = file.swiftVersion();
+                       }
+                       else if ( file.swiftVersion() != _internal.swiftVersion ) {
+                               char fileVersion[64];
+                               char otherVersion[64];
+                               userReadableSwiftVersion(file.swiftVersion(), fileVersion);
+                               userReadableSwiftVersion(_internal.swiftVersion, otherVersion);
+                               if ( file.swiftVersion() > _internal.swiftVersion ) {
+                                       throwf("%s compiled with newer version of Swift language (%s) than previous files (%s)", 
+                                                  file.path(), fileVersion, otherVersion);
+                               }
+                               else {
+                                       throwf("%s compiled with older version of Swift language (%s) than previous files (%s)", 
+                                              file.path(), fileVersion, otherVersion);
+                               }
+                       }
+               }
+               
                // in -r mode, if any .o files have dwarf then add UUID to output .o file
                if ( objFile->debugInfo() == ld::relocatable::File::kDebugInfoDwarf )
                        _internal.someObjectFileHasDwarf = true;
@@ -331,6 +488,18 @@ void Resolver::doFile(const ld::File& file)
                if ( ! objFile->canScatterAtoms() )
                        _internal.allObjectFilesScatterable = false;
        
+               // update minOSVersion off all .o files
+               uint32_t objMinOS = objFile->minOSVersion();
+               if ( !objMinOS )
+                       _internal.objectFileFoundWithNoVersion = true;
+
+               uint32_t objPlatformLC = objFile->platformLoadCommand();
+               if ( (objPlatformLC != 0) && (_internal.derivedPlatformLoadCommand == 0) && (_options.outputKind() == Options::kObjectFile) )
+                       _internal.derivedPlatformLoadCommand = objPlatformLC;
+
+               if ( (_options.outputKind() == Options::kObjectFile) && (objMinOS > _internal.minOSVersion) )
+                       _internal.minOSVersion = objMinOS;
+
                // update cpu-sub-type
                cpu_subtype_t nextObjectSubType = file.cpuSubType();
                switch ( _options.architecture() ) {
@@ -358,11 +527,71 @@ void Resolver::doFile(const ld::File& file)
                                break;
                                
                        case CPU_TYPE_X86_64:
-                               _internal.cpuSubType = CPU_SUBTYPE_X86_64_ALL;
+                               if ( _options.subArchitecture() != nextObjectSubType ) {
+                                       if ( _options.allowSubArchitectureMismatches() ) {
+                                               warning("object file %s was built for different x86_64 sub-type (%d) than link command line (%d)", 
+                                                       file.path(), nextObjectSubType, _options.subArchitecture());
+                                       }
+                                       else {
+                                               throwf("object file %s was built for different x86_64 sub-type (%d) than link command line (%d)", 
+                                                       file.path(), nextObjectSubType, _options.subArchitecture());
+                                       }
+                               }
                                break;
                }
        }
        if ( dylibFile != NULL ) {
+               // Check dylib for bitcode, if the library install path is relative path or @rpath, it has to contain bitcode
+               if ( _options.bundleBitcode() ) {
+                       bool isSystemFramework = ( dylibFile->installPath() != NULL ) && ( dylibFile->installPath()[0] == '/' );
+                       if ( dylibFile->getBitcode() == NULL && !isSystemFramework ) {
+                               // Check if the dylib is from toolchain by checking the path
+                               char tcLibPath[PATH_MAX];
+                               char ldPath[PATH_MAX];
+                               char tempPath[PATH_MAX];
+                               uint32_t bufSize = PATH_MAX;
+                               // toolchain library path should pointed to *.xctoolchain/usr/lib
+                               if ( _NSGetExecutablePath(ldPath, &bufSize) != -1 ) {
+                                       if ( realpath(ldPath, tempPath) != NULL ) {
+                                               char* lastSlash = strrchr(tempPath, '/');
+                                               if ( lastSlash != NULL )
+                                                       strcpy(lastSlash, "/../lib");
+                                       }
+                               }
+                               // Compare toolchain library path to the dylib path
+                               if ( realpath(tempPath, tcLibPath) == NULL ||
+                                        realpath(dylibFile->path(), tempPath) == NULL ||
+                                        strncmp(tcLibPath, tempPath, strlen(tcLibPath)) != 0 ) {
+                                       switch ( _options.platform() ) {
+                                       case Options::kPlatformOSX:
+                                       case Options::kPlatformUnknown:
+                                               warning("all bitcode will be dropped because '%s' was built without bitcode. "
+                                                               "You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target.", file.path());
+                                               _internal.filesWithBitcode.clear();
+                                               _internal.dropAllBitcode = true;
+                                               break;
+                                       case Options::kPlatformiOS:
+                                               throwf("'%s' does not contain bitcode. "
+                                                          "You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target.", file.path());
+                                               break;
+                                       case Options::kPlatformWatchOS:
+#if SUPPORT_APPLE_TV
+                                       case Options::kPlatform_tvOS:
+#endif
+                                               throwf("'%s' does not contain bitcode. "
+                                                               "You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE) or obtain an updated library from the vendor", file.path());
+                                               break;
+                                       }
+                               }
+                       }
+                       // Error on bitcode marker in non-system frameworks if -bitcode_verify is used
+                       if ( _options.verifyBitcode() && !isSystemFramework &&
+                                dylibFile->getBitcode() != NULL && dylibFile->getBitcode()->isMarker() )
+                               throwf("bitcode bundle could not be generated because '%s' was built without full bitcode. "
+                                          "All frameworks and dylibs for bitcode must be generated from Xcode Archive or Install build",
+                                          dylibFile->path());
+               }
+
                // update which form of ObjC dylibs are being linked
                switch ( dylibFile->objCConstraint() ) {
                        case ld::File::objcConstraintNone:
@@ -374,25 +603,85 @@ void Resolver::doFile(const ld::File& file)
                                        throwf("command line specified -objc_gc_only, but dylib is retain/release based: %s", file.path());
                                if ( _options.objcGc() )
                                        throwf("command line specified -objc_gc, but dylib is retain/release based: %s", file.path());
+                               if ( _options.targetIOSSimulator() )
+                                       warning("linking ObjC for iOS Simulator, but dylib (%s) was compiled for MacOSX", file.path());
                                _internal.objcDylibConstraint = ld::File::objcConstraintRetainRelease;
                                break;
                        case ld::File::objcConstraintRetainReleaseOrGC:
                                if ( _internal.objcDylibConstraint == ld::File::objcConstraintNone )
                                        _internal.objcDylibConstraint = ld::File::objcConstraintRetainReleaseOrGC;
+                               if ( _options.targetIOSSimulator() )
+                                       warning("linking ObjC for iOS Simulator, but dylib (%s) was compiled for MacOSX", file.path());
                                break;
                        case ld::File::objcConstraintGC:
                                if ( _internal.objcDylibConstraint == ld::File::objcConstraintRetainRelease )
                                        throwf("%s built with incompatible Garbage Collection settings to link with previous dylibs", file.path());
-                               _internal.objcDylibConstraint = ld::File::objcConstraintGC;
+                               if ( _options.targetIOSSimulator() )
+                                       warning("linking ObjC for iOS Simulator, but dylib (%s) was compiled for MacOSX", file.path());
+                               _internal.objcDylibConstraint = ld::File::objcConstraintGC;
+                               break;
+                       case ld::File::objcConstraintRetainReleaseForSimulator:
+                               if ( _internal.objcDylibConstraint == ld::File::objcConstraintNone )
+                                       _internal.objcDylibConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
+                               else if ( _internal.objcDylibConstraint != ld::File::objcConstraintRetainReleaseForSimulator ) {
+                                       warning("ObjC dylib (%s) was compiled for iOS Simulator, but dylibs others were compiled for MacOSX", file.path());
+                                       _internal.objcDylibConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
+                               }
                                break;
                }
+
+               // <rdar://problem/25680358> verify dylibs use same version of Swift language
+               if ( file.swiftVersion() != 0 ) {
+                       if ( _internal.swiftVersion == 0 ) {
+                               _internal.swiftVersion = file.swiftVersion();
+                       }
+                       else if ( file.swiftVersion() != _internal.swiftVersion ) {
+                               char fileVersion[64];
+                               char otherVersion[64];
+                               userReadableSwiftVersion(file.swiftVersion(), fileVersion);
+                               userReadableSwiftVersion(_internal.swiftVersion, otherVersion);
+                               if ( file.swiftVersion() > _internal.swiftVersion ) {
+                                       throwf("%s compiled with newer version of Swift language (%s) than previous files (%s)", 
+                                                  file.path(), fileVersion, otherVersion);
+                               }
+                               else {
+                                       throwf("%s compiled with older version of Swift language (%s) than previous files (%s)", 
+                                              file.path(), fileVersion, otherVersion);
+                               }
+                       }
+               }
+
+               if ( _options.checkDylibsAreAppExtensionSafe() && !dylibFile->appExtensionSafe() ) {
+                       warning("linking against a dylib which is not safe for use in application extensions: %s", file.path());
+               }
+               const char* depInstallName = dylibFile->installPath();
+               // <rdar://problem/17229513> embedded frameworks are only supported on iOS 8 and later
+               if ( (depInstallName != NULL) && (depInstallName[0] != '/') ) {
+                       if ( (_options.iOSVersionMin() != iOSVersionUnset) && (_options.iOSVersionMin() < iOS_8_0) ) {
+                               // <rdar://problem/17598404> only warn about linking against embedded dylib if it is built for iOS 8 or later
+                               if ( dylibFile->minOSVersion() >= iOS_8_0 )
+                                       throwf("embedded dylibs/frameworks are only supported on iOS 8.0 and later (%s)", depInstallName);
+                       }
+               }
+               if ( _options.sharedRegionEligible() ) {
+                       assert(depInstallName != NULL);
+                       if ( depInstallName[0] == '@' ) {
+                               warning("invalid -install_name (%s) in dependent dylib (%s). Dylibs/frameworks which might go in dyld shared cache "
+                                               "cannot link with dylib that uses @rpath, @loader_path, etc.", depInstallName, dylibFile->path());
+                       } else if ( (strncmp(depInstallName, "/usr/lib/", 9) != 0) && (strncmp(depInstallName, "/System/Library/", 16) != 0) ) {
+                               warning("invalid -install_name (%s) in dependent dylib (%s). Dylibs/frameworks which might go in dyld shared cache "
+                                               "cannot link with dylibs that won't be in the shared cache", depInstallName, dylibFile->path());
+                       }
+               }
        }
 
 }
 
 void Resolver::doAtom(const ld::Atom& atom)
 {
-       //fprintf(stderr, "Resolver::doAtom(%p), name=%s, sect=%s\n", &atom, atom.name(), atom.section().sectionName());
+       //fprintf(stderr, "Resolver::doAtom(%p), name=%s, sect=%s, scope=%d\n", &atom, atom.name(), atom.section().sectionName(), atom.scope());
+       if ( _ltoCodeGenFinished && (atom.contentType() == ld::Atom::typeLTOtemporary) && (atom.scope() != ld::Atom::scopeTranslationUnit) )
+               warning("'%s' is implemented in bitcode, but it was loaded too late", atom.name());
 
        // add to list of known atoms
        _atoms.push_back(&atom);
@@ -456,21 +745,28 @@ void Resolver::doAtom(const ld::Atom& atom)
 
        // work around for kernel that uses 'l' labels in assembly code
        if ( (atom.symbolTableInclusion() == ld::Atom::symbolTableNotInFinalLinkedImages) 
-                       && (atom.name()[0] == 'l') && (_options.outputKind() == Options::kStaticExecutable) )
+                       && (atom.name()[0] == 'l') && (_options.outputKind() == Options::kStaticExecutable) 
+                       && (strncmp(atom.name(), "ltmp", 4) != 0) )
                (const_cast<ld::Atom*>(&atom))->setSymbolTableInclusion(ld::Atom::symbolTableIn);
 
 
        // tell symbol table about non-static atoms
        if ( atom.scope() != ld::Atom::scopeTranslationUnit ) {
-               _symbolTable.add(atom, _options.deadCodeStrip() && _completedInitialObjectFiles);
+               _symbolTable.add(atom, _options.deadCodeStrip() && (_completedInitialObjectFiles || _options.allowDeadDuplicates()));
                
                // add symbol aliases defined on the command line
                if ( _options.haveCmdLineAliases() ) {
                        const std::vector<Options::AliasPair>& aliases = _options.cmdLineAliases();
                        for (std::vector<Options::AliasPair>::const_iterator it=aliases.begin(); it != aliases.end(); ++it) {
                                if ( strcmp(it->realName, atom.name()) == 0 ) {
-                                       const ld::Atom* alias = new AliasAtom(atom, it->alias);
-                                       this->doAtom(*alias);
+                                       if ( strcmp(it->realName, it->alias) == 0 ) {
+                                               warning("ignoring alias of itself '%s'", it->realName);
+                                       }
+                                       else {
+                                               const AliasAtom* alias = new AliasAtom(atom, it->alias);
+                                               _aliasesFromCmdLine.push_back(alias);
+                                               this->doAtom(*alias);
+                                       }
                                }
                        }
                }
@@ -482,11 +778,17 @@ void Resolver::doAtom(const ld::Atom& atom)
        // remember if any atoms are proxies that require LTO
        if ( atom.contentType() == ld::Atom::typeLTOtemporary )
                _haveLLVMObjs = true;
-               
+       
+       // remember if any atoms are aliases
+       if ( atom.section().type() == ld::Section::typeTempAlias )
+               _haveAliases = true;
+       
        if ( _options.deadCodeStrip() ) {
                // add to set of dead-strip-roots, all symbols that the compiler marks as don't strip
                if ( atom.dontDeadStrip() )
                        _deadStripRoots.insert(&atom);
+               else if ( atom.dontDeadStripIfReferencesLive() )
+                       _dontDeadStripIfReferencesLive.push_back(&atom);
                        
                if ( atom.scope() == ld::Atom::scopeGlobal ) {
                        // <rdar://problem/5524973> -exported_symbols_list that has wildcards and -dead_strip
@@ -506,6 +808,8 @@ bool Resolver::isDtraceProbe(ld::Fixup::Kind kind)
                case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
                case ld::Fixup::kindStoreARMDtraceCallSiteNop:
                case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
+               case ld::Fixup::kindStoreARM64DtraceCallSiteNop:
+               case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear:
                case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
                case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
                case ld::Fixup::kindDtraceExtra:
@@ -523,6 +827,8 @@ void Resolver::convertReferencesToIndirect(const ld::Atom& atom)
        const ld::Atom* dummy;
        ld::Fixup::iterator end = atom.fixupsEnd();
        for (ld::Fixup::iterator fit=atom.fixupsBegin(); fit != end; ++fit) {
+               if ( fit->kind == ld::Fixup::kindLinkerOptimizationHint )
+                       _internal.someObjectHasOptimizationHints = true;
                switch ( fit->binding ) { 
                        case ld::Fixup::bindingByNameUnbound:
                                if ( isDtraceProbe(fit->kind) && (_options.outputKind() != Options::kObjectFile ) ) {
@@ -634,14 +940,34 @@ void Resolver::resolveUndefines()
                        }
                }
        }
-               
+       
+       // Use linker options to resolve any remaining undefined symbols
+       if ( !_internal.linkerOptionLibraries.empty() || !_internal.linkerOptionFrameworks.empty() ) {
+               std::vector<const char*> undefineNames;
+               _symbolTable.undefines(undefineNames);
+               if ( undefineNames.size() != 0 ) {
+                       for (std::vector<const char*>::iterator it = undefineNames.begin(); it != undefineNames.end(); ++it) {
+                               const char* undef = *it;
+                               if ( ! _symbolTable.hasName(undef) ) {
+                                       _inputFiles.searchLibraries(undef, true, true, false, *this);
+                               }
+                       }
+               }
+       }
+       
        // create proxies as needed for undefined symbols
        if ( (_options.undefinedTreatment() != Options::kUndefinedError) || (_options.outputKind() == Options::kObjectFile) ) {
                std::vector<const char*> undefineNames;
                _symbolTable.undefines(undefineNames);
                for(std::vector<const char*>::iterator it = undefineNames.begin(); it != undefineNames.end(); ++it) {
-                       // make proxy
-                       this->doAtom(*new UndefinedProxyAtom(*it));
+                       const char* undefName = *it;
+                       // <rdar://problem/14547001> "ld -r -exported_symbol _foo" has wrong error message if _foo is undefined
+                       bool makeProxy = true;
+                       if ( (_options.outputKind() == Options::kObjectFile) && _options.hasExportMaskList() && _options.shouldExport(undefName) ) 
+                               makeProxy = false;
+                       
+                       if ( makeProxy ) 
+                               this->doAtom(*new UndefinedProxyAtom(undefName));
                }
        }
        
@@ -657,6 +983,10 @@ void Resolver::resolveUndefines()
                }
        }
        
+       // After resolving all the undefs within the linkageUnit, record all the remaining undefs and all the proxies.
+       if (_options.bundleBitcode() && _options.hideSymbols())
+               _symbolTable.mustPreserveForBitcode(_internal.allUndefProxies);
+
 }
 
 
@@ -693,6 +1023,7 @@ void Resolver::markLive(const ld::Atom& atom, WhyLiveBackChain* previous)
                        case ld::Fixup::kindNoneGroupSubordinate:
                        case ld::Fixup::kindNoneGroupSubordinateFDE:
                        case ld::Fixup::kindNoneGroupSubordinateLSDA:
+                       case ld::Fixup::kindNoneGroupSubordinatePersonality:
                        case ld::Fixup::kindSetTargetAddress:
                        case ld::Fixup::kindSubtractTargetAddress:
                        case ld::Fixup::kindStoreTargetAddressLittleEndian32:
@@ -709,6 +1040,14 @@ void Resolver::markLive(const ld::Atom& atom, WhyLiveBackChain* previous)
                        case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA:
                        case ld::Fixup::kindStoreTargetAddressARMBranch24:
                        case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+#if SUPPORT_ARCH_arm64
+                       case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+                       case ld::Fixup::kindStoreTargetAddressARM64Page21:
+                       case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+                       case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21:
+                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPage21:
+#endif
                                if ( fit->binding == ld::Fixup::bindingByContentBound ) {
                                        // normally this was done in convertReferencesToIndirect()
                                        // but a archive loaded .o file may have a forward reference
@@ -840,6 +1179,38 @@ void Resolver::deadStripOptimize(bool force)
                this->markLive(**it, &rootChain);
        }
        
+       // special case atoms that need to be live if they reference something live
+       if ( ! _dontDeadStripIfReferencesLive.empty() ) {
+               for (std::vector<const ld::Atom*>::iterator it=_dontDeadStripIfReferencesLive.begin(); it != _dontDeadStripIfReferencesLive.end(); ++it) {
+                       const Atom* liveIfRefLiveAtom = *it;
+                       //fprintf(stderr, "live-if-live atom: %s\n", liveIfRefLiveAtom->name());
+                       if ( liveIfRefLiveAtom->live() )
+                               continue;
+                       bool hasLiveRef = false;
+                       for (ld::Fixup::iterator fit=liveIfRefLiveAtom->fixupsBegin(); fit != liveIfRefLiveAtom->fixupsEnd(); ++fit) {
+                               const Atom* target = NULL;
+                               switch ( fit->binding ) {
+                                       case ld::Fixup::bindingDirectlyBound:
+                                               target = fit->u.target;
+                                               break;
+                                       case ld::Fixup::bindingsIndirectlyBound:
+                                               target = _internal.indirectBindingTable[fit->u.bindingIndex];
+                                               break;
+                                       default:
+                                               break;
+                               }
+                               if ( (target != NULL) && target->live() ) 
+                                       hasLiveRef = true;
+                       }
+                       if ( hasLiveRef ) {
+                               WhyLiveBackChain rootChain;
+                               rootChain.previous = NULL;
+                               rootChain.referer = liveIfRefLiveAtom;
+                               this->markLive(*liveIfRefLiveAtom, &rootChain);
+                       }
+               }
+       }
+       
        // now remove all non-live atoms from _atoms
        const bool log = false;
        if ( log ) {
@@ -851,10 +1222,13 @@ void Resolver::deadStripOptimize(bool force)
        }
        
        if ( _haveLLVMObjs && !force ) {
+                std::copy_if(_atoms.begin(), _atoms.end(), std::back_inserter(_internal.deadAtoms), NotLiveLTO() );
                // <rdar://problem/9777977> don't remove combinable atoms, they may come back in lto output
                _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), NotLiveLTO()), _atoms.end());
+               _symbolTable.removeDeadAtoms();
        }
        else {
+                std::copy_if(_atoms.begin(), _atoms.end(), std::back_inserter(_internal.deadAtoms), NotLive() );
                _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), NotLive()), _atoms.end());
        }
 
@@ -1109,6 +1483,10 @@ void Resolver::checkUndefines(bool force)
                                        else if ( _options.hasReExportList() && _options.shouldReExport(name) ) {
                                                fprintf(stderr, "     -reexported_symbols_list command line option\n");
                                        }
+                                       else if ( (_options.outputKind() == Options::kDynamicExecutable)
+                                                       && (_options.entryName() != NULL) && (strcmp(name, _options.entryName()) == 0) ) {
+                                               fprintf(stderr, "     implicit entry/start for main executable\n");
+                                       }
                                        else {
                                                bool isInitialUndefine = false;
                                                for (Options::UndefinesIterator uit=_options.initialUndefinesBegin(); uit != _options.initialUndefinesEnd(); ++uit) {
@@ -1286,7 +1664,7 @@ void Resolver::fillInInternalState()
        
        // <rdar://problem/7783918> make sure there is a __text section so that codesigning works
        if ( (_options.outputKind() == Options::kDynamicLibrary) || (_options.outputKind() == Options::kDynamicBundle) )
-               _internal.getFinalSection(ld::Section("__TEXT", "__text", ld::Section::typeCode));
+               _internal.getFinalSection(*new ld::Section("__TEXT", "__text", ld::Section::typeCode));
 }
 
 void Resolver::fillInEntryPoint()
@@ -1294,7 +1672,38 @@ void Resolver::fillInEntryPoint()
        _internal.entryPoint = this->entryPoint(true);
 }
 
-
+void Resolver::syncAliases()
+{
+       if ( !_haveAliases || (_options.outputKind() == Options::kObjectFile) )
+               return;
+       
+       // Set attributes of alias to match its found target
+       for (std::vector<const ld::Atom*>::iterator it = _atoms.begin(); it != _atoms.end(); ++it) {
+               const ld::Atom* atom = *it;
+               if ( atom->section().type() == ld::Section::typeTempAlias ) {
+                       assert(atom->fixupsBegin() != atom->fixupsEnd());
+                       for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+                               const ld::Atom* target;
+                               ld::Atom::Scope scope;
+                               assert(fit->kind == ld::Fixup::kindNoneFollowOn);
+                               switch ( fit->binding ) {
+                                       case ld::Fixup::bindingByNameUnbound:
+                                               break;
+                                       case ld::Fixup::bindingsIndirectlyBound:
+                                               target = _internal.indirectBindingTable[fit->u.bindingIndex];
+                                               assert(target != NULL);
+                                               scope = atom->scope();
+                                               (const_cast<Atom*>(atom))->setAttributesFromAtom(*target);
+                                               // alias has same attributes as target, except for scope
+                                               (const_cast<Atom*>(atom))->setScope(scope);
+                                               break;
+                                       default:
+                                               assert(0 && "internal error: unexpected alias binding");
+                               }
+                       }
+               }
+       }
+}
 
 void Resolver::removeCoalescedAwayAtoms()
 {
@@ -1317,39 +1726,70 @@ void Resolver::linkTimeOptimize()
        if ( ! _haveLLVMObjs )
                return;
 
+       // <rdar://problem/15314161> LTO: Symbol multiply defined error should specify exactly where the symbol is found
+    _symbolTable.checkDuplicateSymbols();
+
        // run LLVM lto code-gen
        lto::OptimizeOptions optOpt;
        optOpt.outputFilePath                           = _options.outputFilePath();
        optOpt.tmpObjectFilePath                        = _options.tempLtoObjectPath();
+       optOpt.ltoCachePath                                     = _options.ltoCachePath();
+       optOpt.ltoPruneInterval                         = _options.ltoPruneInterval();
+       optOpt.ltoPruneAfter                            = _options.ltoPruneAfter();
+       optOpt.ltoMaxCacheSize                          = _options.ltoMaxCacheSize();
        optOpt.preserveAllGlobals                       = _options.allGlobalsAreDeadStripRoots() || _options.hasExportRestrictList();
        optOpt.verbose                                          = _options.verbose();
        optOpt.saveTemps                                        = _options.saveTempFiles();
+       optOpt.ltoCodegenOnly                                   = _options.ltoCodegenOnly();
        optOpt.pie                                                      = _options.positionIndependentExecutable();
        optOpt.mainExecutable                           = _options.linkingMainExecutable();;
        optOpt.staticExecutable                         = (_options.outputKind() == Options::kStaticExecutable);
        optOpt.relocatable                                      = (_options.outputKind() == Options::kObjectFile);
        optOpt.allowTextRelocs                          = _options.allowTextRelocs();
        optOpt.linkerDeadStripping                      = _options.deadCodeStrip();
+       optOpt.needsUnwindInfoSection           = _options.needsUnwindInfoSection();
+       optOpt.keepDwarfUnwind                          = _options.keepDwarfUnwind();
+       optOpt.verboseOptimizationHints     = _options.verboseOptimizationHints();
+       optOpt.armUsesZeroCostExceptions    = _options.armUsesZeroCostExceptions();
+       optOpt.simulator                                        = _options.targetIOSSimulator();
+       optOpt.ignoreMismatchPlatform           = ((_options.outputKind() == Options::kPreload) || (_options.outputKind() == Options::kStaticExecutable));
+       optOpt.bitcodeBundle                            = _options.bundleBitcode();
+       optOpt.maxDefaultCommonAlignment        = _options.maxDefaultCommonAlign();
        optOpt.arch                                                     = _options.architecture();
+       optOpt.mcpu                                                     = _options.mcpuLTO();
+       optOpt.platform                                         = _options.platform();
+       optOpt.minOSVersion                                     = _options.minOSversion();
        optOpt.llvmOptions                                      = &_options.llvmOptions();
+       optOpt.initialUndefines                         = &_options.initialUndefines();
        
        std::vector<const ld::Atom*>            newAtoms;
        std::vector<const char*>                        additionalUndefines; 
        if ( ! lto::optimize(_atoms, _internal, optOpt, *this, newAtoms, additionalUndefines) )
                return; // if nothing done
-               
+       _ltoCodeGenFinished = true;
        
        // add all newly created atoms to _atoms and update symbol table
        for(std::vector<const ld::Atom*>::iterator it = newAtoms.begin(); it != newAtoms.end(); ++it)
                this->doAtom(**it);
-               
+
        // some atoms might have been optimized way (marked coalesced), remove them
        this->removeCoalescedAwayAtoms();
 
-       // run through all atoms again and make sure newly codegened atoms have refernces bound
+       // run through all atoms again and make sure newly codegened atoms have references bound
        for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) 
                this->convertReferencesToIndirect(**it);
 
+       // adjust section of any new
+       for (std::vector<const AliasAtom*>::const_iterator it=_aliasesFromCmdLine.begin(); it != _aliasesFromCmdLine.end(); ++it) {
+               const AliasAtom* aliasAtom = *it;
+               // update fields in AliasAtom to match newly constructed mach-o atom
+               aliasAtom->setFinalAliasOf();
+       }
+       
+       // <rdar://problem/14609792> add any auto-link libraries requested by LTO output to dylibs to search
+       _inputFiles.addLinkerOptionLibraries(_internal, *this);
+       _inputFiles.createIndirectDylibs();
+
        // resolve new undefines (e.g calls to _malloc and _memcpy that llvm compiler conjures up)
        for(std::vector<const char*>::iterator uit = additionalUndefines.begin(); uit != additionalUndefines.end(); ++uit) {
                const char *targetName = *uit;
@@ -1369,12 +1809,25 @@ void Resolver::linkTimeOptimize()
                this->deadStripOptimize(true);
        }
        
+       // <rdar://problem/12386559> if -exported_symbols_list on command line, re-force scope
+       if ( _options.hasExportMaskList() ) {
+               for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+                       const ld::Atom* atom = *it;
+                       if ( atom->scope() == ld::Atom::scopeGlobal ) {
+                               if ( !_options.shouldExport(atom->name()) ) {
+                                       (const_cast<ld::Atom*>(atom))->setScope(ld::Atom::scopeLinkageUnit);
+                               }
+                       }
+               }
+       }
+       
        if ( _options.outputKind() == Options::kObjectFile ) {
                // if -r mode, add proxies for new undefines (e.g. ___stack_chk_fail)
                this->resolveUndefines();
        }
        else {
                // last chance to check for undefines
+               this->resolveUndefines();
                this->checkUndefines(true);
 
                // check new code does not override some dylib
@@ -1415,6 +1868,20 @@ void Resolver::tweakWeakness()
        }
 }
 
+void Resolver::buildArchivesList()
+{
+       // Determine which archives were linked and update the internal state.
+       _inputFiles.archives(_internal);
+}
+
+void Resolver::dumpAtoms() 
+{
+       fprintf(stderr, "Resolver all atoms:\n");
+       for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+               const ld::Atom* atom = *it;
+               fprintf(stderr, "  %p name=%s, def=%d\n", atom, atom->name(), atom->definition());
+       }
+}
 
 void Resolver::resolve()
 {
@@ -1426,12 +1893,14 @@ void Resolver::resolve()
        this->deadStripOptimize();
        this->checkUndefines();
        this->checkDylibSymbolCollisions();
+       this->syncAliases();
        this->removeCoalescedAwayAtoms();
        this->fillInEntryPoint();
        this->linkTimeOptimize();
        this->fillInInternalState();
        this->tweakWeakness();
     _symbolTable.checkDuplicateSymbols();
+       this->buildArchivesList();
 }