]> git.saurik.com Git - apple/ld64.git/blobdiff - src/ld/InputFiles.cpp
ld64-351.8.tar.gz
[apple/ld64.git] / src / ld / InputFiles.cpp
index 766b17cfc077d21f72ac24501a765bd538123ff9..2a79ae2ced8b5edcff7df38a3250c81e0ec1f6f8 100644 (file)
@@ -1,3 +1,4 @@
+
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
  *
  * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
@@ -49,8 +50,6 @@
 #include <vector>
 #include <list>
 #include <algorithm>
-#include <ext/hash_map>
-#include <ext/hash_set>
 #include <dlfcn.h>
 #include <AvailabilityMacros.h>
 
 #include "InputFiles.h"
 #include "macho_relocatable_file.h"
 #include "macho_dylib_file.h"
+#include "textstub_dylib_file.hpp"
 #include "archive_file.h"
 #include "lto_file.h"
 #include "opaque_section_file.h"
+#include "MachOFileAbstraction.hpp"
 #include "Snapshot.h"
 
 const bool _s_logPThreads = false;
@@ -80,16 +81,15 @@ public:
 class DSOHandleAtom : public ld::Atom {
 public:
                                                                        DSOHandleAtom(const char* nm, ld::Atom::Scope sc, 
-                                                                                                               ld::Atom::SymbolTableInclusion inc, bool preload=false)
-                                                                               : ld::Atom(preload ? _s_section_preload : _s_section, 
-                                                                                                       ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                                                                               ld::Atom::SymbolTableInclusion inc, ld::Section& sect=_s_section)
+                                                                               : ld::Atom(sect, ld::Atom::definitionRegular,
+                                                                                                  (sect == _s_section_text) ? ld::Atom::combineByName : ld::Atom::combineNever, 
+                                                                                                  // make "weak def" so that link succeeds even if app defines __dso_handle
                                                                                                        sc, ld::Atom::typeUnclassified, inc, true, false, false, 
                                                                                                         ld::Atom::Alignment(1)), _name(nm) {}
 
        virtual ld::File*                                               file() const                                    { return NULL; }
-       virtual bool                                                    translationUnitSource(const char** dir, const char** ) const 
-                                                                                                                                                       { return false; }
-       virtual const char*                                             name() const                                    { return _name; }
+  virtual const char*                                          name() const                                    { return _name; }
        virtual uint64_t                                                size() const                                    { return 0; }
        virtual uint64_t                                                objectAddress() const                   { return 0; }
        virtual void                                                    copyRawContent(uint8_t buffer[]) const
@@ -100,6 +100,7 @@ public:
        
        static ld::Section                                              _s_section;
        static ld::Section                                              _s_section_preload;
+       static ld::Section                                              _s_section_text;
        static DSOHandleAtom                                    _s_atomAll;
        static DSOHandleAtom                                    _s_atomExecutable;
        static DSOHandleAtom                                    _s_atomDylib;
@@ -107,18 +108,21 @@ public:
        static DSOHandleAtom                                    _s_atomDyld;
        static DSOHandleAtom                                    _s_atomObjectFile;
        static DSOHandleAtom                                    _s_atomPreload;
+       static DSOHandleAtom                                    _s_atomPreloadDSO;
 private:
        const char*                                                             _name;
 };
 ld::Section DSOHandleAtom::_s_section("__TEXT", "__mach_header", ld::Section::typeMachHeader, true);
 ld::Section DSOHandleAtom::_s_section_preload("__HEADER", "__mach_header", ld::Section::typeMachHeader, true);
+ld::Section DSOHandleAtom::_s_section_text("__TEXT", "__text", ld::Section::typeCode, false);
 DSOHandleAtom DSOHandleAtom::_s_atomAll("___dso_handle", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
 DSOHandleAtom DSOHandleAtom::_s_atomExecutable("__mh_execute_header", ld::Atom::scopeGlobal, ld::Atom::symbolTableInAndNeverStrip);
 DSOHandleAtom DSOHandleAtom::_s_atomDylib("__mh_dylib_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
 DSOHandleAtom DSOHandleAtom::_s_atomBundle("__mh_bundle_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
 DSOHandleAtom DSOHandleAtom::_s_atomDyld("__mh_dylinker_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
 DSOHandleAtom DSOHandleAtom::_s_atomObjectFile("__mh_object_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
-DSOHandleAtom DSOHandleAtom::_s_atomPreload("__mh_preload_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn, true);
+DSOHandleAtom DSOHandleAtom::_s_atomPreload("__mh_preload_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn, _s_section_preload);
+DSOHandleAtom DSOHandleAtom::_s_atomPreloadDSO("___dso_handle", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn, _s_section_text);
 
 
 
@@ -131,8 +135,6 @@ public:
                                                                                        _size(sz) {}
 
        virtual ld::File*                                               file() const                                    { return NULL; }
-       virtual bool                                                    translationUnitSource(const char** dir, const char** ) const 
-                                                                                                                                                       { return false; }
        virtual const char*                                             name() const                                    { return "page zero"; }
        virtual uint64_t                                                size() const                                    { return _size; }
        virtual uint64_t                                                objectAddress() const                   { return 0; }
@@ -159,8 +161,6 @@ public:
                                                                                        _size(sz) {}
 
        virtual ld::File*                                               file() const                                    { return NULL; }
-       virtual bool                                                    translationUnitSource(const char** dir, const char** ) const 
-                                                                                                                                                       { return false; }
        virtual const char*                                             name() const                                    { return "custom stack"; }
        virtual uint64_t                                                size() const                                    { return _size; }
        virtual uint64_t                                                objectAddress() const                   { return 0; }
@@ -177,13 +177,22 @@ private:
 ld::Section CustomStackAtom::_s_section("__UNIXSTACK", "__stack", ld::Section::typeStack, true);
 
 
+static bool isCompilerSupportLib(const char* path) {
+       const char* libName = strrchr(path, '/');
+       return ( (libName != NULL) && (strncmp(libName, "/libclang_rt", 12) == 0) );
+}
+
 
 const char* InputFiles::fileArch(const uint8_t* p, unsigned len)
 {
        const char* result = mach_o::relocatable::archName(p);
        if ( result != NULL  )
                 return result;
-                
+
+    result = mach_o::dylib::archName(p);
+    if ( result != NULL  )
+               return result;
+
        result = lto::archName(p, len);
        if ( result != NULL  )
                 return result;
@@ -195,7 +204,7 @@ const char* InputFiles::fileArch(const uint8_t* p, unsigned len)
        strcpy(unsupported, "unsupported file format (");
        for (unsigned i=0; i<len && i < 16; i++) {
                char buf[8];
-               sprintf(buf, " 0x%2x", p[i]);
+               sprintf(buf, " 0x%02X", p[i]);
                strcat(unsupported, buf);
        }
        strcat(unsupported, " )");
@@ -205,15 +214,26 @@ const char* InputFiles::fileArch(const uint8_t* p, unsigned len)
 
 ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib)
 {
+       // handle inlined framework first.
+       if (info.isInlined) {
+               auto interface = _options.findTAPIFile(info.path);
+               auto file = textstub::dylib::parse(info.path, std::move(interface), info.modTime, info.ordinal, _options, indirectDylib);
+               assert(file && "could not locate the inlined file");
+               if (!file)
+                       throwf("could not parse inline dylib file: %s(%s)", interface->getInstallName().c_str(), info.path);
+               return file;
+       }
        // map in whole file
-       uint64_t len = info.fileLen;
+       struct stat stat_buf;
        int fd = ::open(info.path, O_RDONLY, 0);
        if ( fd == -1 )
                throwf("can't open file, errno=%d", errno);
-       if ( info.fileLen < 20 )
-               throw "file too small";
-
-       uint8_t* p = (uint8_t*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+       if ( ::fstat(fd, &stat_buf) != 0 )
+               throwf("fstat(%s) failed, errno=%d\n", info.path, errno);
+       if ( stat_buf.st_size < 20 )
+               throwf("file too small (length=%llu)", stat_buf.st_size);
+       int64_t len = stat_buf.st_size;
+       uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
        if ( p == (uint8_t*)(-1) )
                throwf("can't map file, errno=%d", errno);
 
@@ -251,14 +271,23 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
                if ( sliceFound ) {
                        uint32_t fileOffset = OSSwapBigToHostInt32(archs[sliceToUse].offset);
                        len = OSSwapBigToHostInt32(archs[sliceToUse].size);
-                       if ( fileOffset+len > info.fileLen ) {
-                               throwf("truncated fat file. Slice from %u to %llu is past end of file with length %llu", 
-                                               fileOffset, fileOffset+len, info.fileLen);
+                       if ( fileOffset+len > stat_buf.st_size ) {
+                               // <rdar://problem/17593430> file size was read awhile ago.  If file is being written, wait a second to see if big enough now
+                               sleep(1);
+                               int64_t newFileLen = stat_buf.st_size;
+                               struct stat statBuffer;
+                               if ( stat(info.path, &statBuffer) == 0 ) {
+                                       newFileLen = statBuffer.st_size;
+                               }
+                               if ( fileOffset+len > newFileLen ) {
+                                       throwf("truncated fat file. Slice from %u to %llu is past end of file with length %llu", 
+                                               fileOffset, fileOffset+len, stat_buf.st_size);
+                               }
                        }
                        // if requested architecture is page aligned within fat file, then remap just that portion of file
                        if ( (fileOffset & 0x00000FFF) == 0 ) {
                                // unmap whole file
-                               munmap((caddr_t)p, info.fileLen);
+                               munmap((caddr_t)p, stat_buf.st_size);
                                // re-map just part we need
                                p = (uint8_t*)::mmap(NULL, len, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, fileOffset);
                                if ( p == (uint8_t*)(-1) )
@@ -276,8 +305,22 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
        objOpts.architecture            = _options.architecture();
        objOpts.objSubtypeMustMatch = !_options.allowSubArchitectureMismatches();
        objOpts.logAllFiles                     = _options.logAllFiles();
-       objOpts.convertUnwindInfo       = _options.needsUnwindInfoSection();
+       objOpts.warnUnwindConversionProblems    = _options.needsUnwindInfoSection();
+       objOpts.keepDwarfUnwind         = _options.keepDwarfUnwind();
+       objOpts.forceDwarfConversion= (_options.outputKind() == Options::kDyld);
+       objOpts.neverConvertDwarf   = !_options.needsUnwindInfoSection();
+       objOpts.verboseOptimizationHints = _options.verboseOptimizationHints();
+       objOpts.armUsesZeroCostExceptions = _options.armUsesZeroCostExceptions();
+       objOpts.simulator                       = _options.targetIOSSimulator();
+       objOpts.ignoreMismatchPlatform = ((_options.outputKind() == Options::kPreload) || (_options.outputKind() == Options::kStaticExecutable));
        objOpts.subType                         = _options.subArchitecture();
+       objOpts.platform                        = _options.platform();
+       objOpts.minOSVersion            = _options.minOSversion();
+       objOpts.srcKind                         = ld::relocatable::File::kSourceObj;
+       objOpts.treateBitcodeAsData     = _options.bitcodeKind() == Options::kBitcodeAsData;
+       objOpts.usingBitcode            = _options.bundleBitcode();
+       objOpts.maxDefaultCommonAlignment = _options.maxDefaultCommonAlign();
+
        ld::relocatable::File* objResult = mach_o::relocatable::parse(p, len, info.path, info.modTime, info.ordinal, objOpts);
        if ( objResult != NULL ) {
                OSAtomicAdd64(len, &_totalObjectSize);
@@ -286,17 +329,36 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
        }
 
        // see if it is an llvm object file
-       objResult = lto::parse(p, len, info.path, info.modTime, _options.architecture(), _options.subArchitecture(), _options.logAllFiles());
+       objResult = lto::parse(p, len, info.path, info.modTime, info.ordinal, _options.architecture(), _options.subArchitecture(), _options.logAllFiles(), _options.verboseOptimizationHints());
        if ( objResult != NULL ) {
                OSAtomicAdd64(len, &_totalObjectSize);
                OSAtomicIncrement32(&_totalObjectLoaded);
                return objResult;
        }
-       
-       // see if it is a dynamic library
-       ld::dylib::File* dylibResult = mach_o::dylib::parse(p, len, info.path, info.modTime, _options, info.ordinal, info.options.fBundleLoader, indirectDylib);
-       if ( dylibResult != NULL ) {
-               return dylibResult;
+
+       // see if it is a dynamic library (or text-based dynamic library)
+       ld::dylib::File* dylibResult;
+       bool dylibsNotAllowed = false;
+       switch ( _options.outputKind() ) {
+               case Options::kDynamicExecutable:
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:   
+                       dylibResult = mach_o::dylib::parse(p, len, info.path, info.modTime, _options, info.ordinal, info.options.fBundleLoader, indirectDylib);
+                       if ( dylibResult != NULL ) {
+                               return dylibResult;
+                       }
+                       dylibResult = textstub::dylib::parse(p, len, info.path, info.modTime, _options, info.ordinal, info.options.fBundleLoader, indirectDylib);
+                       if ( dylibResult != NULL ) {
+                               return dylibResult;
+                       }
+                       break;
+               case Options::kStaticExecutable:
+               case Options::kDyld:
+               case Options::kPreload:
+               case Options::kObjectFile:
+               case Options::kKextBundle:
+                       dylibsNotAllowed = true;
+                       break;
        }
 
        // see if it is a static library
@@ -308,8 +370,17 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
        archOpts.objcABI2                               = _options.objCABIVersion2POverride();
        archOpts.verboseLoad                    = _options.whyLoad();
        archOpts.logAllFiles                    = _options.logAllFiles();
+       // Set ObjSource Kind, libclang_rt is compiler static library
+       if ( isCompilerSupportLib(info.path) )
+               archOpts.objOpts.srcKind = ld::relocatable::File::kSourceCompilerArchive;
+       else
+               archOpts.objOpts.srcKind = ld::relocatable::File::kSourceArchive;
+       archOpts.objOpts.treateBitcodeAsData = _options.bitcodeKind() == Options::kBitcodeAsData;
+       archOpts.objOpts.usingBitcode = _options.bundleBitcode();
+
        ld::archive::File* archiveResult = ::archive::parse(p, len, info.path, info.modTime, info.ordinal, archOpts);
        if ( archiveResult != NULL ) {
+       
                OSAtomicAdd64(len, &_totalArchiveSize);
                OSAtomicIncrement32(&_totalArchivesLoaded);
                return archiveResult;
@@ -343,6 +414,13 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
                }
        }
 
+       if ( dylibsNotAllowed ) {
+               cpu_type_t dummy1;
+               cpu_type_t dummy2;
+               if ( mach_o::dylib::isDylibFile(p, &dummy1, &dummy2) )
+                       throw "ignoring unexpected dylib file";
+       }
+
        // error handling
        if ( ((fat_header*)p)->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
                throwf("missing required architecture %s in file %s (%u slices)", _options.architectureName(), info.path, sliceCount);
@@ -355,7 +433,7 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
        }
 }
 
-void InputFiles::logDylib(ld::File* file, bool indirect)
+void InputFiles::logDylib(ld::File* file, bool indirect, bool speculative)
 {
        if ( _options.traceDylibs() ) {
                const char* fullPath = file->path();
@@ -367,18 +445,45 @@ void InputFiles::logDylib(ld::File* file, bool indirect)
                        // don't log upward dylibs when XBS is computing dependencies
                        logTraceInfo("[Logging for XBS] Used upward dynamic library: %s\n", fullPath);
                }
+               else if ( (dylib != NULL ) && dylib->speculativelyLoaded() ) {
+                       logTraceInfo("[Logging for XBS] Speculatively loaded dynamic library: %s\n", fullPath);
+               }
                else {
-                       if ( indirect )
-                               logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath);
-                       else
+                       if ( indirect ) {
+                               if ( speculative )
+                                       logTraceInfo("[Logging for XBS] Speculatively loaded indirect dynamic library: %s\n", fullPath);
+                               else
+                                       logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath);
+                       }
+                       else {
                                logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath);
+                       }
+               }
+       }
+       
+       if ( _options.dumpDependencyInfo() ) {
+               const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(file);
+               if ( file == _bundleLoader ) {
+                       _options.addDependency(Options::depBundleLoader, file->path());
+               }
+               else if ( (dylib != NULL ) && dylib->willBeUpwardDylib() ) {
+                       if ( indirect ) 
+                               _options.addDependency(Options::depUpwardIndirectDylib, file->path());
+                       else 
+                               _options.addDependency(Options::depUpwardDirectDylib, file->path());
+               }
+               else {
+                       if ( indirect ) 
+                               _options.addDependency(Options::depIndirectDylib, file->path());
+                       else 
+                               _options.addDependency(Options::depDirectDylib, file->path());
                }
        }
 }
 
 void InputFiles::logArchive(ld::File* file) const
 {
-       if ( _options.traceArchives() && (_archiveFilesLogged.count(file) == 0) ) {
+       if ( (_options.traceArchives() || _options.traceEmitJSON()) && (_archiveFilesLogged.count(file) == 0) ) {
                // <rdar://problem/4947347> LD_TRACE_ARCHIVES should only print out when a .o is actually used from an archive
                _archiveFilesLogged.insert(file);
                const char* fullPath = file->path();
@@ -386,44 +491,25 @@ void InputFiles::logArchive(ld::File* file) const
                if ( realpath(fullPath, realName) != NULL )
                        fullPath = realName;
                logTraceInfo("[Logging for XBS] Used static archive: %s\n", fullPath);
+               
+               std::string archivePath(fullPath);
+               _archiveFilePaths.push_back(archivePath);
        }
 }
 
 
 void InputFiles::logTraceInfo(const char* format, ...) const
 {
-       // one time open() of custom LD_TRACE_FILE
-       static int trace_file = -1;
-       if ( trace_file == -1 ) {
-               const char *trace_file_path = _options.traceOutputFile();
-               if ( trace_file_path != NULL ) {
-                       trace_file = open(trace_file_path, O_WRONLY | O_APPEND | O_CREAT, 0666);
-                       if ( trace_file == -1 )
-                               throwf("Could not open or create trace file: %s", trace_file_path);
-               }
-               else {
-                       trace_file = fileno(stderr);
-               }
-       }
-
        char trace_buffer[MAXPATHLEN * 2];
     va_list ap;
        va_start(ap, format);
        int length = vsnprintf(trace_buffer, sizeof(trace_buffer), format, ap);
        va_end(ap);
-       char* buffer_ptr = trace_buffer;
-
-       while (length > 0) {
-               ssize_t amount_written = write(trace_file, buffer_ptr, length);
-               if(amount_written == -1)
-                       /* Failure to write shouldn't fail the build. */
-                       return;
-               buffer_ptr += amount_written;
-               length -= amount_written;
-       }
+       _options.writeToTraceFile(trace_buffer, length);
 }
 
-ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* fromPath)
+
+ld::dylib::File* InputFiles::findDylib(const char* installPath, const ld::dylib::File* fromDylib, bool speculative)
 {
        //fprintf(stderr, "findDylib(%s, %s)\n", installPath, fromPath);
        InstallNameToDylib::iterator pos = _installPathToDylibs.find(installPath);
@@ -438,12 +524,13 @@ ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* from
                                        Options::FileInfo info = _options.findFile(dit->useInstead);
                                        _indirectDylibOrdinal = _indirectDylibOrdinal.nextIndirectDylibOrdinal();
                                        info.ordinal = _indirectDylibOrdinal;
+                                       info.options.fIndirectDylib = true;
                                        ld::File* reader = this->makeFile(info, true);
                                        ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
                                        if ( dylibReader != NULL ) {
                                                addDylib(dylibReader, info);
                                                //_installPathToDylibs[strdup(installPath)] = dylibReader;
-                                               this->logDylib(dylibReader, true);
+                                               this->logDylib(dylibReader, true, speculative);
                                                return dylibReader;
                                        }
                                        else 
@@ -454,22 +541,12 @@ ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* from
                                }
                        }
                }
-               char newPath[MAXPATHLEN];
-               // handle @loader_path
-               if ( strncmp(installPath, "@loader_path/", 13) == 0 ) {
-                       strcpy(newPath, fromPath);
-                       char* addPoint = strrchr(newPath,'/');
-                       if ( addPoint != NULL )
-                               strcpy(&addPoint[1], &installPath[13]);
-                       else
-                               strcpy(newPath, &installPath[13]);
-                       installPath = newPath;
-               }
-               // note: @executable_path case is handled inside findFileUsingPaths()
-               // search for dylib using -F and -L paths
-               Options::FileInfo info = _options.findFileUsingPaths(installPath);
+
+               // search for dylib using -F and -L paths and expanding @ paths
+               Options::FileInfo info = _options.findIndirectDylib(installPath, fromDylib);
                _indirectDylibOrdinal = _indirectDylibOrdinal.nextIndirectDylibOrdinal();
                info.ordinal = _indirectDylibOrdinal;
+               info.options.fIndirectDylib = true;
                try {
                        ld::File* reader = this->makeFile(info, true);
                        ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
@@ -477,31 +554,162 @@ ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* from
                                //assert(_installPathToDylibs.find(installPath) !=  _installPathToDylibs.end());
                                //_installPathToDylibs[strdup(installPath)] = dylibReader;
                                addDylib(dylibReader, info);
-                               this->logDylib(dylibReader, true);
+                               this->logDylib(dylibReader, true, speculative);
                                return dylibReader;
                        }
                        else 
                                throwf("indirect dylib at %s is not a dylib", info.path);
                }
                catch (const char* msg) {
-                       throwf("in %s, %s", info.path, msg);
+                       throwf("in '%s', %s", info.path, msg);
                }
        }
 }
 
 
-
-void InputFiles::createIndirectDylibs()
-{
-       _allDirectDylibsLoaded = true;
-       _indirectDylibOrdinal = ld::File::Ordinal::indirectDylibBase();
-       
-       // mark all dylibs initially specified as required and check if they can be used
+// mark all dylibs initially specified as required, and check if they can be used
+void InputFiles::markExplicitlyLinkedDylibs()
+{      
        for (InstallNameToDylib::iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); it++) {
                it->second->setExplicitlyLinked();
                this->checkDylibClientRestrictions(it->second);
        }
-       
+}
+
+bool InputFiles::frameworkAlreadyLoaded(const char* path, const char* frameworkName)
+{
+       for (ld::File* file : _inputFiles) {
+               if ( strcmp(path, file->path()) == 0 )
+                       return true;
+       }
+       for (ld::dylib::File* dylibx : _allDylibs) {
+               const char* fname = dylibx->frameworkName();
+               if ( fname == NULL )
+                       continue;
+               if ( strcmp(frameworkName, fname) == 0 )
+                       return true;
+       }
+       return false;
+}
+
+bool InputFiles::libraryAlreadyLoaded(const char* path)
+{
+       for (ld::File* file : _inputFiles) {
+               if ( strcmp(path, file->path()) == 0 )
+                       return true;
+       }
+       for (ld::dylib::File* dylib : _allDylibs) {
+               if ( strcmp(path, dylib->path()) == 0 )
+                       return true;
+       }
+       for (const LibraryInfo& libInfo : _searchLibraries) {
+               if ( strcmp(path, libInfo.archive()->path()) == 0 )
+                       return true;
+       }
+
+       char realDylibPath[PATH_MAX];
+       if ( (realpath(path, realDylibPath) != NULL) && (strcmp(path, realDylibPath) != 0) ) {
+               return libraryAlreadyLoaded(realDylibPath);
+       }
+
+       return false;
+}
+
+
+void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHandler& handler)
+{      
+       if ( _options.outputKind() == Options::kObjectFile )
+               return;
+  
+       while (! state.unprocessedLinkerOptionLibraries.empty() || ! state.unprocessedLinkerOptionFrameworks.empty()) {
+
+               // process frameworks specified in .o linker options
+               CStringSet newFrameworks = std::move(state.unprocessedLinkerOptionFrameworks);
+               state.unprocessedLinkerOptionFrameworks.clear();
+               for (const char* frameworkName : newFrameworks) {
+                       if ( state.linkerOptionFrameworks.count(frameworkName) )
+                               continue;
+                       try {
+                               Options::FileInfo info = _options.findFramework(frameworkName);
+                               if ( ! this->frameworkAlreadyLoaded(info.path, frameworkName) ) {
+                                       _linkerOptionOrdinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal();
+                                       info.ordinal = _linkerOptionOrdinal;
+                                       ld::File* reader = this->makeFile(info, true);
+                                       ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
+                                       ld::archive::File* archiveReader = dynamic_cast<ld::archive::File*>(reader);
+                                       if ( dylibReader != NULL ) {
+                                               if ( ! dylibReader->installPathVersionSpecific() ) {
+                                                       dylibReader->forEachAtom(handler);
+                                                       dylibReader->setImplicitlyLinked();
+                                                       dylibReader->setSpeculativelyLoaded();
+                                                       this->addDylib(dylibReader, info);
+                                               }
+                                       }
+                                       else if ( archiveReader != NULL ) {
+                                               _searchLibraries.push_back(LibraryInfo(archiveReader));
+                                               _options.addDependency(Options::depArchive, archiveReader->path());
+                                               //<rdar://problem/17787306> -force_load_swift_libs
+                                               if (info.options.fForceLoad) {
+                                                       archiveReader->forEachAtom(handler);
+                                               }
+                                       }
+                                       else {
+                                               throwf("framework linker option at %s is not a dylib and not an archive", info.path);
+                                       }
+                               }
+                       }
+                       catch (const char* msg) {
+                               warning("Auto-Linking %s", msg);
+                       }
+                       state.linkerOptionFrameworks.insert(frameworkName);
+               }
+
+               // process libraries specified in .o linker options
+               // fixme optimize with std::move?
+               CStringSet newLibraries = std::move(state.unprocessedLinkerOptionLibraries);
+               state.unprocessedLinkerOptionLibraries.clear();
+               for (const char* libName : newLibraries) {
+                       if ( state.linkerOptionLibraries.count(libName) )
+                               continue;
+                       try {
+                               Options::FileInfo info = _options.findLibrary(libName);
+                               if ( ! this->libraryAlreadyLoaded(info.path) ) {
+                                       _linkerOptionOrdinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal();
+                                       info.ordinal = _linkerOptionOrdinal;
+                                       //<rdar://problem/17787306> -force_load_swift_libs
+                                       info.options.fForceLoad = _options.forceLoadSwiftLibs() && (strncmp(libName, "swift", 5) == 0);
+                                       ld::File* reader = this->makeFile(info, true);
+                                       ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
+                                       ld::archive::File* archiveReader = dynamic_cast<ld::archive::File*>(reader);
+                                       if ( dylibReader != NULL ) {
+                                               dylibReader->forEachAtom(handler);
+                                               dylibReader->setImplicitlyLinked();
+                                               dylibReader->setSpeculativelyLoaded();
+                                               this->addDylib(dylibReader, info);
+                                       }
+                                       else if ( archiveReader != NULL ) {
+                                               _searchLibraries.push_back(LibraryInfo(archiveReader));
+                                               _options.addDependency(Options::depArchive, archiveReader->path());
+                                               //<rdar://problem/17787306> -force_load_swift_libs
+                                               if (info.options.fForceLoad) {
+                                                       archiveReader->forEachAtom(handler);
+                                               }
+                                       }
+                                       else {
+                                               throwf("linker option dylib at %s is not a dylib", info.path);
+                                       }
+                               }
+                       }
+                       catch (const char* msg) {
+                               warning("Auto-Linking %s", msg);
+                       }
+                       state.linkerOptionLibraries.insert(libName);
+               }
+       }
+}
+
+void InputFiles::createIndirectDylibs()
+{      
        // keep processing dylibs until no more dylibs are added
        unsigned long lastMapSize = 0;
        std::set<ld::dylib::File*>  dylibsProcessed;
@@ -542,9 +750,10 @@ void InputFiles::createIndirectDylibs()
 
 void InputFiles::createOpaqueFileSections()
 {
-       // extra command line section always at end
+       // extra command line sections always at end
        for (Options::ExtraSection::const_iterator it=_options.extraSectionsBegin(); it != _options.extraSectionsEnd(); ++it) {
                _inputFiles.push_back(opaque_section::parse(it->segmentName, it->sectionName, it->path, it->data, it->dataLen));
+               _options.addDependency(Options::depSection, it->path);
        }
 
 }
@@ -637,20 +846,27 @@ void InputFiles::inferArchitecture(Options& opts, const char** archName)
        _inferredArch = true;
        // scan all input files, looking for a thin .o file.
        // the first one found is presumably the architecture to link
-       uint8_t buffer[sizeof(mach_header_64)];
+       uint8_t buffer[4096];
        const std::vector<Options::FileInfo>& files = opts.getInputFiles();
        for (std::vector<Options::FileInfo>::const_iterator it = files.begin(); it != files.end(); ++it) {
                int fd = ::open(it->path, O_RDONLY, 0);
                if ( fd != -1 ) {
-                       ssize_t amount = read(fd, buffer, sizeof(buffer));
-                       ::close(fd);
-                       if ( amount >= (ssize_t)sizeof(buffer) ) {
-                               cpu_type_t type;
-                               cpu_subtype_t subtype;
-                               if ( mach_o::relocatable::isObjectFile(buffer, &type, &subtype) ) {
-                                       opts.setArchitecture(type, subtype);
-                                       *archName = opts.architectureName();
-                                       return;
+                       struct stat stat_buf;
+                       if ( fstat(fd, &stat_buf) != -1) {
+                               ssize_t readAmount = stat_buf.st_size;
+                               if ( 4096 < readAmount )
+                                       readAmount = 4096;
+                               ssize_t amount = read(fd, buffer, readAmount);
+                               ::close(fd);
+                               if ( amount >= readAmount ) {
+                                       cpu_type_t type;
+                                       cpu_subtype_t subtype;
+                                       Options::Platform platform;
+                                       if ( mach_o::relocatable::isObjectFile(buffer, &type, &subtype, &platform) ) {
+                                               opts.setArchitecture(type, subtype, platform);
+                                               *archName = opts.architectureName();
+                                               return;
+                                       }
                                }
                        }
                }
@@ -659,11 +875,11 @@ void InputFiles::inferArchitecture(Options& opts, const char** archName)
        // no thin .o files found, so default to same architecture this tool was built as
        warning("-arch not specified");
 #if __i386__
-       opts.setArchitecture(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL);
+       opts.setArchitecture(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL, Options::kPlatformOSX);
 #elif __x86_64__
-       opts.setArchitecture(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL);
+       opts.setArchitecture(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL, Options::kPlatformOSX);
 #elif __arm__
-       opts.setArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6);
+       opts.setArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6, Options::kPlatformOSX);
 #else
        #error unknown default architecture
 #endif
@@ -675,8 +891,10 @@ InputFiles::InputFiles(Options& opts, const char** archName)
  : _totalObjectSize(0), _totalArchiveSize(0), 
    _totalObjectLoaded(0), _totalArchivesLoaded(0), _totalDylibsLoaded(0),
        _options(opts), _bundleLoader(NULL), 
-       _allDirectDylibsLoaded(false), _inferredArch(false), _fileMonitor(-1),
-       _exception(NULL)
+       _inferredArch(false),
+       _exception(NULL), 
+       _indirectDylibOrdinal(ld::File::Ordinal::indirectDylibBase()),
+       _linkerOptionOrdinal(ld::File::Ordinal::linkeOptionBase())
 {
 //     fStartCreateReadersTime = mach_absolute_time();
        if ( opts.architecture() == 0 ) {
@@ -687,6 +905,7 @@ InputFiles::InputFiles(Options& opts, const char** archName)
        pthread_mutex_init(&_parseLock, NULL);
        pthread_cond_init(&_parseWorkReady, NULL);
        pthread_cond_init(&_newFileAvailable, NULL);
+       _neededFileSlot = -1;
 #endif
        const std::vector<Options::FileInfo>& files = _options.getInputFiles();
        if ( files.size() == 0 )
@@ -784,7 +1003,8 @@ void InputFiles::parseWorkerThread() {
                        if (_s_logPThreads) printf("parsing index %u\n", slot);
                        try {
                                file = makeFile(entry, false);
-                       } catch (const char *msg) {
+                       }
+                       catch (const char *msg) {
                                if ( (strstr(msg, "architecture") != NULL) && !_options.errorOnOtherArchFiles() ) {
                                        if ( _options.ignoreOtherArchInputFiles() ) {
                                                // ignore, because this is about an architecture not in use
@@ -792,8 +1012,12 @@ void InputFiles::parseWorkerThread() {
                                        else {
                                                warning("ignoring file %s, %s", entry.path, msg);
                                        }
-                               } else {
-                                       exception = msg;
+                               } 
+                               else if ( strstr(msg, "ignoring unexpected") != NULL ) {
+                                       warning("%s, %s", entry.path, msg);
+                               }
+                               else {
+                                       asprintf((char**)&exception, "%s file '%s'", msg, entry.path);
                                }
                                file = new IgnoredFile(entry.path, entry.modTime, entry.ordinal, ld::File::Other);
                        }
@@ -805,7 +1029,8 @@ void InputFiles::parseWorkerThread() {
                                // We are about to die, so set to zero to stop other threads from doing unneeded work.
                                _remainingInputFiles = 0;
                                _exception = exception;
-                       } else {
+                       } 
+                       else {
                                _inputFiles[slot] = file;
                                if (_neededFileSlot == slot)
                                        pthread_cond_signal(&_newFileAvailable);
@@ -870,20 +1095,23 @@ ld::File* InputFiles::addDylib(ld::dylib::File* reader, const Options::FileInfo&
                        }
                        // remove warning for <rdar://problem/10860629> Same install name for CoreServices and CFNetwork?
                        //if ( !dylibOnCommandLineTwice && !isSymlink )
-                       //      warning("dylibs with same install name: %s and %s", pos->second->path(), reader->path());
+                       //      warning("dylibs with same install name: %p %s and %p %s", pos->second, pos->second->path(), reader, reader->path());
                }
        }
        else if ( info.options.fBundleLoader )
                _bundleLoader = reader;
 
        // log direct readers
-       if ( !_allDirectDylibsLoaded ) 
-               this->logDylib(reader, false);
+       if ( ! info.options.fIndirectDylib ) 
+               this->logDylib(reader, false, false);
 
        // update stats
        _totalDylibsLoaded++;
 
-    _searchLibraries.push_back(LibraryInfo(reader));
+       // just add direct libraries to search-first list
+       if ( ! info.options.fIndirectDylib ) 
+               _searchLibraries.push_back(LibraryInfo(reader));
+       
        return reader;
 }
 
@@ -919,7 +1147,7 @@ void InputFiles::waitForInputFiles()
                        if (it == fileMap.end())
                                throwf("pipelined linking error - not in file list: %s\n", path_buf);
                        Options::FileInfo* inputInfo = (Options::FileInfo*)it->second;
-                       if (!inputInfo->checkFileExists())
+                       if (!inputInfo->checkFileExists(_options))
                                throwf("pipelined linking error - file does not exist: %s\n", inputInfo->path);
                        pthread_mutex_lock(&_parseLock);
                        if (_idleWorkers)
@@ -947,7 +1175,7 @@ void InputFiles::waitForInputFiles(InputFiles *inputFiles) {
 #endif
 
 
-void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler)
+void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler, ld::Internal& state)
 {
        // add all direct object, archives, and dylibs
        const std::vector<Options::FileInfo>& files = _options.getInputFiles();
@@ -987,6 +1215,7 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler)
                        {
                                ld::relocatable::File* reloc = (ld::relocatable::File*)file;
                                _options.snapshot().recordObjectFile(reloc->path());
+                               _options.addDependency(Options::depObjectFile, reloc->path());
                        }
                                break;
                        case ld::File::Dylib:
@@ -999,9 +1228,14 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler)
                        {
                                ld::archive::File* archive = (ld::archive::File*)file;
                                // <rdar://problem/9740166> force loaded archives should be in LD_TRACE
-                               if ( (info.options.fForceLoad || _options.fullyLoadArchives()) && _options.traceArchives() ) 
+                               if ( (info.options.fForceLoad || _options.fullyLoadArchives()) && (_options.traceArchives() || _options.traceEmitJSON()) )
                                        logArchive(archive);
+
+                               if ( isCompilerSupportLib(info.path) && (info.options.fForceLoad || _options.fullyLoadArchives()) )
+                                       state.forceLoadCompilerRT = true;
+
                                _searchLibraries.push_back(LibraryInfo(archive));
+                               _options.addDependency(Options::depArchive, archive->path());
                        }
                                break;
                        case ld::File::Other:
@@ -1012,9 +1246,18 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler)
                        }
                                break;
                }
-               file->forEachAtom(handler);
+               try {
+                       file->forEachAtom(handler);
+               }
+               catch (const char* msg) {
+                       asprintf((char**)&_exception, "%s file '%s'", msg, file->path());
+               }
        }
+       if (_exception)
+               throw _exception;
 
+       markExplicitlyLinkedDylibs();
+       addLinkerOptionLibraries(state, handler);
        createIndirectDylibs();
        createOpaqueFileSections();
        
@@ -1053,7 +1296,9 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler)
         case Options::kPreload:
             // add implicit __mh_preload_header label
             handler.doAtom(DSOHandleAtom::_s_atomPreload);
-            handler.doAtom(DSOHandleAtom::_s_atomAll);
+            // add implicit __dso_handle label, but put it in __text section because 
+            // with -preload the mach_header is no in the address space.
+            handler.doAtom(DSOHandleAtom::_s_atomPreloadDSO);
             break;
         case Options::kObjectFile:
             handler.doAtom(DSOHandleAtom::_s_atomObjectFile);
@@ -1069,11 +1314,8 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler)
 bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searchArchives, bool dataSymbolOnly, ld::File::AtomHandler& handler) const
 {
        // Check each input library.
-    std::vector<LibraryInfo>::const_iterator libIterator = _searchLibraries.begin();
-    
-    
-    while (libIterator != _searchLibraries.end()) {
-        LibraryInfo lib = *libIterator;
+    for (std::vector<LibraryInfo>::const_iterator it=_searchLibraries.begin(); it != _searchLibraries.end(); ++it) {
+        LibraryInfo lib = *it;
         if (lib.isDylib()) {
             if (searchDylibs) {
                 ld::dylib::File *dylibFile = lib.dylib();
@@ -1093,16 +1335,17 @@ bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searc
                 ld::archive::File *archiveFile = lib.archive();
                 if ( dataSymbolOnly ) {
                     if ( archiveFile->justInTimeDataOnlyforEachAtom(name, handler) ) {
-                        if ( _options.traceArchives() 
+                        if ( _options.traceArchives() || _options.traceEmitJSON())
                             logArchive(archiveFile);
                         _options.snapshot().recordArchive(archiveFile->path());
+                                               // DALLAS _state.archives.push_back(archiveFile);
                         // found data definition in static library, done
-                        return true;
+                       return true;
                     }
                 }
                 else {
                     if ( archiveFile->justInTimeforEachAtom(name, handler) ) {
-                        if ( _options.traceArchives() 
+                        if ( _options.traceArchives() || _options.traceEmitJSON())
                             logArchive(archiveFile);
                         _options.snapshot().recordArchive(archiveFile->path());
                         // found definition in static library, done
@@ -1111,7 +1354,6 @@ bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searc
                 }
             }
         }
-        libIterator++;
     }
 
        // search indirect dylibs
@@ -1148,7 +1390,7 @@ bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searc
 
 bool InputFiles::searchWeakDefInDylib(const char* name) const
 {
-       // search all relevant dylibs to see if any of a weak-def with this name
+       // search all relevant dylibs to see if any have a weak-def with this name
        for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) {
                ld::dylib::File* dylibFile = it->second;
                if ( dylibFile->implicitlyLinked() || dylibFile->explicitlyLinked() ) {
@@ -1165,6 +1407,14 @@ static bool vectorContains(const std::vector<ld::dylib::File*>& vec, ld::dylib::
        return std::find(vec.begin(), vec.end(), key) != vec.end();
 }
 
+struct DylibByInstallNameSorter
+{      
+        bool operator()(const ld::dylib::File* left, const ld::dylib::File* right)
+        {
+          return (strcmp(left->installPath(), right->installPath()) < 0);
+        }
+};
+
 void InputFiles::dylibs(ld::Internal& state)
 {
        bool dylibsOK = false;
@@ -1199,20 +1449,36 @@ void InputFiles::dylibs(ld::Internal& state)
        }
        // add implicitly linked dylibs
        if ( _options.nameSpace() == Options::kTwoLevelNameSpace ) {
+               std::vector<ld::dylib::File*> implicitDylibs;
                for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) {
                        ld::dylib::File* dylibFile = it->second;
                        if ( dylibFile->implicitlyLinked() && dylibsOK ) {
-                               if ( ! vectorContains(state.dylibs, dylibFile) ) {
-                                       state.dylibs.push_back(dylibFile);
+                               if ( ! vectorContains(implicitDylibs, dylibFile) ) {
+                                       implicitDylibs.push_back(dylibFile);
+                               }
+                       }
+               }
+               // <rdar://problem/15002251> make implicit dylib order be deterministic by sorting by install_name
+               std::sort(implicitDylibs.begin(), implicitDylibs.end(), DylibByInstallNameSorter());
+
+               if ( _options.traceDylibs() ) {
+                       for (ld::dylib::File* dylib :  implicitDylibs) {
+                               if ( dylib->speculativelyLoaded() && !dylib->explicitlyLinked() && dylib->providedExportAtom() ) {
+                                       const char* fullPath = dylib->path();
+                                       char realName[MAXPATHLEN];
+                                       if ( realpath(fullPath, realName) != NULL )
+                                               fullPath = realName;
+                                       logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath);
                                }
                        }
                }
+               state.dylibs.insert(state.dylibs.end(), implicitDylibs.begin(), implicitDylibs.end());
        }
 
        //fprintf(stderr, "all dylibs:\n");
        //for(std::vector<ld::dylib::File*>::iterator it=state.dylibs.begin(); it != state.dylibs.end(); ++it) {
        //      const ld::dylib::File* dylib = *it;
-       //      fprintf(stderr, "    %p %s\n", dylib, dylib->path());
+       //      fprintf(stderr, "    %p impl=%d %s\n", dylib, dylib->implicitlyLinked(), dylib->path());
        //}
        
        // and -bundle_loader
@@ -1223,8 +1489,15 @@ void InputFiles::dylibs(ld::Internal& state)
                throw "dynamic main executables must link with libSystem.dylib";
 }
 
+void InputFiles::archives(ld::Internal& state)
+{
+       for (const std::string path :  _archiveFilePaths) {
+               
+               state.archivePaths.push_back(path);
+       }
+}
+
 
 } // namespace tool 
 } // namespace ld 
 
-