X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/b1c6f52afb9f246c71bc8c8c57a268f11d0895e5..f410558f5d60087e4c310119a1751b437121c3b9:/src/ld/Options.cpp diff --git a/src/ld/Options.cpp b/src/ld/Options.cpp index b739786..6f115d8 100644 --- a/src/ld/Options.cpp +++ b/src/ld/Options.cpp @@ -45,7 +45,6 @@ #include "MachOFileAbstraction.hpp" #include "Snapshot.h" - // from FunctionNameDemangle.h extern "C" size_t fnd_get_demangled_name(const char *mangledName, char *outputBuffer, size_t length); @@ -117,6 +116,10 @@ void throwf(const char* format, ...) bool Options::FileInfo::checkFileExists(const Options& options, const char *p) { + if (isInlined) { + modTime = 0; + return true; + } struct stat statBuffer; if (p == NULL) p = path; @@ -125,8 +128,7 @@ bool Options::FileInfo::checkFileExists(const Options& options, const char *p) modTime = statBuffer.st_mtime; return true; } - if ( options.dumpDependencyInfo() ) - options.dumpDependency(Options::depNotFound, p); + options.addDependency(Options::depNotFound, p); // fprintf(stderr, "not found: %s\n", p); return false; } @@ -160,7 +162,8 @@ Options::Options(int argc, const char* argv[]) fUsingLazyDylibLinking(false), fEncryptable(true), fEncryptableForceOn(false), fEncryptableForceOff(false), fOrderData(true), fMarkDeadStrippableDylib(false), fMakeCompressedDyldInfo(true), fMakeCompressedDyldInfoForceOff(false), fNoEHLabels(false), - fAllowCpuSubtypeMismatches(false), fEnforceDylibSubtypesMatch(false), fUseSimplifiedDylibReExports(false), + fAllowCpuSubtypeMismatches(false), fEnforceDylibSubtypesMatch(false), + fWarnOnSwiftABIVersionMismatches(false), fUseSimplifiedDylibReExports(false), fObjCABIVersion2Override(false), fObjCABIVersion1Override(false), fCanUseUpwardDylib(false), fFullyLoadArchives(false), fLoadAllObjcObjectsFromArchives(false), fFlatNamespace(false), fLinkingMainExecutable(false), fForFinalLinkedImage(false), fForStatic(false), @@ -169,7 +172,7 @@ Options::Options(int argc, const char* argv[]) fWarnCompactUnwind(false), fRemoveDwarfUnwindIfCompactExists(false), fAutoOrderInitializers(true), fOptimizeZeroFill(true), fMergeZeroFill(false), fLogObjectFiles(false), fLogAllFiles(false), fTraceDylibs(false), fTraceIndirectDylibs(false), fTraceArchives(false), fTraceEmitJSON(false), - fOutputSlidable(false), fWarnWeakExports(false), + fOutputSlidable(false), fWarnWeakExports(false), fNoWeakExports(false), fObjcGcCompaction(false), fObjCGc(false), fObjCGcOnly(false), fDemangle(false), fTLVSupport(false), fVersionLoadCommand(false), fVersionLoadCommandForcedOn(false), @@ -192,11 +195,12 @@ Options::Options(int argc, const char* argv[]) fBundleBitcode(false), fHideSymbols(false), fVerifyBitcode(false), fReverseMapUUIDRename(false), fDeDupe(true), fVerboseDeDupe(false), fReverseMapPath(NULL), fLTOCodegenOnly(false), - fIgnoreAutoLink(false), fAllowDeadDups(false), fAllowWeakImports(true), fNoInitializers(false), fBitcodeKind(kBitcodeProcess), + fIgnoreAutoLink(false), fAllowDeadDups(false), fAllowWeakImports(true), fInitializersTreatment(Options::kInvalid), + fZeroModTimeInDebugMap(false), fBitcodeKind(kBitcodeProcess), fPlatform(kPlatformUnknown), fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL), fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset), fWatchOSVersionMin(ld::wOSVersionUnset), fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL), - fDependencyInfoPath(NULL), fDependencyFileDescriptor(-1), fTraceFileDescriptor(-1), fMaxDefaultCommonAlign(0), + fDependencyInfoPath(NULL), fTraceFileDescriptor(-1), fMaxDefaultCommonAlign(0), fUnalignedPointerTreatment(kUnalignedPointerIgnore) { this->checkForClassic(argc, argv); @@ -206,18 +210,13 @@ Options::Options(int argc, const char* argv[]) this->reconfigureDefaults(); this->checkIllegalOptionCombinations(); - if ( this->dumpDependencyInfo() ) { - this->dumpDependency(depOutputFile, fOutputFile); - if ( fMapPath != NULL ) - this->dumpDependency(depOutputFile, fMapPath); - } + this->addDependency(depOutputFile, fOutputFile); + if ( fMapPath != NULL ) + this->addDependency(depOutputFile, fMapPath); } Options::~Options() { - if ( fDependencyFileDescriptor != -1 ) - ::close(fDependencyFileDescriptor); - if ( fTraceFileDescriptor != -1 ) ::close(fTraceFileDescriptor); } @@ -827,6 +826,16 @@ static std::string replace_extension(const std::string &path, const std::string return result; } +void Options::addTAPIInterface(tapi::LinkerInterfaceFile *interface, const char *path) const { +#if ((TAPI_API_VERSION_MAJOR == 1 && TAPI_API_VERSION_MINOR >= 3) || (TAPI_API_VERSION_MAJOR > 1)) + if (tapi::APIVersion::isAtLeast(1, 3)) { + for (auto &name : interface->inlinedFrameworkNames()) { + fTAPIFiles.emplace_back(interface, path, name.c_str()); + } + } +#endif +} + bool Options::findFile(const std::string &path, const std::vector &tbdExtensions, FileInfo& result) const { FileInfo tbdInfo; @@ -935,6 +944,14 @@ Options::FileInfo Options::findFile(const std::string &path, const ld::dylib::Fi } } + // find inlined TBD file before raw path. + // rdar://problem/35864452 + if (hasInlinedTAPIFile(path)) { + FileInfo inlinedFile(path.c_str()); + inlinedFile.isInlined = true; + return inlinedFile; + } + // try raw path if ( findFile(path, {".tbd"}, result) ) return result; @@ -943,6 +960,58 @@ Options::FileInfo Options::findFile(const std::string &path, const ld::dylib::Fi throwf("file not found: %s", path.c_str()); } +bool Options::hasInlinedTAPIFile(const std::string &path) const { + for (const auto &dylib : fTAPIFiles) { + if (dylib.getInstallName() == path) + return true; + } + return false; +} + +std::unique_ptr Options::findTAPIFile(const std::string &path) const +{ + std::unique_ptr interface; + std::string TBDPath; + + // create parsing options. + tapi::ParsingFlags flags = tapi::ParsingFlags::None; + if (enforceDylibSubtypesMatch()) + flags |= tapi::ParsingFlags::ExactCpuSubType; + + if (!allowWeakImports()) + flags |= tapi::ParsingFlags::DisallowWeakImports; + + // Search through all the inlined framework. + for (const auto &dylib : fTAPIFiles) { + if (dylib.getInstallName() == path) { + // If the install name matches, parse the framework. + std::string errorMessage; + auto file = dylib.getInterfaceFile()->getInlinedFramework(path.c_str(), architecture(), subArchitecture(), + flags, tapi::PackedVersion32(minOSversion()), errorMessage); + if (!file) + throw strdup(errorMessage.c_str()); + + if (!interface) { + // If this is the first inlined framework found, record the information. + interface.reset(file); + TBDPath = dylib.getTAPIFilePath(); + } else { + // If we found other inlined framework already, check to see if their versions are the same. + // If not the same, emit an warning and record the newer one. Otherwise, just use the current one. + if (interface->getCurrentVersion() == file->getCurrentVersion()) + continue; + warning("Inlined framework/dylib mismatch: %s (%s and %s)", path.c_str(), + TBDPath.c_str(), dylib.getTAPIFilePath().c_str()); + if (interface->getCurrentVersion() < file->getCurrentVersion()) { + interface.reset(file); + TBDPath = dylib.getTAPIFilePath(); + } + } + } + } + return interface; +} + // search for indirect dylib first using -F and -L paths first Options::FileInfo Options::findIndirectDylib(const std::string& installName, const ld::dylib::File* fromDylib) const { @@ -1067,16 +1136,14 @@ void Options::loadFileList(const char* fileOfPaths, ld::File::Ordinal baseOrdina file = fopen(realFileOfPaths, "r"); if ( file == NULL ) throwf("-filelist file '%s' could not be opened, errno=%d (%s)\n", realFileOfPaths, errno, strerror(errno)); - if ( this->dumpDependencyInfo() ) - this->dumpDependency(Options::depFileList, realFileOfPaths); + this->addDependency(Options::depFileList, realFileOfPaths); } } else { file = fopen(fileOfPaths, "r"); if ( file == NULL ) throwf("-filelist file '%s' could not be opened, errno=%d (%s)\n", fileOfPaths, errno, strerror(errno)); - if ( this->dumpDependencyInfo() ) - this->dumpDependency(Options::depFileList, fileOfPaths); + this->addDependency(Options::depFileList, fileOfPaths); } char path[PATH_MAX]; @@ -1287,8 +1354,7 @@ void Options::loadExportFile(const char* fileOfExports, const char* option, SetW if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size ) throwf("can't read %s file: %s", option, fileOfExports); - if ( this->dumpDependencyInfo() ) - this->dumpDependency(Options::depMisc, fileOfExports); + this->addDependency(Options::depMisc, fileOfExports); ::close(fd); @@ -1361,8 +1427,7 @@ void Options::parseAliasFile(const char* fileOfAliases) throwf("can't read alias file: %s", fileOfAliases); p[stat_buf.st_size] = '\n'; ::close(fd); - if ( this->dumpDependencyInfo() ) - this->dumpDependency(Options::depMisc, fileOfAliases); + this->addDependency(Options::depMisc, fileOfAliases); // parse into symbols and add to fAliases AliasPair pair; @@ -1790,8 +1855,7 @@ void Options::parseOrderFile(const char* path, bool cstring) throwf("can't read order file: %s", path); ::close(fd); p[stat_buf.st_size] = '\n'; - if ( this->dumpDependencyInfo() ) - this->dumpDependency(Options::depMisc, path); + this->addDependency(Options::depMisc, path); // parse into vector of pairs char * const end = &p[stat_buf.st_size+1]; @@ -3492,6 +3556,9 @@ void Options::parse(int argc, const char* argv[]) else if ( strcmp(arg, "-warn_weak_exports") == 0 ) { fWarnWeakExports = true; } + else if ( strcmp(arg, "-no_weak_exports") == 0 ) { + fNoWeakExports = true; + } else if ( strcmp(arg, "-objc_gc_compaction") == 0 ) { fObjcGcCompaction = true; cannotBeUsedWithBitcode(arg); @@ -3865,7 +3932,10 @@ void Options::parse(int argc, const char* argv[]) fAllowWeakImports = false; } else if ( strcmp(argv[i], "-no_inits") == 0 ) { - fNoInitializers = true; + fInitializersTreatment = Options::kError; + } + else if ( strcmp(argv[i], "-no_warn_inits") == 0 ) { + fInitializersTreatment = Options::kSuppress; } // put this last so that it does not interfer with other options starting with 'i' else if ( strncmp(arg, "-i", 2) == 0 ) { @@ -4192,6 +4262,9 @@ void Options::parsePreCommandLineEnvironmentSettings() if (getenv("LD_DYLIB_CPU_SUBTYPES_MUST_MATCH") != NULL) fEnforceDylibSubtypesMatch = true; + + if (getenv("LD_WARN_ON_SWIFT_ABI_VERSION_MISMATCHES") != NULL) + fWarnOnSwiftABIVersionMismatches = true; sWarningsSideFilePath = getenv("LD_WARN_FILE"); @@ -4211,6 +4284,10 @@ void Options::parsePreCommandLineEnvironmentSettings() if (pipeFdString != NULL) { fPipelineFifo = pipeFdString; } + + // [Reproducible Builds] If env ZERO_AR_DATE is set, zero out timestamp in N_OSO stab + if ( getenv("ZERO_AR_DATE") != NULL ) + fZeroModTimeInDebugMap = true; } @@ -4650,6 +4727,9 @@ void Options::reconfigureDefaults() // only use v2 for Swift dylibs on Mac OS X if ( strncmp(this->installPath(), "/System/Library/PrivateFrameworks/Swift/", 40) == 0 ) fSharedRegionEncodingV2 = true; + // use v2 for ABI stable Swift dylibs on macOS + if ( strncmp(this->installPath(), "/System/Library/Frameworks/Swift/", 33) == 0 ) + fSharedRegionEncodingV2 = true; // an other OS frameworks that use swift need v2 for (const char* searchPath : fLibrarySearchPaths ) { if ( strstr(searchPath, "xctoolchain/usr/lib/swift/macos") != NULL ) { @@ -5246,6 +5326,18 @@ void Options::reconfigureDefaults() fUnalignedPointerTreatment = Options::kUnalignedPointerIgnore; } + // warn by default for OS dylibs + if ( fInitializersTreatment == Options::kInvalid ) { + if ( fSharedRegionEligible && (fOutputKind == Options::kDynamicLibrary) ) { + fInitializersTreatment = Options::kWarning; + // TEMP HACK + if ( (fOutputKind == Options::kDynamicLibrary) && (fDylibInstallName != NULL) && (strstr(fDylibInstallName, "EmbeddedAcousticRecognition.framework") != NULL) && !fNoWeakExports ) + fInitializersTreatment = Options::kSuppress; + } + else + fInitializersTreatment = Options::kSuppress; + } + } void Options::checkIllegalOptionCombinations() @@ -5911,7 +6003,7 @@ const char* Options::demangleSymbol(const char* sym) const static size_t size = 1024; static char* buff = (char*)malloc(size); - + #if DEMANGLE_SWIFT // only try to demangle symbols that look like Swift symbols if ( strncmp(sym, "__T", 3) == 0 ) { @@ -5941,26 +6033,50 @@ const char* Options::demangleSymbol(const char* sym) const } -void Options::dumpDependency(uint8_t opcode, const char* path) const +void Options::writeDependencyInfo() const { - if ( !this->dumpDependencyInfo() ) + // do nothing if -dependency_info not used + if ( !dumpDependencyInfo() ) return; + // sort entries for build reproducibility + std::sort(fDependencies.begin(), fDependencies.end(), [](const DependencyEntry& a, const DependencyEntry& b) -> bool { + if ( a.opcode != b.opcode ) + return (a.opcode < b.opcode); + return (a.path < b.path); + }); + // one time open() of -dependency_info file - if ( fDependencyFileDescriptor == -1 ) { - fDependencyFileDescriptor = open(this->dependencyInfoPath(), O_WRONLY | O_TRUNC | O_CREAT, 0666); - if ( fDependencyFileDescriptor == -1 ) - throwf("Could not open or create -dependency_info file: %s", this->dependencyInfoPath()); - - // write header - uint8_t version = depLinkerVersion; - if ( write(fDependencyFileDescriptor, &version, 1) == -1 ) + int fd = open(this->dependencyInfoPath(), O_WRONLY | O_TRUNC | O_CREAT, 0666); + if ( fd == -1 ) + throwf("Could not open or create -dependency_info file: %s", this->dependencyInfoPath()); + + // write header + uint8_t version = depLinkerVersion; + if ( write(fd, &version, 1) == -1 ) + throwf("write() to -dependency_info failed, errno=%d", errno); + extern const char ldVersionString[]; + if ( write(fd, ldVersionString, strlen(ldVersionString)+1) == -1 ) + throwf("write() to -dependency_info failed, errno=%d", errno); + + // write each dependency + for (const auto& entry: fDependencies) { + //printf("%d %s\n", entry.opcode, entry.path.c_str()); + if ( write(fd, &entry.opcode, 1) == -1 ) throwf("write() to -dependency_info failed, errno=%d", errno); - extern const char ldVersionString[]; - if ( write(fDependencyFileDescriptor, ldVersionString, strlen(ldVersionString)+1) == -1 ) + if ( write(fd, entry.path.c_str(), entry.path.size()+1) == -1 ) throwf("write() to -dependency_info failed, errno=%d", errno); } + ::close(fd); +} + + +void Options::addDependency(uint8_t opcode, const char* path) const +{ + if ( !this->dumpDependencyInfo() ) + return; + char realPath[PATH_MAX]; if ( path[0] != '/' ) { if ( realpath(path, realPath) != NULL ) { @@ -5968,12 +6084,10 @@ void Options::dumpDependency(uint8_t opcode, const char* path) const } } - if ( write(fDependencyFileDescriptor, &opcode, 1) == -1 ) - throwf("write() to -dependency_info failed, errno=%d", errno); - if ( write(fDependencyFileDescriptor, path, strlen(path)+1) == -1 ) - throwf("write() to -dependency_info failed, errno=%d", errno); - - //fprintf(stderr, "0x%02X %s\n", opcode, path); + DependencyEntry entry; + entry.opcode = opcode; + entry.path = path; + fDependencies.push_back(entry); }