X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/ec29ba20dfd4abc0cb74366b39dda06af136e073..f410558f5d60087e4c310119a1751b437121c3b9:/src/ld/InputFiles.cpp diff --git a/src/ld/InputFiles.cpp b/src/ld/InputFiles.cpp index ab31d4a..2a79ae2 100644 --- a/src/ld/InputFiles.cpp +++ b/src/ld/InputFiles.cpp @@ -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) { @@ -209,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 ) - 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 +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 ) { + if ( fileOffset+len > stat_buf.st_size ) { // 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 +371,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 +380,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 +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(); @@ -429,37 +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(file); if ( file == _bundleLoader ) { - _options.dumpDependency(Options::depBundleLoader, file->path()); + _options.addDependency(Options::depBundleLoader, file->path()); } else if ( (dylib != NULL ) && dylib->willBeUpwardDylib() ) { if ( indirect ) - _options.dumpDependency(Options::depUpwardIndirectDylib, file->path()); + _options.addDependency(Options::depUpwardIndirectDylib, file->path()); else - _options.dumpDependency(Options::depUpwardDirectDylib, file->path()); + _options.addDependency(Options::depUpwardDirectDylib, file->path()); } else { if ( indirect ) - _options.dumpDependency(Options::depIndirectDylib, file->path()); + _options.addDependency(Options::depIndirectDylib, file->path()); else - _options.dumpDependency(Options::depDirectDylib, file->path()); + _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) ) { // 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 +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 (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 +530,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 +541,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 +554,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 +607,104 @@ 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(); + 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 { - ld::File* reader = this->makeFile(info, true); - ld::dylib::File* dylibReader = dynamic_cast(reader); - if ( dylibReader != NULL ) { - if ( ! dylibReader->installPathVersionSpecific() ) { - dylibReader->forEachAtom(handler); - dylibReader->setImplicitlyLinked(); - this->addDylib(dylibReader, info); + 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(reader); + ld::archive::File* archiveReader = dynamic_cast(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); - } - } + else if ( archiveReader != NULL ) { + _searchLibraries.push_back(LibraryInfo(archiveReader)); + _options.addDependency(Options::depArchive, archiveReader->path()); + // -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 supplied '%s', %s", info.path, msg); + warning("Auto-Linking %s", 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(); + 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 { - // -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(reader); - ld::archive::File* archiveReader = dynamic_cast(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()); - // -force_load_swift_libs - if (info.options.fForceLoad) { - archiveReader->forEachAtom(handler); + Options::FileInfo info = _options.findLibrary(libName); + if ( ! this->libraryAlreadyLoaded(info.path) ) { + _linkerOptionOrdinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal(); + info.ordinal = _linkerOptionOrdinal; + // -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(reader); + ld::archive::File* archiveReader = dynamic_cast(reader); + if ( dylibReader != NULL ) { + dylibReader->forEachAtom(handler); + dylibReader->setImplicitlyLinked(); + dylibReader->setSpeculativelyLoaded(); + this->addDylib(dylibReader, info); } - } - else { - throwf("linker option dylib at %s is not a dylib", info.path); - } - } + else if ( archiveReader != NULL ) { + _searchLibraries.push_back(LibraryInfo(archiveReader)); + _options.addDependency(Options::depArchive, archiveReader->path()); + // -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); + warning("Auto-Linking %s", msg); } + state.linkerOptionLibraries.insert(libName); } - state.linkerOptionLibrariesProcessed.insert(libName); } } @@ -736,8 +753,7 @@ void InputFiles::createOpaqueFileSections() // 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)); - if ( _options.dumpDependencyInfo() ) - _options.dumpDependency(Options::depSection, it->path); + _options.addDependency(Options::depSection, it->path); } } @@ -889,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& files = _options.getInputFiles(); if ( files.size() == 0 ) @@ -986,7 +1003,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 +1103,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++; @@ -1198,8 +1215,7 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler, ld::Internal { ld::relocatable::File* reloc = (ld::relocatable::File*)file; _options.snapshot().recordObjectFile(reloc->path()); - if ( _options.dumpDependencyInfo() ) - _options.dumpDependency(Options::depObjectFile, reloc->path()); + _options.addDependency(Options::depObjectFile, reloc->path()); } break; case ld::File::Dylib: @@ -1212,11 +1228,14 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler, ld::Internal { ld::archive::File* archive = (ld::archive::File*)file; // 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()); + _options.addDependency(Options::depArchive, archive->path()); } break; case ld::File::Other: @@ -1227,8 +1246,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 +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; } } 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 +1460,18 @@ void InputFiles::dylibs(ld::Internal& state) } // 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 +1489,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