]> git.saurik.com Git - apple/ld64.git/blobdiff - src/ld/Resolver.cpp
ld64-241.9.tar.gz
[apple/ld64.git] / src / ld / Resolver.cpp
index 2502820c01b6a5210bdbe225cf4a0249eb427cbf..a5405a9951057673fb0cdf1cd9c5a629acebdec2 100644 (file)
@@ -47,8 +47,6 @@
 #include <vector>
 #include <list>
 #include <algorithm>
-#include <ext/hash_map>
-#include <ext/hash_set>
 #include <dlfcn.h>
 #include <AvailabilityMacros.h>
 
@@ -80,8 +78,6 @@ public:
                                                                                                        _name(nm) {}
        // overrides of ld::Atom
        virtual const ld::File*                                         file() const            { return NULL; }
-       virtual bool                                                            translationUnitSource(const char** dir, const char** nm) const
-                                                                                                                                       { return false; }
        virtual const char*                                                     name() const            { return _name; }
        virtual uint64_t                                                        size() const            { return 0; }
        virtual uint64_t                                                        objectAddress() const { return 0; }
@@ -116,8 +112,8 @@ public:
 
        // overrides of ld::Atom
        virtual const ld::File*                         file() const            { return _aliasOf.file(); }
-       virtual bool                                            translationUnitSource(const char** dir, const char** nm) const
-                                                                                                                       { return _aliasOf.translationUnitSource(dir, nm); }
+       virtual const char*                                             translationUnitSource() const
+                                                                                                                       { return _aliasOf.translationUnitSource(); }
        virtual const char*                                     name() const            { return _name; }
        virtual uint64_t                                        size() const            { return 0; }
        virtual uint64_t                                        objectAddress() const { return _aliasOf.objectAddress(); }
@@ -133,6 +129,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;
@@ -149,8 +150,6 @@ public:
        static SectionBoundaryAtom*                     makeOldSectionBoundaryAtom(const char* name, bool start);
        
        // overrides of ld::Atom
-       virtual bool                                            translationUnitSource(const char** dir, const char** nm) const
-                                                                                                                       { return false; }
        virtual const ld::File*                         file() const            { return NULL; }
        virtual const char*                                     name() const            { return _name; }
        virtual uint64_t                                        size() const            { return 0; }
@@ -215,8 +214,6 @@ public:
        static SegmentBoundaryAtom*                     makeOldSegmentBoundaryAtom(const char* name, bool start); 
        
        // overrides of ld::Atom
-       virtual bool                                            translationUnitSource(const char** dir, const char** nm) const
-                                                                                                                       { return false; }
        virtual const ld::File*                         file() const            { return NULL; }
        virtual const char*                                     name() const            { return _name; }
        virtual uint64_t                                        size() const            { return 0; }
@@ -285,25 +282,82 @@ void Resolver::initializeState()
                _internal.objcObjectConstraint = ld::File::objcConstraintGC;
        
        _internal.cpuSubType = _options.subArchitecture();
+       
+       // 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;
        
        //_symbolTable.printStatistics();
 }
 
 
+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 ) {
+                       _internal.linkerOptionLibraries.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 ) {
+                       _internal.linkerOptionFrameworks.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;
+               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 ) {
+                       for (relocatable::File::LinkerOptionsList::const_iterator it=lo->begin(); it != lo->end(); ++it) {
+                               this->doLinkerOption(*it, file.path());
+                       }
+               }
+               
                // update which form of ObjC is being used
                switch ( file.objCConstraint() ) {
                        case ld::File::objcConstraintNone:
@@ -315,27 +369,59 @@ 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;
                        
-               // remember if any objc classes built for fix-and-continue
-               if ( objFile->objcReplacementClasses() )
-                       _internal.hasObjcReplacementClasses = true;
-                       
                // remember if any .o file did not have MH_SUBSECTIONS_VIA_SYMBOLS bit set
                if ( ! objFile->canScatterAtoms() )
                        _internal.allObjectFilesScatterable = false;
@@ -367,7 +453,16 @@ 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;
                }
        }
@@ -383,17 +478,52 @@ 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;
+               }
+               if ( _options.checkDylibsAreAppExtensionSafe() && !dylibFile->appExtensionSafe() ) {
+                       warning("linking against dylib 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->iOSMinVersion() >= 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, @loaderpath, etc.", depInstallName, dylibFile->path());
+                       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());
                }
        }
 
@@ -401,7 +531,9 @@ void Resolver::doFile(const ld::File& file)
 
 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);
@@ -427,16 +559,16 @@ void Resolver::doAtom(const ld::Atom& atom)
                                                        }
                                                        else if ( _options.outputKind() == Options::kDynamicLibrary ) {
                                                                if ( atom.file() != NULL )
-                                                                       warning("target OS does not support re-exporting symbol %s from %s\n", SymbolTable::demangle(name), atom.file()->path());
+                                                                       warning("target OS does not support re-exporting symbol %s from %s\n", _options.demangleSymbol(name), atom.file()->path());
                                                                else
-                                                                       warning("target OS does not support re-exporting symbol %s\n", SymbolTable::demangle(name));
+                                                                       warning("target OS does not support re-exporting symbol %s\n", _options.demangleSymbol(name));
                                                        }
                                                }
                                                else {
                                                        if ( atom.file() != NULL )
-                                                               warning("cannot export hidden symbol %s from %s", SymbolTable::demangle(name), atom.file()->path());
+                                                               warning("cannot export hidden symbol %s from %s", _options.demangleSymbol(name), atom.file()->path());
                                                        else
-                                                               warning("cannot export hidden symbol %s", SymbolTable::demangle(name));
+                                                               warning("cannot export hidden symbol %s", _options.demangleSymbol(name));
                                                }
                                        }
                                }
@@ -446,7 +578,7 @@ void Resolver::doAtom(const ld::Atom& atom)
                                                (const_cast<ld::Atom*>(&atom))->setScope(ld::Atom::scopeGlobal);
                                        }
                                        else {
-                                               throwf("requested re-export symbol %s is not from a dylib, but from %s\n", SymbolTable::demangle(name), atom.file()->path());
+                                               throwf("requested re-export symbol %s is not from a dylib, but from %s\n", _options.demangleSymbol(name), atom.file()->path());
                                        }
                                }
                                break;
@@ -457,7 +589,7 @@ void Resolver::doAtom(const ld::Atom& atom)
                                        //fprintf(stderr, "demote %s to hidden\n", name);
                                }
                                if ( _options.canReExportSymbols() && _options.shouldReExport(name) ) {
-                                       throwf("requested re-export symbol %s is not from a dylib, but from %s\n", SymbolTable::demangle(name), atom.file()->path());
+                                       throwf("requested re-export symbol %s is not from a dylib, but from %s\n", _options.demangleSymbol(name), atom.file()->path());
                                }
                                break;
                }
@@ -465,7 +597,8 @@ 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);
 
 
@@ -478,7 +611,8 @@ void Resolver::doAtom(const ld::Atom& atom)
                        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);
+                                       const AliasAtom* alias = new AliasAtom(atom, it->alias);
+                                       _aliasesFromCmdLine.push_back(alias);
                                        this->doAtom(*alias);
                                }
                        }
@@ -492,9 +626,9 @@ void Resolver::doAtom(const ld::Atom& atom)
        if ( atom.contentType() == ld::Atom::typeLTOtemporary )
                _haveLLVMObjs = true;
        
-       // if we've already partitioned into final sections, and lto needs a symbol very late, add it
-       if ( _addToFinalSection ) 
-               _internal.addAtom(atom);
+       // 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
@@ -519,6 +653,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:
@@ -536,6 +672,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 ) ) {
@@ -647,14 +785,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));
                }
        }
        
@@ -706,6 +864,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:
@@ -722,6 +881,12 @@ 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:
+#endif
                                if ( fit->binding == ld::Fixup::bindingByContentBound ) {
                                        // normally this was done in convertReferencesToIndirect()
                                        // but a archive loaded .o file may have a forward reference
@@ -801,7 +966,7 @@ public:
        }
 };
 
-void Resolver::deadStripOptimize()
+void Resolver::deadStripOptimize(bool force)
 {
        // only do this optimization with -dead_strip
        if ( ! _options.deadCodeStrip() ) 
@@ -856,22 +1021,71 @@ void Resolver::deadStripOptimize()
        // now remove all non-live atoms from _atoms
        const bool log = false;
        if ( log ) {
-               fprintf(stderr, "deadStripOptimize() all atoms with liveness:\n");
+               fprintf(stderr, "deadStripOptimize() all %ld atoms with liveness:\n", _atoms.size());
                for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
-                       fprintf(stderr, "  live=%d  name=%s\n", (*it)->live(), (*it)->name());
+                       const ld::File* file = (*it)->file();
+                       fprintf(stderr, "  live=%d  atom=%p  name=%s from=%s\n", (*it)->live(), *it, (*it)->name(),  (file ? file->path() : "<internal>"));
                }
        }
        
-       if ( _haveLLVMObjs ) {
+       if ( _haveLLVMObjs && !force ) {
                // <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 {
                _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), NotLive()), _atoms.end());
        }
+
+       if ( log ) {
+               fprintf(stderr, "deadStripOptimize() %ld remaining atoms\n", _atoms.size());
+               for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+                       fprintf(stderr, "  live=%d  atom=%p  name=%s\n", (*it)->live(), *it, (*it)->name());
+               }
+       }
 }
 
 
+// This is called when LTO is used but -dead_strip is not used.
+// Some undefines were eliminated by LTO, but others were not.
+void Resolver::remainingUndefines(std::vector<const char*>& undefs)
+{
+       StringSet  undefSet;
+       // search all atoms for references that are unbound
+       for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+               const ld::Atom* atom = *it;
+               for (ld::Fixup::iterator fit=atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+                       switch ( (ld::Fixup::TargetBinding)fit->binding ) {
+                               case ld::Fixup::bindingByNameUnbound:
+                                       assert(0 && "should not be by-name this late");
+                                       undefSet.insert(fit->u.name);
+                                       break;
+                               case ld::Fixup::bindingsIndirectlyBound:
+                                       if ( _internal.indirectBindingTable[fit->u.bindingIndex] == NULL ) {
+                                               undefSet.insert(_symbolTable.indirectName(fit->u.bindingIndex));
+                                       }
+                                       break;
+                               case ld::Fixup::bindingByContentBound:
+                               case ld::Fixup::bindingNone:
+                               case ld::Fixup::bindingDirectlyBound:
+                                       break;
+                       }
+               }
+       }
+       // look for any initial undefines that are still undefined
+       for (Options::UndefinesIterator uit=_options.initialUndefinesBegin(); uit != _options.initialUndefinesEnd(); ++uit) {
+               if ( ! _symbolTable.hasName(*uit) ) {
+                       undefSet.insert(*uit);
+               }
+       }
+       
+       // copy set to vector
+       for (StringSet::const_iterator it=undefSet.begin(); it != undefSet.end(); ++it) {
+        fprintf(stderr, "undef: %s\n", *it);
+               undefs.push_back(*it);
+       }
+}
+
 void Resolver::liveUndefines(std::vector<const char*>& undefs)
 {
        StringSet  undefSet;
@@ -990,7 +1204,7 @@ bool Resolver::printReferencedBy(const char* name, SymbolTable::IndirectBindingS
                                                ++foundReferenceCount;
                                        }
                                        else {
-                                               fprintf(stderr, "      %s in %s\n", SymbolTable::demangle(atom->name()), pathLeafName(atom->file()->path()));
+                                               fprintf(stderr, "      %s in %s\n", _options.demangleSymbol(atom->name()), pathLeafName(atom->file()->path()));
                                                ++foundReferenceCount;
                                                break; // if undefined used twice in a function, only show first
                                        }
@@ -1029,9 +1243,10 @@ void Resolver::checkUndefines(bool force)
                        break;
        }
        std::vector<const char*> unresolvableUndefines;
-       // <rdar://problem/10052396> LTO many have eliminated need for some undefines
-       if ( _options.deadCodeStrip() || _haveLLVMObjs ) 
+       if ( _options.deadCodeStrip() )
                this->liveUndefines(unresolvableUndefines);
+    else if( _haveLLVMObjs ) 
+               this->remainingUndefines(unresolvableUndefines); // <rdar://problem/10052396> LTO may have eliminated need for some undefines
        else    
                _symbolTable.undefines(unresolvableUndefines);
 
@@ -1056,7 +1271,7 @@ void Resolver::checkUndefines(bool force)
                        for (int i=0; i < unresolvableCount; ++i) {
                                const char* name = unresolvableUndefines[i];
                                unsigned int slot = _symbolTable.findSlotForName(name);
-                               fprintf(stderr, "  \"%s\", referenced from:\n", SymbolTable::demangle(name));
+                               fprintf(stderr, "  \"%s\", referenced from:\n", _options.demangleSymbol(name));
                                // scan all atoms for references
                                bool foundAtomReference = printReferencedBy(name, slot);
                                // scan command line options
@@ -1073,6 +1288,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) {
@@ -1174,8 +1393,6 @@ const ld::Atom* Resolver::entryPoint(bool searchArchives)
                else if ( _internal.indirectBindingTable[slot]->definition() == ld::Atom::definitionProxy ) {
                        if ( makingDylib ) 
                                throwf("-init function (%s) found in linked dylib, must be in dylib being linked", symbolName);
-                       else
-                               throwf("entry point (%s) found in linked dylib, must be in executable being linked", symbolName);
                }
                return _internal.indirectBindingTable[slot];
        }
@@ -1252,17 +1469,60 @@ 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));
+}
 
-       // add entry point
+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()
 {
+       const bool log = false;
+       if ( log ) {
+               fprintf(stderr, "removeCoalescedAwayAtoms() starts with %lu atoms\n", _atoms.size());
+       }
        _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), AtomCoalescedAway()), _atoms.end());
+       if ( log ) {
+               fprintf(stderr, "removeCoalescedAwayAtoms() after removing coalesced atoms, %lu remain\n", _atoms.size());
+               for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+                       fprintf(stderr, "  atom=%p %s\n", *it, (*it)->name());
+               }
+       }
 }
 
 void Resolver::linkTimeOptimize()
@@ -1270,12 +1530,15 @@ void Resolver::linkTimeOptimize()
        // only do work here if some llvm obj files where loaded
        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.allGlobalsAReDeadStripRoots      = _options.allGlobalsAreDeadStripRoots();
+       optOpt.preserveAllGlobals                       = _options.allGlobalsAreDeadStripRoots() || _options.hasExportRestrictList();
        optOpt.verbose                                          = _options.verbose();
        optOpt.saveTemps                                        = _options.saveTempFiles();
        optOpt.pie                                                      = _options.positionIndependentExecutable();
@@ -1284,51 +1547,43 @@ void Resolver::linkTimeOptimize()
        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.arch                                                     = _options.architecture();
+       optOpt.mcpu                                                     = _options.mcpuLTO();
        optOpt.llvmOptions                                      = &_options.llvmOptions();
+       optOpt.initialUndefines                         = &_options.initialUndefines();
        
        std::vector<const ld::Atom*>            newAtoms;
        std::vector<const char*>                        additionalUndefines; 
-       if ( ! lto::optimize(_atoms, _internal, _inputFiles.nextInputOrdinal(), optOpt, *this, newAtoms, 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();
-       
-       // add new atoms into their final section
-       for (std::vector<const ld::Atom*>::iterator it = newAtoms.begin(); it != newAtoms.end(); ++it) {
-               _internal.addAtom(**it);
-       }
 
-       // remove temp lto section and move all of its atoms to their final section
-       ld::Internal::FinalSection* tempLTOsection = NULL;
-       for (std::vector<ld::Internal::FinalSection*>::iterator sit=_internal.sections.begin(); sit != _internal.sections.end(); ++sit) {
-               ld::Internal::FinalSection* sect = *sit;
-               if ( sect->type() == ld::Section::typeTempLTO ) {
-                       tempLTOsection = sect;
-                       // remove temp lto section from final image
-                       _internal.sections.erase(sit);
-                       break;
-               }
-       }
-       // lto atoms now have proper section info, so add to final section
-       if ( tempLTOsection != NULL ) {
-               for (std::vector<const ld::Atom*>::iterator ait=tempLTOsection->atoms.begin(); ait != tempLTOsection->atoms.end(); ++ait) {
-                       const ld::Atom* atom = *ait;
-                       if ( ! atom->coalescedAway() ) {
-                               this->convertReferencesToIndirect(*atom);
-                               _internal.addAtom(*atom);
-                       }
-               }
+       // 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)
-       _addToFinalSection = true;
        for(std::vector<const char*>::iterator uit = additionalUndefines.begin(); uit != additionalUndefines.end(); ++uit) {
                const char *targetName = *uit;
                // these symbols may or may not already be in linker's symbol table
@@ -1336,7 +1591,6 @@ void Resolver::linkTimeOptimize()
                        _inputFiles.searchLibraries(targetName, true, true, false, *this);
                }
        }
-       _addToFinalSection = false;
 
        // if -dead_strip on command line
        if ( _options.deadCodeStrip() ) {
@@ -1345,23 +1599,28 @@ void Resolver::linkTimeOptimize()
                        (const_cast<ld::Atom*>(*it))->setLive((*it)->dontDeadStrip());
                }
                // and re-compute dead code
-               this->deadStripOptimize();
-
-               // remove newly dead atoms from each section
-               for (std::vector<ld::Internal::FinalSection*>::iterator sit=_internal.sections.begin(); sit != _internal.sections.end(); ++sit) {
-                       ld::Internal::FinalSection* sect = *sit;
-                       sect->atoms.erase(std::remove_if(sect->atoms.begin(), sect->atoms.end(), NotLive()), sect->atoms.end());
+               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)
-               _addToFinalSection = true;
                this->resolveUndefines();
-               _addToFinalSection = false;
        }
        else {
                // last chance to check for undefines
+               this->resolveUndefines();
                this->checkUndefines(true);
 
                // check new code does not override some dylib
@@ -1370,6 +1629,47 @@ void Resolver::linkTimeOptimize()
 }
 
 
+void Resolver::tweakWeakness()
+{
+       // <rdar://problem/7977374> Add command line options to control symbol weak-def bit on exported symbols                 
+       if ( _options.hasWeakBitTweaks() ) {
+               for (std::vector<ld::Internal::FinalSection*>::iterator sit = _internal.sections.begin(); sit != _internal.sections.end(); ++sit) {
+                       ld::Internal::FinalSection* sect = *sit;
+                       for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                               const ld::Atom* atom = *ait;
+                               if ( atom->definition() != ld::Atom::definitionRegular ) 
+                                       continue;
+                               const char* name = atom->name();
+                               if ( atom->scope() == ld::Atom::scopeGlobal ) {
+                                       if ( atom->combine() == ld::Atom::combineNever ) {
+                                               if ( _options.forceWeak(name) )
+                                                       (const_cast<ld::Atom*>(atom))->setCombine(ld::Atom::combineByName);
+                                       }
+                                       else if ( atom->combine() == ld::Atom::combineByName ) {
+                                               if ( _options.forceNotWeak(name) )
+                                                       (const_cast<ld::Atom*>(atom))->setCombine(ld::Atom::combineNever);
+                                       }
+                               }
+                               else {
+                                       if ( _options.forceWeakNonWildCard(name) )
+                                               warning("cannot force to be weak, non-external symbol %s", name);
+                                       else if ( _options.forceNotWeakNonWildcard(name) )
+                                               warning("cannot force to be not-weak, non-external symbol %s", name);
+                               }
+                       }
+               }
+       }
+}
+
+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()
 {
        this->initializeState();
@@ -1380,9 +1680,13 @@ void Resolver::resolve()
        this->deadStripOptimize();
        this->checkUndefines();
        this->checkDylibSymbolCollisions();
+       this->syncAliases();
        this->removeCoalescedAwayAtoms();
-       this->fillInInternalState();
+       this->fillInEntryPoint();
        this->linkTimeOptimize();
+       this->fillInInternalState();
+       this->tweakWeakness();
+    _symbolTable.checkDuplicateSymbols();
 }