]> git.saurik.com Git - apple/ld64.git/blobdiff - src/ld/InputFiles.cpp
ld64-305.tar.gz
[apple/ld64.git] / src / ld / InputFiles.cpp
index ab31d4acab07ffe72a8e69cfde6a37cbf064fffc..1c69de62135e58464aca1c0174b4bfe09425485c 100644 (file)
@@ -177,6 +177,11 @@ 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)
 {
@@ -210,14 +215,16 @@ const char* InputFiles::fileArch(const uint8_t* p, unsigned len)
 ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib)
 {
        // 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 )
-               throwf("file too small (length=%llu)", info.fileLen);
-
-       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);
 
@@ -255,23 +262,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 ) {
+                       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);
-                               uint64_t newFileLen = info.fileLen;
+                               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, info.fileLen);
+                                               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) )
@@ -355,8 +362,7 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
        archOpts.verboseLoad                    = _options.whyLoad();
        archOpts.logAllFiles                    = _options.logAllFiles();
        // Set ObjSource Kind, libclang_rt is compiler static library
-       const char* libName = strrchr(info.path, '/');
-       if ( (libName != NULL) && (strncmp(libName, "/libclang_rt", 12) == 0) )
+       if ( isCompilerSupportLib(info.path) )
                archOpts.objOpts.srcKind = ld::relocatable::File::kSourceCompilerArchive;
        else
                archOpts.objOpts.srcKind = ld::relocatable::File::kSourceArchive;
@@ -365,6 +371,7 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
 
        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;
@@ -417,7 +424,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();
@@ -429,11 +436,19 @@ 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);
+                       }
                }
        }
        
@@ -459,7 +474,7 @@ void InputFiles::logDylib(ld::File* file, bool indirect)
 
 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();
@@ -467,45 +482,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 (errno=%d): %s", errno, 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);
@@ -526,7 +521,7 @@ ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* from
                                        if ( dylibReader != NULL ) {
                                                addDylib(dylibReader, info);
                                                //_installPathToDylibs[strdup(installPath)] = dylibReader;
-                                               this->logDylib(dylibReader, true);
+                                               this->logDylib(dylibReader, true, speculative);
                                                return dylibReader;
                                        }
                                        else 
@@ -537,20 +532,9 @@ 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;
@@ -561,7 +545,7 @@ 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 
@@ -614,80 +598,96 @@ bool InputFiles::libraryAlreadyLoaded(const char* path)
                        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;
-
-       // process frameworks specified in .o linker options
-       for (CStringSet::const_iterator it = state.linkerOptionFrameworks.begin(); it != state.linkerOptionFrameworks.end(); ++it) {
-               const char* frameworkName = *it;
-               if ( state.linkerOptionFrameworksProcessed.count(frameworkName) )
-                       continue;
-               Options::FileInfo info = _options.findFramework(frameworkName);
-               if ( ! this->frameworkAlreadyLoaded(info.path, frameworkName) ) {
-                       info.ordinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal();
-                       try {
-                               ld::File* reader = this->makeFile(info, true);
-                               ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
-                               if ( dylibReader != NULL ) {
-                                       if ( ! dylibReader->installPathVersionSpecific() ) {
+       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;
+                       Options::FileInfo info = _options.findFramework(frameworkName);
+                       if ( ! this->frameworkAlreadyLoaded(info.path, frameworkName) ) {
+                               _linkerOptionOrdinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal();
+                               info.ordinal = _linkerOptionOrdinal;
+                               try {
+                                       ld::File* reader = this->makeFile(info, true);
+                                       ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
+                                       if ( dylibReader != NULL ) {
+                                               if ( ! dylibReader->installPathVersionSpecific() ) {
+                                                       dylibReader->forEachAtom(handler);
+                                                       dylibReader->setImplicitlyLinked();
+                                                       dylibReader->setSpeculativelyLoaded();
+                                                       this->addDylib(dylibReader, info);
+                                               }
+                                       }
+                                       else {
+                                               throwf("framework linker option at %s is not a dylib", info.path);
+                                       }
+                               }
+                               catch (const char* msg) {
+                                       warning("Auto-Linking supplied '%s', %s", info.path, 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;
+                       Options::FileInfo info = _options.findLibrary(libName);
+                       if ( ! this->libraryAlreadyLoaded(info.path) ) {
+                               _linkerOptionOrdinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal();
+                               info.ordinal = _linkerOptionOrdinal;
+                               try {
+                                       //<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 {
-                                       throwf("framework linker option at %s is not a dylib", info.path);
-                               }
-                       }
-                       catch (const char* msg) {
-                               warning("Auto-Linking supplied '%s', %s", info.path, msg);
-                       }
-               }
-               state.linkerOptionFrameworksProcessed.insert(frameworkName);
-       }
-       // process libraries specified in .o linker options
-       for (CStringSet::const_iterator it = state.linkerOptionLibraries.begin(); it != state.linkerOptionLibraries.end(); ++it) {
-               const char* libName = *it;
-               if ( state.linkerOptionLibrariesProcessed.count(libName) )
-                       continue;
-               Options::FileInfo info = _options.findLibrary(libName);
-               if ( ! this->libraryAlreadyLoaded(info.path) ) {
-                       info.ordinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal();
-                       try {
-                               //<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();
-                                       this->addDylib(dylibReader, info);
-                               }
-                               else if ( archiveReader != NULL ) {
-                                       _searchLibraries.push_back(LibraryInfo(archiveReader));
-                                       if ( _options.dumpDependencyInfo() )
-                                               _options.dumpDependency(Options::depArchive, archiveReader->path());
-                                       //<rdar://problem/17787306> -force_load_swift_libs
-                                       if (info.options.fForceLoad) {
-                                               archiveReader->forEachAtom(handler);
+                                       else if ( archiveReader != NULL ) {
+                                               _searchLibraries.push_back(LibraryInfo(archiveReader));
+                                               if ( _options.dumpDependencyInfo() )
+                                                       _options.dumpDependency(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 supplied '%s', %s", info.path, msg);
-                       }
+                                       else {
+                                               throwf("linker option dylib at %s is not a dylib", info.path);
+                                       }
+                               }
+                               catch (const char* msg) {
+                                       warning("Auto-Linking supplied '%s', %s", info.path, msg);
+                               }
+                       }
+                       state.linkerOptionLibraries.insert(libName);
                }
-               state.linkerOptionLibrariesProcessed.insert(libName);
        }
 }
 
@@ -889,6 +889,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 )
@@ -986,7 +987,7 @@ void InputFiles::parseWorkerThread() {
                        if (_s_logPThreads) printf("parsing index %u\n", slot);
                        try {
                                file = makeFile(entry, false);
-                       } 
+                       }
                        catch (const char *msg) {
                                if ( (strstr(msg, "architecture") != NULL) && !_options.errorOnOtherArchFiles() ) {
                                        if ( _options.ignoreOtherArchInputFiles() ) {
@@ -1086,7 +1087,7 @@ ld::File* InputFiles::addDylib(ld::dylib::File* reader, const Options::FileInfo&
 
        // log direct readers
        if ( ! info.options.fIndirectDylib ) 
-               this->logDylib(reader, false);
+               this->logDylib(reader, false, false);
 
        // update stats
        _totalDylibsLoaded++;
@@ -1212,8 +1213,12 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler, ld::Internal
                        {
                                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));
                                if ( _options.dumpDependencyInfo() )
                                        _options.dumpDependency(Options::depArchive, archive->path());
@@ -1227,8 +1232,15 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler, ld::Internal
                        }
                                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);
@@ -1309,16 +1321,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;
                     }
                 }
                 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
@@ -1433,6 +1446,18 @@ void InputFiles::dylibs(ld::Internal& state)
                }
                // <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());
        }
 
@@ -1450,6 +1475,14 @@ 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