]> git.saurik.com Git - apple/ld64.git/commitdiff
ld64-351.8.tar.gz developer-tools-93 developer-tools-931 developer-tools-94 developer-tools-941 v351.8
authorApple <opensource@apple.com>
Tue, 18 Sep 2018 21:50:19 +0000 (21:50 +0000)
committerApple <opensource@apple.com>
Tue, 18 Sep 2018 21:50:19 +0000 (21:50 +0000)
33 files changed:
doc/man/man1/ld.1
ld64.xcodeproj/project.pbxproj
src/create_configure
src/ld/InputFiles.cpp
src/ld/InputFiles.h
src/ld/Options.cpp
src/ld/Options.h
src/ld/OutputFile.cpp
src/ld/Resolver.cpp
src/ld/Resolver.h
src/ld/SymbolTable.cpp
src/ld/SymbolTable.h
src/ld/ld.cpp
src/ld/ld.hpp
src/ld/parsers/generic_dylib_file.hpp
src/ld/parsers/lto_file.cpp
src/ld/parsers/macho_relocatable_file.cpp
src/ld/parsers/textstub_dylib_file.cpp
src/ld/parsers/textstub_dylib_file.hpp
src/ld/passes/branch_shim.cpp
src/other/machochecker.cpp
unit-tests/test-cases/linker_options-framework-static-chain/Makefile [new file with mode: 0644]
unit-tests/test-cases/linker_options-framework-static-chain/bar.c [new file with mode: 0644]
unit-tests/test-cases/linker_options-framework-static-chain/baz.c [new file with mode: 0644]
unit-tests/test-cases/linker_options-framework-static-chain/foo.c [new file with mode: 0644]
unit-tests/test-cases/linker_options-framework-static-chain/main.c [new file with mode: 0644]
unit-tests/test-cases/linker_options-framework-static/Makefile [new file with mode: 0644]
unit-tests/test-cases/linker_options-framework-static/foo.c [new file with mode: 0644]
unit-tests/test-cases/linker_options-framework-static/main.c [new file with mode: 0644]
unit-tests/test-cases/lto-duplicate_symbols/Makefile [new file with mode: 0644]
unit-tests/test-cases/lto-duplicate_symbols/main.c [new file with mode: 0644]
unit-tests/test-cases/lto-duplicate_symbols/non-static.c [new file with mode: 0644]
unit-tests/test-cases/lto-duplicate_symbols/static.c [new file with mode: 0644]

index 30692dcae466bd1587cf77880f20fbaf54a4bafa..64641a6aae486b3a9fcc5f88486e564653444e26 100644 (file)
@@ -548,6 +548,10 @@ projects that assume they are built and run on the same OS version.
 Don't run deduplication pass in linker
 .It Fl verbose_deduplicate
 Prints names of functions that are eliminated by deduplication and total code savings size.
+.It Fl no_inits
+Error if the output contains any static initializers
+.It Fl no_warn_inits
+Do not warn if the output contains any static initializers
 .It Fl dirty_data_list Ar filename
 Specifies a file containing the names of data symbols likely to be dirtied.
 If the linker is creating a __DATA_DIRTY segment, those symbols will be moved
@@ -615,6 +619,9 @@ any function whose FDE cannot be expressed in the compact unwind format.
 .It Fl warn_weak_exports
 Issue a warning if the resulting final linked image contains weak external symbols. Such
 symbols require dyld to do extra work at launch time to coalesce those symbols.
+.It Fl no_weak_exports
+Issue an erro if the resulting final linked image contains weak external symbols. Such
+symbols require dyld to do extra work at launch time to coalesce those symbols.
 .It Fl objc_gc_compaction
 Marks the Objective-C image info in the final linked image with the bit that says that the
 code was built to work the compacting garbage collection.
index 7b7260e4730f0c391bbfd784d6d4b063f24a678c..3297210e0ba0325677ba0e9e44310911d813ed25 100644 (file)
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
-                       shellScript = "if [ \"${CONFIGURATION}\" == \"Debug\" ]; then\n    cd \"${TARGET_BUILD_DIR}\"\n    cd ..\n    mkdir -p lib\n    cd lib\n    ln -s -f \"${DT_TOOLCHAIN_DIR}/usr/lib/libLTO.dylib\"\n    ln -s -f \"${DT_TOOLCHAIN_DIR}/usr/lib/libtapi.dylib\"\nfi\n\n";
+                       shellScript = "if [ \"${CONFIGURATION}\" == \"Debug\" ]; then\n    cd \"${TARGET_BUILD_DIR}\"\n    cd ..\n    mkdir -p lib\n    cd lib\n    ln -s -f \"${DT_TOOLCHAIN_DIR}/usr/lib/libLTO.dylib\"\n    ln -s -f \"${DT_TOOLCHAIN_DIR}/usr/lib/libtapi.dylib\"\n    ln -s -f \"${DT_TOOLCHAIN_DIR}/usr/lib/libswiftDemangle.dylib\"\nfi\n\n";
                        showEnvVarsInLog = 0;
                };
                F96D5367094A2754008E9EE8 /* ShellScript */ = {
                                        "-stdlib=libc++",
                                        "-lxar",
                                        "-Wl,-lazy_library,$(DT_TOOLCHAIN_DIR)/usr/lib/libLTO.dylib",
-                                       "@$(DERIVED_FILE_DIR)/linkExtras",
                                        "-Wl,-exported_symbol,__mh_execute_header",
                                        "-L$(DT_TOOLCHAIN_DIR)/usr/lib",
                                        "-ltapi",
+                                       "@$(DERIVED_FILE_DIR)/linkExtras",
                                );
                                PREBINDING = NO;
                                PRODUCT_NAME = ld;
                                        "-stdlib=libc++",
                                        "-lxar",
                                        "-Wl,-lazy_library,$(DT_TOOLCHAIN_DIR)/usr/lib/libLTO.dylib",
-                                       "@$(DERIVED_FILE_DIR)/linkExtras",
                                        "-Wl,-exported_symbol,__mh_execute_header",
                                        "-L$(DT_TOOLCHAIN_DIR)/usr/lib",
                                        "-ltapi",
+                                       "@$(DERIVED_FILE_DIR)/linkExtras",
                                );
                                PREBINDING = NO;
                                PRODUCT_NAME = ld;
                                        "-stdlib=libc++",
                                        "-lxar",
                                        "-Wl,-lazy_library,$(DT_TOOLCHAIN_DIR)/usr/lib/libLTO.dylib",
-                                       "@$(DERIVED_FILE_DIR)/linkExtras",
                                        "-Wl,-exported_symbol,__mh_execute_header",
                                        "-L$(DT_TOOLCHAIN_DIR)/usr/lib",
                                        "-ltapi",
+                                       "@$(DERIVED_FILE_DIR)/linkExtras",
                                );
                                PREBINDING = NO;
                                PRODUCT_NAME = ld;
index a740779f57c69e8a36fd9da64d6613912dc4550e..7ba470b339b833cf37fcebd4ca838a1445b51279 100755 (executable)
@@ -39,7 +39,7 @@ else
 fi
 
 if [ -f "${DT_TOOLCHAIN_DIR}/usr/lib/libswiftDemangle.dylib" ]; then
-       echo "-Wl,-lazy_library,${DT_TOOLCHAIN_DIR}/usr/lib/libswiftDemangle.dylib" >  ${DERIVED_FILE_DIR}/linkExtras
+       echo "${DT_TOOLCHAIN_DIR}/usr/lib/libswiftDemangle.dylib" >  ${DERIVED_FILE_DIR}/linkExtras
        echo "#define DEMANGLE_SWIFT 1" >> ${DERIVED_FILE_DIR}/configure.h
 else
        echo "" > ${DERIVED_FILE_DIR}/linkExtras
index 1c69de62135e58464aca1c0174b4bfe09425485c..2a79ae2ced8b5edcff7df38a3250c81e0ec1f6f8 100644 (file)
@@ -214,6 +214,15 @@ 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
        struct stat stat_buf;
        int fd = ::open(info.path, O_RDONLY, 0);
@@ -455,19 +464,19 @@ void InputFiles::logDylib(ld::File* file, bool indirect, bool speculative)
        if ( _options.dumpDependencyInfo() ) {
                const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(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());
                }
        }
 }
@@ -620,13 +629,14 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHan
                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 {
+                       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);
@@ -635,14 +645,22 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHan
                                                        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", info.path);
+                                               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);
-                               }
                        }
+                       catch (const char* msg) {
+                               warning("Auto-Linking %s", msg);
+                       }
                        state.linkerOptionFrameworks.insert(frameworkName);
                }
 
@@ -653,11 +671,11 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHan
                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 {
+                       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);
@@ -671,8 +689,7 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHan
                                        }
                                        else if ( archiveReader != NULL ) {
                                                _searchLibraries.push_back(LibraryInfo(archiveReader));
-                                               if ( _options.dumpDependencyInfo() )
-                                                       _options.dumpDependency(Options::depArchive, archiveReader->path());
+                                               _options.addDependency(Options::depArchive, archiveReader->path());
                                                //<rdar://problem/17787306> -force_load_swift_libs
                                                if (info.options.fForceLoad) {
                                                        archiveReader->forEachAtom(handler);
@@ -682,10 +699,10 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHan
                                                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);
-                               }
                        }
+                       catch (const char* msg) {
+                               warning("Auto-Linking %s", msg);
+                       }
                        state.linkerOptionLibraries.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);
        }
 
 }
@@ -1199,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:
@@ -1220,8 +1235,7 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler, ld::Internal
                                        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:
index 21f878a513b3046e5e3258a6d804ff5187d56593..ba8ae543dc06824f3bbde4a4d384a2560f048f1d 100644 (file)
@@ -110,7 +110,7 @@ private:
        static void                                     parseWorkerThread(InputFiles *inputFiles);
        void                                            startThread(void (*threadFunc)(InputFiles *)) const;
 
-       typedef std::unordered_map<const char*, ld::dylib::File*, CStringHash, CStringEquals>   InstallNameToDylib;
+       typedef std::map<std::string, ld::dylib::File*> InstallNameToDylib;
 
        const Options&                          _options;
        std::vector<ld::File*>          _inputFiles;
index b7397863330fb3899f120aa552b128de6ceff6f5..6f115d8a5edae5074a5c39f408b1eea081d04cf6 100644 (file)
@@ -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<std::string> &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<tapi::LinkerInterfaceFile> Options::findTAPIFile(const std::string &path) const
+{
+       std::unique_ptr<tapi::LinkerInterfaceFile> 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;
     }
+
+       // <rdar://problem/30746905> [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()
                        // <rdar://problem/24772435> only use v2 for Swift dylibs on Mac OS X
                        if ( strncmp(this->installPath(), "/System/Library/PrivateFrameworks/Swift/", 40) == 0 )
                                fSharedRegionEncodingV2 = true;
+                       // <rdar://problem/32525720> use v2 for ABI stable Swift dylibs on macOS
+                       if ( strncmp(this->installPath(), "/System/Library/Frameworks/Swift/", 33) == 0 )
+                               fSharedRegionEncodingV2 = true;
                        // <rdar://problem/31428120> 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;
 
+       // <rdar://problem/30750137> 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);
 }
 
 
index 4ff780ca35073dd75d7160ed568206e2039f405f..3b0a37ce8599ddf1d416bd0a57de20eb9ba1d8c9 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <stdint.h>
 #include <mach/machine.h>
+#include <tapi/tapi.h>
 
 #include <vector>
 #include <unordered_set>
@@ -37,6 +38,7 @@
 #include "Snapshot.h"
 #include "MachOFileAbstraction.hpp"
 
+
 extern void throwf (const char* format, ...) __attribute__ ((noreturn,format(printf, 1, 2)));
 extern void warning(const char* format, ...) __attribute__((format(printf, 1, 2)));
 
@@ -163,6 +165,7 @@ public:
                LibraryOptions                  options;
                ld::File::Ordinal               ordinal;
                bool                                    fromFileList;
+               bool                                    isInlined;
 
                // These are used by the threaded input file parsing engine.
                mutable int                             inputFileSlot;  // The input file "slot" assigned to this particular file
@@ -171,7 +174,7 @@ public:
         // The use pattern for FileInfo is to create one on the stack in a leaf function and return
         // it to the calling frame by copy. Therefore the copy constructor steals the path string from
         // the source, which dies with the stack frame.
-        FileInfo(FileInfo const &other) : path(other.path), modTime(other.modTime), options(other.options), ordinal(other.ordinal), fromFileList(other.fromFileList), inputFileSlot(-1) { ((FileInfo&)other).path = NULL; };
+        FileInfo(FileInfo const &other) : path(other.path), modTime(other.modTime), options(other.options), ordinal(other.ordinal), fromFileList(other.fromFileList), isInlined(other.isInlined), inputFileSlot(-1) { ((FileInfo&)other).path = NULL; };
 
                FileInfo &operator=(FileInfo other) {
                        std::swap(path, other.path);
@@ -179,16 +182,17 @@ public:
                        std::swap(options, other.options);
                        std::swap(ordinal, other.ordinal);
                        std::swap(fromFileList, other.fromFileList);
+                       std::swap(isInlined, other.isInlined);
                        std::swap(inputFileSlot, other.inputFileSlot);
                        std::swap(readyToParse, other.readyToParse);
                        return *this;
                }
 
         // Create an empty FileInfo. The path can be set implicitly by checkFileExists().
-        FileInfo() : path(NULL), modTime(-1), options(), fromFileList(false) {};
+        FileInfo() : path(NULL), modTime(-1), options(), fromFileList(false), isInlined(false) {};
         
         // Create a FileInfo for a specific path, but does not stat the file.
-        FileInfo(const char *_path) : path(strdup(_path)), modTime(-1), options(), fromFileList(false) {};
+        FileInfo(const char *_path) : path(strdup(_path)), modTime(-1), options(), fromFileList(false), isInlined(false) {};
 
         ~FileInfo() { if (path) ::free((void*)path); }
         
@@ -203,6 +207,19 @@ public:
         bool missing() const { return modTime == -1; }
        };
 
+       class TAPIInterface {
+       public:
+               TAPIInterface(tapi::LinkerInterfaceFile *file, const char* path, const char *installName) :
+                       _file(file), _tbdPath(path), _installName(installName) {}
+               tapi::LinkerInterfaceFile *getInterfaceFile() const { return _file; }
+               std::string getTAPIFilePath() const { return _tbdPath; }
+               const std::string &getInstallName() const { return _installName; }
+       private:
+               tapi::LinkerInterfaceFile *_file;
+               std::string _tbdPath;
+               std::string _installName;
+       };
+       
        struct ExtraSection {
                const char*                             segmentName;
                const char*                             sectionName;
@@ -273,7 +290,7 @@ public:
                  depFileList=0x10, depSection=0x10, depBundleLoader=0x10, depMisc=0x10, depNotFound=0x11,
                  depOutputFile = 0x40 };
        
-       void                                            dumpDependency(uint8_t, const char* path) const;
+       void                                            addDependency(uint8_t, const char* path) const;
        
        typedef const char* const*      UndefinesIterator;
 
@@ -286,6 +303,7 @@ public:
        cpu_subtype_t                           subArchitecture() const { return fSubArchitecture; }
        bool                                            allowSubArchitectureMismatches() const { return fAllowCpuSubtypeMismatches; }
        bool                                            enforceDylibSubtypesMatch() const { return fEnforceDylibSubtypesMatch; }
+       bool                                            warnOnSwiftABIVersionMismatches() const { return fWarnOnSwiftABIVersionMismatches; }
        bool                                            forceCpuSubtypeAll() const { return fForceSubtypeAll; }
        const char*                                     architectureName() const { return fArchitectureName; }
        void                                            setArchitecture(cpu_type_t, cpu_subtype_t subtype, Options::Platform platform);
@@ -353,6 +371,8 @@ public:
        bool                                            keepRelocations();
        FileInfo                                        findFile(const std::string &path, const ld::dylib::File* fromDylib=nullptr) const;
        bool                                            findFile(const std::string &path, const std::vector<std::string> &tbdExtensions, FileInfo& result) const;
+       bool                                            hasInlinedTAPIFile(const std::string &path) const;
+       std::unique_ptr<tapi::LinkerInterfaceFile>      findTAPIFile(const std::string &path) const;
        UUIDMode                                        UUIDMode() const { return fUUIDMode; }
        bool                                            warnStabs();
        bool                                            pauseAtEnd() { return fPause; }
@@ -429,6 +449,7 @@ public:
        bool                                            makeTentativeDefinitionsReal() const { return fMakeTentativeDefinitionsReal; }
        const char*                                     dyldInstallPath() const { return fDyldInstallPath; }
        bool                                            warnWeakExports() const { return fWarnWeakExports; }
+       bool                                            noWeakExports() const { return fNoWeakExports; }
        bool                                            objcGcCompaction() const { return fObjcGcCompaction; }
        bool                                            objcGc() const { return fObjCGc; }
        bool                                            objcGcOnly() const { return fObjCGcOnly; }
@@ -468,7 +489,7 @@ public:
        bool                                            ignoreAutoLink() const { return fIgnoreAutoLink; }
        bool                                            allowDeadDuplicates() const { return fAllowDeadDups; }
        bool                                            allowWeakImports() const { return fAllowWeakImports; }
-       bool                                            noInitializers() const { return fNoInitializers; }
+       Treatment                                       initializersTreatment() const { return fInitializersTreatment; }
        BitcodeMode                                     bitcodeKind() const { return fBitcodeKind; }
        bool                                            sharedRegionEncodingV2() const { return fSharedRegionEncodingV2; }
        bool                                            useDataConstSegment() const { return fUseDataConstSegment; }
@@ -513,6 +534,10 @@ public:
        bool                                            hasCodeSymbolMoves() const { return !fSymbolsMovesCode.empty(); }
        void                                            writeToTraceFile(const char* buffer, size_t len) const;
        UnalignedPointerTreatment       unalignedPointerTreatment() const { return fUnalignedPointerTreatment; }
+       bool                                            zeroModTimeInDebugMap() const { return fZeroModTimeInDebugMap; }
+       void                                            writeDependencyInfo() const;
+       std::vector<TAPIInterface>      &TAPIFiles() { return fTAPIFiles; }
+       void                                            addTAPIInterface(tapi::LinkerInterfaceFile *interface, const char *path) const;
 
        static uint32_t                         parseVersionNumber32(const char*);
 
@@ -549,6 +574,11 @@ private:
                SetWithWildcards        symbols;
        };
 
+       struct DependencyEntry {
+               uint8_t                         opcode;
+               std::string                     path;
+       };
+
        void                                            parse(int argc, const char* argv[]);
        void                                            checkIllegalOptionCombinations();
        void                                            buildSearchPaths(int argc, const char* argv[]);
@@ -701,6 +731,7 @@ private:
        bool                                                            fNoEHLabels;
        bool                                                            fAllowCpuSubtypeMismatches;
        bool                                                            fEnforceDylibSubtypesMatch;
+       bool                                                            fWarnOnSwiftABIVersionMismatches;
        bool                                                            fUseSimplifiedDylibReExports;
        bool                                                            fObjCABIVersion2Override;
        bool                                                            fObjCABIVersion1Override;
@@ -731,6 +762,7 @@ private:
        bool                                                            fTraceEmitJSON;
        bool                                                            fOutputSlidable;
        bool                                                            fWarnWeakExports;
+       bool                                                            fNoWeakExports;
        bool                                                            fObjcGcCompaction;
        bool                                                            fObjCGc;
        bool                                                            fObjCGcOnly;
@@ -788,7 +820,8 @@ private:
        bool                                                            fIgnoreAutoLink;
        bool                                                            fAllowDeadDups;
        bool                                                            fAllowWeakImports;
-       bool                                                            fNoInitializers;
+       Treatment                                                       fInitializersTreatment;
+       bool                                                            fZeroModTimeInDebugMap;
        BitcodeMode                                                     fBitcodeKind;
        Platform                                                        fPlatform;
        DebugInfoStripping                                      fDebugInfoStripping;
@@ -825,10 +858,12 @@ private:
     bool                                                               fSnapshotRequested;
     const char*                                                        fPipelineFifo;
        const char*                                                     fDependencyInfoPath;
-       mutable int                                                     fDependencyFileDescriptor;
        mutable int                                                     fTraceFileDescriptor;
        uint8_t                                                         fMaxDefaultCommonAlign;
        UnalignedPointerTreatment                       fUnalignedPointerTreatment;
+       mutable std::vector<DependencyEntry> fDependencies;
+       mutable std::vector<Options::TAPIInterface> fTAPIFiles;
+
 };
 
 
index 62e052e450913ece5cf2f2ce62ed94380dacb8a9..e5059d55e89838551167889412e9f08f5029c442 100644 (file)
@@ -5311,16 +5311,23 @@ void OutputFile::synthesizeDebugNotes(ld::Internal& state)
        std::sort(atomsNeedingDebugNotes.begin(), atomsNeedingDebugNotes.end(), DebugNoteSorter());
 
        // <rdar://problem/17689030> Add -add_ast_path option to linker which add N_AST stab entry to output
+       std::set<std::string> seenAstPaths;
        const std::vector<const char*>& astPaths = _options.astFilePaths();
        for (std::vector<const char*>::const_iterator it=astPaths.begin(); it != astPaths.end(); it++) {
                const char* path = *it;
+               if ( seenAstPaths.count(path) != 0 )
+                       continue;
+               seenAstPaths.insert(path);
                //  emit N_AST
                ld::relocatable::File::Stab astStab;
                astStab.atom    = NULL;
                astStab.type    = N_AST;
                astStab.other   = 0;
                astStab.desc    = 0;
-               astStab.value   = fileModTime(path);
+               if ( _options.zeroModTimeInDebugMap() )
+                       astStab.value = 0;
+               else
+                       astStab.value = fileModTime(path);
                astStab.string  = path;
                state.stabs.push_back(astStab);
        }
@@ -5387,11 +5394,17 @@ void OutputFile::synthesizeDebugNotes(ld::Internal& state)
                                objStab.desc            = 1;
                                if ( atomObjFile != NULL ) {
                                        objStab.string  = assureFullPath(atomObjFile->debugInfoPath());
-                                       objStab.value   = atomObjFile->debugInfoModificationTime();
+                                       if ( _options.zeroModTimeInDebugMap() )
+                                               objStab.value   = 0;
+                                       else
+                                               objStab.value   = atomObjFile->debugInfoModificationTime();
                                }
                                else {
                                        objStab.string  = assureFullPath(atomFile->path());
-                                       objStab.value   = atomFile->modificationTime();
+                                       if ( _options.zeroModTimeInDebugMap() )
+                                               objStab.value   = 0;
+                                       else
+                                               objStab.value   = atomFile->modificationTime();
                                }
                                state.stabs.push_back(objStab);
                                wroteStartSO = true;
@@ -5401,6 +5414,25 @@ void OutputFile::synthesizeDebugNotes(ld::Internal& state)
                                asprintf(&fullFilePath, "%s%s", newDirPath, newFilename);
                                // add both leaf path and full path
                                seenFiles.insert(fullFilePath);
+
+                               // <rdar://problem/34121435> Add linker support for propagating N_AST debug notes from .o files to linked image
+                               if ( const std::vector<relocatable::File::AstTimeAndPath>* asts = atomObjFile->astFiles() ) {
+                                       for (const relocatable::File::AstTimeAndPath& file : *asts) {
+                                               const char* cpath = file.path.c_str();
+                                               if ( seenAstPaths.count(cpath) != 0 )
+                                                       continue;
+                                               seenAstPaths.insert(cpath);
+                                               //  generate N_AST in output
+                                               ld::relocatable::File::Stab astStab;
+                                               astStab.atom    = NULL;
+                                               astStab.type    = N_AST;
+                                               astStab.other   = 0;
+                                               astStab.desc    = 0;
+                                               astStab.value   = file.time;
+                                               astStab.string  = cpath;
+                                               state.stabs.push_back(astStab);
+                                       }
+                               }
                        }
                        filename = newFilename;
                        dirPath = newDirPath;
@@ -5534,6 +5566,7 @@ void OutputFile::synthesizeDebugNotes(ld::Internal& state)
                        }
                }
        }
+
 }
 
 
index 831fa7f0f051a5ca9ce6f6f0e74ffb9cd390610a..51afe8dfca9b8ac3482228c50d9c347ff28abb2a 100644 (file)
@@ -462,12 +462,22 @@ void Resolver::doFile(const ld::File& file)
                                Options::userReadableSwiftVersion(file.swiftVersion(), fileVersion);
                                Options::userReadableSwiftVersion(_internal.swiftVersion, otherVersion);
                                if ( file.swiftVersion() > _internal.swiftVersion ) {
-                                       throwf("%s compiled with newer version of Swift language (%s) than previous files (%s)", 
-                                                  file.path(), fileVersion, otherVersion);
+                                       if ( _options.warnOnSwiftABIVersionMismatches() ) {
+                                               warning("%s compiled with newer version of Swift language (%s) than previous files (%s)",
+                                                       file.path(), fileVersion, otherVersion);
+                                       } else {
+                                               throwf("%s compiled with newer version of Swift language (%s) than previous files (%s)",
+                                                      file.path(), fileVersion, otherVersion);
+                                       }
                                }
                                else {
-                                       throwf("%s compiled with older version of Swift language (%s) than previous files (%s)", 
-                                              file.path(), fileVersion, otherVersion);
+                                       if ( _options.warnOnSwiftABIVersionMismatches() ) {
+                                               warning("%s compiled with older version of Swift language (%s) than previous files (%s)",
+                                                       file.path(), fileVersion, otherVersion);
+                                       } else {
+                                               throwf("%s compiled with older version of Swift language (%s) than previous files (%s)",
+                                                      file.path(), fileVersion, otherVersion);
+                                       }
                                }
                        }
                }
@@ -479,7 +489,11 @@ void Resolver::doFile(const ld::File& file)
                // remember if any .o file did not have MH_SUBSECTIONS_VIA_SYMBOLS bit set
                if ( ! objFile->canScatterAtoms() )
                        _internal.allObjectFilesScatterable = false;
-       
+
+               // remember if building for profiling (so we don't warn about initializers)
+               if ( objFile->hasllvmProfiling() )
+                       _havellvmProfiling = true;
+
                // update minOSVersion off all .o files
                uint32_t objMinOS = objFile->minOSVersion();
                if ( !objMinOS )
@@ -652,12 +666,22 @@ void Resolver::doFile(const ld::File& file)
                                Options::userReadableSwiftVersion(file.swiftVersion(), fileVersion);
                                Options::userReadableSwiftVersion(_internal.swiftVersion, otherVersion);
                                if ( file.swiftVersion() > _internal.swiftVersion ) {
-                                       throwf("%s compiled with newer version of Swift language (%s) than previous files (%s)", 
-                                                  file.path(), fileVersion, otherVersion);
+                                       if ( _options.warnOnSwiftABIVersionMismatches() ) {
+                                               warning("%s compiled with newer version of Swift language (%s) than previous files (%s)",
+                                                       file.path(), fileVersion, otherVersion);
+                                       } else {
+                                               throwf("%s compiled with newer version of Swift language (%s) than previous files (%s)",
+                                                      file.path(), fileVersion, otherVersion);
+                                       }
                                }
                                else {
-                                       throwf("%s compiled with older version of Swift language (%s) than previous files (%s)", 
-                                              file.path(), fileVersion, otherVersion);
+                                       if ( _options.warnOnSwiftABIVersionMismatches() ) {
+                                               warning("%s compiled with older version of Swift language (%s) than previous files (%s)",
+                                                       file.path(), fileVersion, otherVersion);
+                                       } else {
+                                               throwf("%s compiled with older version of Swift language (%s) than previous files (%s)",
+                                                      file.path(), fileVersion, otherVersion);
+                                       }
                                }
                        }
                }
@@ -794,9 +818,17 @@ void Resolver::doAtom(const ld::Atom& atom)
        if ( atom.section().type() == ld::Section::typeTempAlias )
                _haveAliases = true;
        
-       // prevent initializers if -no_inits used
-       if ( (atom.section().type() == ld::Section::typeInitializerPointers) && _options.noInitializers() ) {
-               throw "-no_inits specified, but initializer found";
+       // error or warn about initializers
+       if ( (atom.section().type() == ld::Section::typeInitializerPointers) && !_havellvmProfiling ) {
+               switch ( _options.initializersTreatment() ) {
+                       case Options::kError:
+                               throwf("static initializer found in '%s'",atom.safeFilePath());
+                       case Options::kWarning:
+                               warning("static initializer found in '%s'. Use -no_inits to make this an error.  Use -no_warn_inits to suppress warning",atom.safeFilePath());
+                               break;
+                       default:
+                               break;
+               }
        }
        
        if ( _options.deadCodeStrip() ) {
@@ -1832,7 +1864,7 @@ void Resolver::linkTimeOptimize()
                // and re-compute dead code
                this->deadStripOptimize(true);
        }
-       
+
        // <rdar://problem/12386559> if -exported_symbols_list on command line, re-force scope
        if ( _options.hasExportMaskList() ) {
                for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
@@ -1856,6 +1888,23 @@ void Resolver::linkTimeOptimize()
 
                // check new code does not override some dylib
                this->checkDylibSymbolCollisions();
+
+               // <rdar://problem/33853815> remove undefs from LTO objects that gets optimized away
+               std::unordered_set<const ld::Atom*> mustPreserve;
+               if ( _internal.classicBindingHelper != NULL )
+                       mustPreserve.insert(_internal.classicBindingHelper);
+               if ( _internal.compressedFastBinderProxy != NULL )
+                       mustPreserve.insert(_internal.compressedFastBinderProxy);
+               if ( _internal.lazyBindingHelper != NULL )
+                       mustPreserve.insert(_internal.lazyBindingHelper);
+               if ( const ld::Atom* entry = this->entryPoint(true) )
+                       mustPreserve.insert(entry);
+               for (Options::UndefinesIterator uit=_options.initialUndefinesBegin(); uit != _options.initialUndefinesEnd(); ++uit) {
+                       SymbolTable::IndirectBindingSlot slot = _symbolTable.findSlotForName(*uit);
+                       if ( _internal.indirectBindingTable[slot] != NULL )
+                               mustPreserve.insert(_internal.indirectBindingTable[slot]);
+               }
+               _symbolTable.removeDeadUndefs(_atoms, mustPreserve);
        }
 }
 
index 06b7a8b0f145702c88e304a1bc473b8fe7ff83c3..811edef61001c41310d725dbfbfc8998a4381cfe 100644 (file)
@@ -64,7 +64,7 @@ public:
                                                                  _haveLLVMObjs(false),
                                                                  _completedInitialObjectFiles(false),
                                                                  _ltoCodeGenFinished(false),
-                                                                 _haveAliases(false) {}
+                                                                 _haveAliases(false), _havellvmProfiling(false) {}
                                                                
 
                virtual void            doAtom(const ld::Atom&);
@@ -135,6 +135,7 @@ private:
        bool                                                    _completedInitialObjectFiles;
        bool                                                    _ltoCodeGenFinished;
        bool                                                    _haveAliases;
+       bool                                                    _havellvmProfiling;
 };
 
 
index 3c12a777d930e6e38915dca081c034d30a3b3cf1..e12c1e4460e7478fcae0417cb0e7929188b91d2d 100644 (file)
@@ -860,6 +860,41 @@ const ld::Atom* SymbolTable::indirectAtom(IndirectBindingSlot slot) const
        return _indirectBindingTable[slot];
 }
 
+
+void SymbolTable::removeDeadUndefs(std::vector<const ld::Atom*>& allAtoms, const std::unordered_set<const ld::Atom*>& keep)
+{
+       // mark the indirect entries in use
+       std::vector<bool> indirectUsed;
+       for (size_t i=0; i < _indirectBindingTable.size(); ++i)
+               indirectUsed.push_back(false);
+       for (const ld::Atom* atom : allAtoms) {
+               for (auto it = atom->fixupsBegin(); it != atom->fixupsEnd(); ++it) {
+                       switch (it->binding) {
+                               case ld::Fixup::bindingsIndirectlyBound:
+                                       indirectUsed[it->u.bindingIndex] = true;
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+       }
+
+       // any indirect entry not in use which points to an undefined proxy can be removed
+       for (size_t slot=0; slot < indirectUsed.size(); ++slot) {
+               if ( !indirectUsed[slot] ) {
+                       const ld::Atom* atom = _indirectBindingTable[slot];
+                       if ( (atom != nullptr) && (atom->definition() == ld::Atom::definitionProxy) && (keep.count(atom) == 0) ) {
+                               const char* name = atom->name();
+                               _indirectBindingTable[slot] = NULL;
+                               _byNameReverseTable.erase(slot);
+                               _byNameTable.erase(name);
+                               allAtoms.erase(std::remove(allAtoms.begin(), allAtoms.end(), atom), allAtoms.end());
+                       }
+               }
+       }
+
+}
+
 void SymbolTable::printStatistics()
 {
 //     fprintf(stderr, "cstring table size: %lu, bucket count: %lu, hash func called %u times\n", 
index 2708f1fce6a75d73cfb45618ea9d78da04f888f8..b48330405e52a8b2543821f909b8bb22d5dad6da 100644 (file)
@@ -127,7 +127,8 @@ public:
        byNameIterator          begin()                                                         { return byNameIterator(_byNameTable.begin(),_indirectBindingTable); }
        byNameIterator          end()                                                           { return byNameIterator(_byNameTable.end(),_indirectBindingTable); }
        void                            printStatistics();
-       
+       void                            removeDeadUndefs(std::vector<const ld::Atom *>& allAtoms, const std::unordered_set<const ld::Atom*>& keep);
+
        // from ld::IndirectBindingTable
        virtual const char*                     indirectName(IndirectBindingSlot slot) const;
        virtual const ld::Atom*         indirectAtom(IndirectBindingSlot slot) const;
index a8d2276651f078ca402709b4a81c7f94696599e3..e0830ab7cb106e1ae36089292c58794088b661d9 100644 (file)
@@ -945,6 +945,8 @@ void InternalState::setSectionSizesAndAlignments()
                                                this->hasWeakExternalSymbols = true;
                                                if ( _options.warnWeakExports() ) 
                                                        warning("weak external symbol: %s", atom->name());
+                                               else if ( _options.noWeakExports()      )
+                                                       throwf("weak external symbol: %s", atom->name());
                                }
                        }
                        sect->size = offset;
@@ -1351,6 +1353,8 @@ int main(int argc, const char* argv[])
                // sort final sections
                state.sortSections();
 
+               options.writeDependencyInfo();
+
                // write output file
                statistics.startOutput = mach_absolute_time();
                ld::tool::OutputFile out(options);
index 5e9164f14953fcf3f6300c09b2aee7ed02957587..71e5a21712f577faf6bcc82df0397a5ccf251738 100644 (file)
@@ -214,6 +214,7 @@ namespace relocatable {
                };
                typedef const std::vector< std::vector<const char*> > LinkerOptionsList;
                typedef std::vector<std::pair<uint32_t,uint32_t>> ToolVersionList;
+               struct AstTimeAndPath { uint64_t time; std::string path; };
 
                                                                                        File(const char* pth, time_t modTime, Ordinal ord)
                                                                                                : ld::File(pth, modTime, ord, Reloc) { }
@@ -224,10 +225,12 @@ namespace relocatable {
                virtual const std::vector<Stab>*        stabs() const = 0;
                virtual bool                                            canScatterAtoms() const = 0;
                virtual bool                                            hasLongBranchStubs()            { return false; }
+               virtual bool                                            hasllvmProfiling() const    { return false; }
                virtual LinkerOptionsList*                      linkerOptions() const = 0;
                virtual const ToolVersionList&          toolVersions() const = 0;
                virtual SourceKind                                      sourceKind() const { return kSourceUnknown; }
                virtual const uint8_t*                          fileContent() const { return nullptr; }
+               virtual const std::vector<AstTimeAndPath>*      astFiles() const { return nullptr; }
        };
 } // namespace relocatable
 
index eb9d0ead94febe36918c820b048398e5ecd59c2b..0b781bec7091957e5bbc75e1087a6a1564dcfc11 100644 (file)
@@ -138,7 +138,7 @@ public:
 
 
        // overrides of ld::dylib::File
-       virtual void                                                    processIndirectLibraries(ld::dylib::File::DylibHandler*, bool addImplicitDylibs) override final;
+       virtual void                                                    processIndirectLibraries(ld::dylib::File::DylibHandler*, bool addImplicitDylibs) override;
        virtual bool                                                    providedExportAtom() const      override final { return _providedAtom; }
        virtual const char*                                             parentUmbrella() const override final { return _parentUmbrella; }
        virtual const std::vector<const char*>* allowableClients() const override final { return _allowableClients.empty() ? nullptr : &_allowableClients; }
index 586516c8e8ea9802c20754765a289eb32c510cd2..811b6b308d5a69e87db75d465df6cbab90eaf270 100644 (file)
@@ -1459,7 +1459,7 @@ void Parser::AtomSyncer::doAtom(const ld::Atom& machoAtom)
        // update proxy atoms to point to real atoms and find new atoms
        const char* name = machoAtom.name();
        CStringToAtom::const_iterator pos = _llvmAtoms.find(name);
-       if ( pos != _llvmAtoms.end() ) {
+       if ( (pos != _llvmAtoms.end()) && (machoAtom.scope() != ld::Atom::scopeTranslationUnit) ) {
                // turn Atom into a proxy for this mach-o atom
                if (pos->second->scope() == ld::Atom::scopeLinkageUnit) {
                        if (log) fprintf(stderr, "demote %s to hidden after LTO\n", name);
@@ -1535,6 +1535,7 @@ void Parser::AtomSyncer::doAtom(const ld::Atom& machoAtom)
                                // If mach-o atom is referencing another mach-o atom then 
                                // reference is not going through Atom proxy. Fix it here to ensure that all
                                // llvm symbol references always go through Atom proxy.
+                               if ( fit->u.target->scope() != ld::Atom::scopeTranslationUnit )
                                {
                                        const char* targetName = fit->u.target->name();
                                        CStringToAtom::const_iterator post = _llvmAtoms.find(targetName);
index 47c2ac0e2d68602b1e8322cc2c87e6768f4f3420..ae3be5f5cd5ba86d9a1bd59fcca668870ee7b339 100644 (file)
@@ -86,6 +86,7 @@ public:
                                                                                                _minOSVersion(0),
                                                                                                _platform(Options::kPlatformUnknown),
                                                                                                _canScatterAtoms(false),
+                                                                                               _hasllvmProfiling(false),
                                                                                                _objcHasCategoryClassPropertiesField(false),
                                                                                                _srcKind(kSourceUnknown) { }
        virtual                                                                 ~File();
@@ -105,6 +106,7 @@ public:
        virtual DebugInfoKind                                                           debugInfo() const                               { return _debugInfoKind; }
        virtual const std::vector<ld::relocatable::File::Stab>* stabs() const                           { return &_stabs; }
        virtual bool                                                                            canScatterAtoms() const                 { return _canScatterAtoms; }
+       virtual bool                                                                            hasllvmProfiling() const        { return _hasllvmProfiling; }
        virtual const char*                                                                     translationUnitSource() const;
        virtual LinkerOptionsList*                                                      linkerOptions() const                   { return &_linkerOptions; }
        virtual const ToolVersionList&                                          toolVersions() const                    { return _toolVersions; }
@@ -113,12 +115,15 @@ public:
        virtual SourceKind                                                                      sourceKind() const                              { return _srcKind; }
        
        virtual const uint8_t*                                                          fileContent() const                             { return _fileContent; }
+       virtual const std::vector<AstTimeAndPath>*                      astFiles() const                                { return &_astFiles; }
+
+       void                                                                                    setHasllvmProfiling()                   { _hasllvmProfiling = true; }
 private:
        friend class Atom<A>;
        friend class Section<A>;
        friend class Parser<A>;
        friend class CFISection<A>::OAS;
-       
+
        typedef typename A::P                                   P;
        
        const uint8_t*                                                  _fileContent;
@@ -132,6 +137,7 @@ private:
        std::vector<ld::Atom::UnwindInfo>               _unwindInfos;
        std::vector<ld::Atom::LineInfo>                 _lineInfos;
        std::vector<ld::relocatable::File::Stab>_stabs;
+       std::vector<AstTimeAndPath>                             _astFiles;
        ld::relocatable::File::DebugInfoKind    _debugInfoKind;
        const char*                                                             _dwarfTranslationUnitPath;
        const macho_section<P>*                                 _dwarfDebugInfoSect;
@@ -144,6 +150,7 @@ private:
        uint32_t                                                                _minOSVersion;
        Options::Platform                                               _platform;
        bool                                                                    _canScatterAtoms;
+       bool                                                                    _hasllvmProfiling;
        bool                                                                    _objcHasCategoryClassPropertiesField;
        std::vector<std::vector<const char*> >  _linkerOptions;
        std::unique_ptr<ld::Bitcode>                    _bitcode;
@@ -1214,6 +1221,7 @@ private:
 
        void                                                                                    parseDebugInfo();
        void                                                                                    parseStabs();
+       void                                                                                    addAstFiles();
        void                                                                                    appendAliasAtoms(uint8_t* atomBuffer);
        static bool                                                                             isConstFunStabs(const char *stabStr);
        bool                                                                                    read_comp_unit(const char ** name, const char ** comp_dir,
@@ -1554,7 +1562,6 @@ template <typename A>
 bool Parser<A>::LabelAndCFIBreakIterator::next(Parser<A>& parser, const Section<A>& sect, uint32_t sectNum, pint_t startAddr, pint_t endAddr, 
                                                                                                pint_t* addr, pint_t* size, const macho_nlist<P>** symbol)
 {
-       bool cfiApplicable = (sect.machoSection()->flags() & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS));
        // may not be a label on start of section, but need atom demarcation there
        if ( newSection ) {
                newSection = false;
@@ -1614,7 +1621,7 @@ bool Parser<A>::LabelAndCFIBreakIterator::next(Parser<A>& parser, const Section<
                        return true;
                }
                // no symbols in section, check CFI
-               if ( cfiApplicable && (cfiIndex < cfiStartsCount) ) {
+               if ( cfiIndex < cfiStartsCount ) {
                        pint_t nextCfiAddr = cfiStartsArray[cfiIndex];
                        if ( nextCfiAddr < endAddr ) {
                                // use cfi
@@ -2185,18 +2192,13 @@ bool Parser<A>::parseLoadCommands(Options::Platform platform, uint32_t linkMinOS
        }
 
 
-       // validate just one segment
+       // record range of sections
        if ( segment == NULL ) 
                throw "missing LC_SEGMENT";
-       if ( segment->filesize() > _fileLength )
-               throw "LC_SEGMENT filesize too large";
-
-       // record and validate sections
        _sectionsStart = (macho_section<P>*)((char*)segment + sizeof(macho_segment_command<P>));
        _machOSectionsCount = segment->nsects();
        if ( (sizeof(macho_segment_command<P>) + _machOSectionsCount * sizeof(macho_section<P>)) > segment->cmdsize() )
                throw "too many sections for size of LC_SEGMENT command";
-
        return true;
 }
 
@@ -3630,6 +3632,8 @@ bool Parser<A>::isConstFunStabs(const char *stabStr)
 template <typename A>
 void Parser<A>::parseDebugInfo()
 {
+       addAstFiles();
+       
        // check for dwarf __debug_info section
        if ( _file->_dwarfDebugInfoSect == NULL ) {
                // if no DWARF debug info, look for stabs
@@ -4000,6 +4004,22 @@ void Parser<A>::parseStabs()
 }
 
 
+template <typename A>
+void Parser<A>::addAstFiles()
+{
+       // scan symbol table for N_AST entries
+       for (uint32_t symbolIndex = 0; symbolIndex < _symbolCount; ++symbolIndex ) {
+               const macho_nlist<P>& sym = this->symbolFromIndex(symbolIndex);
+               if ( (sym.n_type() == N_AST) &&  (sym.n_strx() != 0) ) {
+                       const char* symString = this->nameFromSymbol(sym);
+                       ld::relocatable::File::AstTimeAndPath entry;
+                       entry.time = sym.n_value();
+                       entry.path = symString;
+                       _file->_astFiles.push_back(entry);
+               }
+       }
+}
+
 
 // Look at the compilation unit DIE and determine
 // its NAME, compilation directory (in COMP_DIR) and its
@@ -4445,7 +4465,7 @@ bool CFISection<A>::needsRelocating()
 
 template <>
 void CFISection<x86_64>::cfiParse(class Parser<x86_64>& parser, uint8_t* buffer,
-                                                                       libunwind::CFI_Atom_Info<CFISection<x86_64>::OAS>::CFI_Atom_Info cfiArray[], 
+                                                                       libunwind::CFI_Atom_Info<CFISection<x86_64>::OAS> cfiArray[],
                                                                        uint32_t& count, const pint_t cuStarts[], uint32_t cuCount)
 {
        const uint32_t sectionSize = this->_machOSection->size();
@@ -4510,7 +4530,7 @@ void CFISection<x86_64>::cfiParse(class Parser<x86_64>& parser, uint8_t* buffer,
 
 template <>
 void CFISection<x86>::cfiParse(class Parser<x86>& parser, uint8_t* buffer, 
-                                                                       libunwind::CFI_Atom_Info<CFISection<x86>::OAS>::CFI_Atom_Info cfiArray[], 
+                                                                       libunwind::CFI_Atom_Info<CFISection<x86>::OAS> cfiArray[],
                                                                        uint32_t& count, const pint_t cuStarts[], uint32_t cuCount)
 {
        // create ObjectAddressSpace object for use by libunwind
@@ -4531,7 +4551,7 @@ void CFISection<x86>::cfiParse(class Parser<x86>& parser, uint8_t* buffer,
 
 template <>
 void CFISection<arm>::cfiParse(class Parser<arm>& parser, uint8_t* buffer, 
-                                                                       libunwind::CFI_Atom_Info<CFISection<arm>::OAS>::CFI_Atom_Info cfiArray[], 
+                                                                       libunwind::CFI_Atom_Info<CFISection<arm>::OAS> cfiArray[],
                                                                        uint32_t& count, const pint_t cuStarts[], uint32_t cuCount)
 {
        if ( !parser.armUsesZeroCostExceptions() ) {
@@ -4557,7 +4577,7 @@ void CFISection<arm>::cfiParse(class Parser<arm>& parser, uint8_t* buffer,
 
 template <>
 void CFISection<arm64>::cfiParse(class Parser<arm64>& parser, uint8_t* buffer, 
-                                                                       libunwind::CFI_Atom_Info<CFISection<arm64>::OAS>::CFI_Atom_Info cfiArray[], 
+                                                                       libunwind::CFI_Atom_Info<CFISection<arm64>::OAS> cfiArray[],
                                                                        uint32_t& count, const pint_t cuStarts[], uint32_t cuCount)
 {
        // copy __eh_frame data to buffer
@@ -5268,6 +5288,9 @@ SymboledSection<A>::SymboledSection(Parser<A>& parser, File<A>& f, const macho_s
                                _type = ld::Atom::typeLSDA;
                        else if ( this->type() == ld::Section::typeInitializerPointers )
                                _type = ld::Atom::typeInitializerPointers;
+                       // <rdar://problem/34716321> don't warn about static initializers in dylibs built for profiling
+                       if ( strncmp(s->sectname(), "__llvm_prf_", 11) == 0 )
+                               this->_file.setHasllvmProfiling();
                        break;
        }
 }
@@ -6285,8 +6308,6 @@ bool Section<x86_64>::addRelocFixup(class Parser<x86_64>& parser, const macho_re
        Parser<x86_64>::TargetDesc              target;
        Parser<x86_64>::TargetDesc              toTarget;
        src.atom = this->findAtomByAddress(srcAddr);
-       if ( src.atom == NULL )
-               throwf("malformed mach-o, reloc addr 0x%llX not in any atom", srcAddr);
        src.offsetInAtom = srcAddr - src.atom->_objAddress;
        const uint8_t* fixUpPtr = file().fileContent() + sect->offset() + reloc->r_address();
        uint64_t contentValue = 0;
@@ -7469,8 +7490,12 @@ bool Section<arm64>::addRelocFixup(class Parser<arm64>& parser, const macho_relo
                                parser.findTargetFromAddressAndSectionNum(contentValue, nextReloc->r_symbolnum(), toTarget);
                                useDirectBinding = (toTarget.atom->scope() == ld::Atom::scopeTranslationUnit);
                        }
-                       if ( useDirectBinding )
-                               parser.addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, toTarget.atom);
+                       if ( useDirectBinding ) {
+                               if ( (toTarget.atom->combine() == ld::Atom::combineByNameAndContent) || (toTarget.atom->combine() == ld::Atom::combineByNameAndReferences) )
+                                       parser.addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, toTarget.atom);
+                               else
+                                       parser.addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, toTarget.atom);
+                       }
                        else
                                parser.addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, toTarget.weakImport, toTarget.name);
                        parser.addFixup(src, ld::Fixup::k2of4, ld::Fixup::kindAddAddend, toTarget.addend);
index 076736e714929eb6bafe0c297d3c7c382cb282d8..27c456010e8fde56378dcca2a7bc52d81a7330ba 100644 (file)
@@ -29,7 +29,7 @@
 #include <vector>
 
 #include "Architectures.hpp"
-#include "bitcode.hpp"
+#include "Bitcode.hpp"
 #include "MachOFileAbstraction.hpp"
 #include "MachOTrie.hpp"
 #include "generic_dylib_file.hpp"
@@ -50,7 +50,14 @@ class File final : public generic::dylib::File<A>
        using Base = generic::dylib::File<A>;
 
 public:
-                                       File(const char* path, const uint8_t* fileContent, uint64_t fileLength,
+                                       File(const char* path, const uint8_t* fileContent, uint64_t fileLength, const Options *opts,
+                                                time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace,
+                                                bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
+                                                Options::Platform platform, uint32_t linkMinOSVersion, bool allowWeakImports,
+                                                cpu_type_t cpuType, cpu_subtype_t cpuSubType, bool enforceDylibSubtypesMatch,
+                                                bool allowSimToMacOSX, bool addVers, bool buildingForSimulator,
+                                                bool logAllFiles, const char* installPath, bool indirectDylib);
+                                       File(std::unique_ptr<tapi::LinkerInterfaceFile> &&file, const char *path, const Options *opts,
                                                 time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace,
                                                 bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
                                                 Options::Platform platform, uint32_t linkMinOSVersion, bool allowWeakImports,
@@ -58,9 +65,18 @@ public:
                                                 bool allowSimToMacOSX, bool addVers, bool buildingForSimulator,
                                                 bool logAllFiles, const char* installPath, bool indirectDylib);
        virtual                 ~File() noexcept {}
+       
+       // overrides of generic::dylib::File
+       virtual void    processIndirectLibraries(ld::dylib::File::DylibHandler*, bool addImplicitDylibs) override final;
 
 private:
+       void                    init(tapi::LinkerInterfaceFile *file, const Options *opts, bool buildingForSimulator,
+                                                bool indirectDylib, bool linkingFlatNamespace, bool linkingMainExecutable,
+                                                const char *path, Options::Platform platform, const char *targetInstallPath);
        void                    buildExportHashTable(const tapi::LinkerInterfaceFile* file);
+       
+       const Options   *_opts;
+       std::unique_ptr<tapi::LinkerInterfaceFile> _interface;
 };
 
 static ld::File::ObjcConstraint mapObjCConstraint(tapi::ObjCConstraint constraint) {
@@ -101,8 +117,8 @@ static Options::Platform mapPlatform(tapi::Platform platform) {
        return Options::kPlatformUnknown;
 }
 
-template <typename A>
-       File<A>::File(const char* path, const uint8_t* fileContent, uint64_t fileLength,
+       template <typename A>
+       File<A>::File(const char* path, const uint8_t* fileContent, uint64_t fileLength, const Options *opts,
                          time_t mTime, ld::File::Ordinal ord, bool linkingFlatNamespace,
                          bool linkingMainExecutable, bool hoistImplicitPublicDylibs, Options::Platform platform,
                          uint32_t linkMinOSVersion, bool allowWeakImports, cpu_type_t cpuType, cpu_subtype_t cpuSubType,
@@ -112,12 +128,25 @@ template <typename A>
        : Base(strdup(path), mTime, ord, platform, linkMinOSVersion, allowWeakImports, linkingFlatNamespace,
                   hoistImplicitPublicDylibs, allowSimToMacOSX, addVers)
 {
-       std::unique_ptr<tapi::LinkerInterfaceFile> file;
        std::string errorMessage;
 
 // <rdar://problem/29038544> Support $ld$weak symbols in .tbd files
-#if ((TAPI_API_VERSION_MAJOR == 1 &&  TAPI_API_VERSION_MINOR >= 1) || (TAPI_API_VERSION_MAJOR > 1))
+#if ((TAPI_API_VERSION_MAJOR == 1 &&  TAPI_API_VERSION_MINOR >= 3) || (TAPI_API_VERSION_MAJOR > 1))
        // Check if the library supports the new create API.
+       if (tapi::APIVersion::isAtLeast(1, 3)) {
+               tapi::ParsingFlags flags = tapi::ParsingFlags::None;
+               if (enforceDylibSubtypesMatch)
+                       flags |= tapi::ParsingFlags::ExactCpuSubType;
+
+               if (!allowWeakImports)
+                       flags |= tapi::ParsingFlags::DisallowWeakImports;
+
+               _interface.reset(tapi::LinkerInterfaceFile::create(
+                       path, cpuType, cpuSubType, flags,
+                       tapi::PackedVersion32(linkMinOSVersion), errorMessage));
+       } else
+#endif
+#if ((TAPI_API_VERSION_MAJOR == 1 &&  TAPI_API_VERSION_MINOR >= 1) || (TAPI_API_VERSION_MAJOR > 1))
        if (tapi::APIVersion::isAtLeast(1, 1)) {
                tapi::ParsingFlags flags = tapi::ParsingFlags::None;
                if (enforceDylibSubtypesMatch)
@@ -126,27 +155,23 @@ template <typename A>
                if (!allowWeakImports)
                        flags |= tapi::ParsingFlags::DisallowWeakImports;
 
-               file.reset(tapi::LinkerInterfaceFile::create(
+               _interface.reset(tapi::LinkerInterfaceFile::create(
                        path, fileContent, fileLength, cpuType, cpuSubType, flags,
                        tapi::PackedVersion32(linkMinOSVersion), errorMessage));
-       } else {
+       } else
+#endif
+#if (TAPI_API_VERSION_MAJOR >= 1)
+       {
                auto matchingType = enforceDylibSubtypesMatch ?
-                               tapi::CpuSubTypeMatching::Exact : tapi::CpuSubTypeMatching::ABI_Compatible;
+                       tapi::CpuSubTypeMatching::Exact : tapi::CpuSubTypeMatching::ABI_Compatible;
 
-               file.reset(tapi::LinkerInterfaceFile::create(
+               _interface.reset(tapi::LinkerInterfaceFile::create(
                        path, fileContent, fileLength, cpuType, cpuSubType, matchingType,
                        tapi::PackedVersion32(linkMinOSVersion), errorMessage));
        }
-#else
-       auto matchingType = enforceDylibSubtypesMatch ?
-               tapi::CpuSubTypeMatching::Exact : tapi::CpuSubTypeMatching::ABI_Compatible;
-
-       file.reset(tapi::LinkerInterfaceFile::create(
-               path, fileContent, fileLength, cpuType, cpuSubType, matchingType,
-               tapi::PackedVersion32(linkMinOSVersion), errorMessage));
 #endif
 
-       if (file == nullptr)
+       if (!_interface)
                throw strdup(errorMessage.c_str());
 
        // unmap file - it is no longer needed.
@@ -156,6 +181,30 @@ template <typename A>
        if ( logAllFiles )
                printf("%s\n", path);
 
+       init(_interface.get(), opts, buildingForSimulator, indirectDylib, linkingFlatNamespace,
+                linkingMainExecutable, path, platform, targetInstallPath);
+}
+
+       template<typename A>
+       File<A>::File(std::unique_ptr<tapi::LinkerInterfaceFile> &&file, const char* path, const Options *opts,
+                                 time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace,
+                                bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
+                                Options::Platform platform, uint32_t linkMinOSVersion, bool allowWeakImports,
+                                cpu_type_t cpuType, cpu_subtype_t cpuSubType, bool enforceDylibSubtypesMatch,
+                                bool allowSimToMacOSX, bool addVers, bool buildingForSimulator,
+                                bool logAllFiles, const char* installPath, bool indirectDylib)
+       : Base(strdup(path), mTime, ordinal, platform, linkMinOSVersion, allowWeakImports, linkingFlatNamespace,
+                  hoistImplicitPublicDylibs, allowSimToMacOSX, addVers), _interface(std::move(file))
+{
+       init(_interface.get(), opts, buildingForSimulator, indirectDylib, linkingFlatNamespace,
+                linkingMainExecutable, path, platform, installPath);
+}
+       
+template<typename A>
+void File<A>::init(tapi::LinkerInterfaceFile *file, const Options *opts, bool buildingForSimulator,
+                                  bool indirectDylib, bool linkingFlatNamespace, bool linkingMainExecutable,
+                                  const char *path, Options::Platform platform, const char *targetInstallPath) {
+       _opts = opts;
        this->_bitcode = std::unique_ptr<ld::Bitcode>(new ld::Bitcode(nullptr, 0));
        this->_noRexports = !file->hasReexportedLibraries();
        this->_hasWeakExports = file->hasWeakDefinedExports();
@@ -179,16 +228,16 @@ template <typename A>
                if ( strstr(this->_dylibInstallPath, frname) != NULL )
                        this->_frameworkName = leafName;
        }
-
+       
        for (auto &client : file->allowableClients())
                this->_allowableClients.push_back(strdup(client.c_str()));
-
+       
        // <rdar://problem/20659505> [TAPI] Don't hoist "public" (in /usr/lib/) dylibs that should not be directly linked
        this->_hasPublicInstallName = file->hasAllowableClients() ? false : this->isPublicLocation(file->getInstallName().c_str());
-
+       
        for (const auto &client : file->allowableClients())
                this->_allowableClients.emplace_back(strdup(client.c_str()));
-
+       
        auto dylibPlatform = mapPlatform(file->getPlatform());
        if ( (dylibPlatform != platform) && (platform != Options::kPlatformUnknown) ) {
                this->_wrongOS = true;
@@ -196,23 +245,23 @@ template <typename A>
                        if ( buildingForSimulator ) {
                                if ( !this->_allowSimToMacOSXLinking )
                                        throwf("building for %s simulator, but linking against dylib built for %s (%s).",
-                                                       Options::platformName(platform), Options::platformName(dylibPlatform), path);
+                                                  Options::platformName(platform), Options::platformName(dylibPlatform), path);
                        } else {
                                throwf("building for %s, but linking against dylib built for %s (%s).",
-                                               Options::platformName(platform), Options::platformName(dylibPlatform), path);
+                                          Options::platformName(platform), Options::platformName(dylibPlatform), path);
                        }
                }
        }
-
+       
        for (const auto& reexport : file->reexportedLibraries()) {
                const char *path = strdup(reexport.c_str());
                if ( (targetInstallPath == nullptr) || (strcmp(targetInstallPath, path) != 0) )
                        this->_dependentDylibs.emplace_back(path, true);
        }
-
+       
        for (const auto& symbol : file->ignoreExports())
                this->_ignoreExports.insert(strdup(symbol.c_str()));
-
+       
        // if linking flat and this is a flat dylib, create one atom that references all imported symbols.
        if ( linkingFlatNamespace && linkingMainExecutable && (file->hasTwoLevelNamespace() == false) ) {
                std::vector<const char*> importNames;
@@ -223,9 +272,9 @@ template <typename A>
                        importNames.emplace_back(sym.getName().c_str());
                this->_importAtom = new generic::dylib::ImportAtom<A>(*this, importNames);
        }
-
+       
        // build hash table
-       buildExportHashTable(file.get());
+       buildExportHashTable(file);
 }
 
 template <typename A>
@@ -245,6 +294,13 @@ void File<A>::buildExportHashTable(const tapi::LinkerInterfaceFile* file) {
        }
 }
 
+template <typename A>
+void File<A>::processIndirectLibraries(ld::dylib::File::DylibHandler* handler, bool addImplicitDylibs) {
+       if (_interface)
+               _opts->addTAPIInterface(_interface.get(), this->path());
+       Base::processIndirectLibraries(handler, addImplicitDylibs);
+}
+
 template <typename A>
 class Parser
 {
@@ -256,7 +312,7 @@ public:
                                                                  ld::File::Ordinal ordinal, const Options& opts,
                                                                  bool indirectDylib)
        {
-               return new File<A>(path, fileContent, fileLength,mTime, ordinal,
+               return new File<A>(path, fileContent, fileLength, &opts, mTime, ordinal,
                                                   opts.flatNamespace(),
                                                   opts.linkingMainExecutable(),
                                                   opts.implicitlyLinkIndirectPublicDylibs(),
@@ -273,6 +329,29 @@ public:
                                                   opts.installPath(),
                                                   indirectDylib);
        }
+       
+       static ld::dylib::File* parse(const char* path, std::unique_ptr<tapi::LinkerInterfaceFile> &&file, time_t mTime,
+                                                                 ld::File::Ordinal ordinal, const Options& opts,
+                                                                 bool indirectDylib)
+       {
+               return new File<A>(std::move(file), path, &opts, mTime, ordinal,
+                                                  opts.flatNamespace(),
+                                                  opts.linkingMainExecutable(),
+                                                  opts.implicitlyLinkIndirectPublicDylibs(),
+                                                  opts.platform(),
+                                                  opts.minOSversion(),
+                                                  opts.allowWeakImports(),
+                                                  opts.architecture(),
+                                                  opts.subArchitecture(),
+                                                  opts.enforceDylibSubtypesMatch(),
+                                                  opts.allowSimulatorToLinkWithMacOSX(),
+                                                  opts.addVersionLoadCommand(),
+                                                  opts.targetIOSSimulator(),
+                                                  opts.logAllFiles(),
+                                                  opts.installPath(),
+                                                  indirectDylib);
+       }
+
 };
 
 //
@@ -307,7 +386,31 @@ ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, const ch
        }
        return nullptr;
 }
-       
-       
+
+ld::dylib::File *parse(const char *path, std::unique_ptr<tapi::LinkerInterfaceFile> &&file, time_t modTime,
+                                          ld::File::Ordinal ordinal, const Options& opts, bool indirectDylib) {
+       switch ( opts.architecture() ) {
+#if SUPPORT_ARCH_x86_64
+               case CPU_TYPE_X86_64:
+                       return Parser<x86_64>::parse(path, std::move(file), modTime, ordinal, opts, indirectDylib);
+#endif
+#if SUPPORT_ARCH_i386
+               case CPU_TYPE_I386:
+                       return Parser<x86>::parse(path, std::move(file), modTime, ordinal, opts, indirectDylib);
+#endif
+#if SUPPORT_ARCH_arm_any
+               case CPU_TYPE_ARM:
+                       return Parser<arm>::parse(path, std::move(file), modTime, ordinal, opts, indirectDylib);
+#endif
+#if SUPPORT_ARCH_arm64
+               case CPU_TYPE_ARM64:
+                       return Parser<arm64>::parse(path, std::move(file), modTime, ordinal, opts, indirectDylib);
+#endif
+       }
+       return nullptr;
+
+}
+
+
 } // namespace dylib
 } // namespace textstub
index e0a75f6f033b284edac3d731e929dac8ba826f96..9931908c58cbb446ca7c2be3ba481004154903ce 100644 (file)
@@ -36,6 +36,9 @@ extern ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, c
                                                          time_t modTime, const Options& opts, ld::File::Ordinal ordinal,
                                                          bool bundleLoader, bool indirectDylib);
 
+extern ld::dylib::File *parse(const char *path, std::unique_ptr<tapi::LinkerInterfaceFile> &&file, time_t modTime,
+                              ld::File::Ordinal ordinal, const Options& opts, bool indirectDylib);
+
 } // namespace dylib
 } // namespace textstub
 
index 7be33d2ea5fa05d7a112555332227e1869636c9b..d5f81eb99cf1c1e001c8ffb689dc8fdea634faca 100644 (file)
@@ -348,7 +348,7 @@ void doPass(const Options& opts, ld::Internal& state)
                                                                break;
                                                        fixUpLocation += fit->offsetInAtom;
                                                        uint32_t instruction = *((uint32_t*)fixUpLocation);
-                                                       bool is_b = ((instruction & 0x0F000000) == 0x0A000000) && ((instruction & 0xF0000000) != 0xF0000000);
+                                                       bool is_b = ((instruction & 0x0E000000) == 0x0A000000) && ((instruction & 0xF0000000) != 0xF0000000);
                                                        // need shim for branch from arm to thumb, or for call to function outside kext
                                                        if ( is_b || (targetIsProxy && makingKextBundle) ) {
                                                                if ( _s_log ) fprintf(stderr, "need to add arm->thumb instr=0x%08X shim to %s for %s\n", instruction, target->name(), atom->name()); 
index eddcbc96c26d0c655533f1130b13c8e40d178706..ef6ba486e1ae9b55164d8ece518d58a351972299 100644 (file)
@@ -393,7 +393,7 @@ void MachOChecker<A>::checkMachHeader()
                throw "sizeofcmds in mach_header is larger than file";
        
        uint32_t flags = fHeader->flags();
-       const uint32_t invalidBits = MH_INCRLINK | MH_LAZY_INIT | 0xFC000000;
+       const uint32_t invalidBits = MH_INCRLINK | MH_LAZY_INIT | 0xF8000000;
        if ( flags & invalidBits )
                throw "invalid bits in mach_header flags";
        if ( (flags & MH_NO_REEXPORTED_DYLIBS) && (fHeader->filetype() != MH_DYLIB) ) 
diff --git a/unit-tests/test-cases/linker_options-framework-static-chain/Makefile b/unit-tests/test-cases/linker_options-framework-static-chain/Makefile
new file mode 100644 (file)
index 0000000..fdeed4c
--- /dev/null
@@ -0,0 +1,54 @@
+##
+# Copyright (c) 2013 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check linker options work for -framework containing static archives
+# in a recursive manner, chaining linkage from one archive to another
+#
+
+run: all
+
+all:
+       mkdir -p Baz.framework
+       ${CC} ${CCFLAGS} baz.c -c -o baz.o
+       libtool -static baz.o -o Baz.framework/Baz
+       mkdir -p Bar.framework
+       ${CC} ${CCFLAGS} bar.c -c -o bar.o
+       libtool -static bar.o -o Bar.framework/Bar
+       mkdir -p Foo.framework
+       ${CC} ${CCFLAGS} foo.c -c -o foo.o
+       ${LD} -r foo.o -add_linker_option '-framework Bar' -add_linker_option '-framework Baz' -o foo.o
+       libtool -static foo.o -o Foo.framework/Foo
+       ${CC} ${CCFLAGS} main.c -c -o main.o
+       ${LD} -r main.o -add_linker_option '-framework Foo' -o main.o 
+       ${CC} ${CCFLAGS} main.o -o main -F.
+       ${DYLDINFO} -export main | grep _baz | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -export main | grep _bar | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -export main | grep _foo | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -export main | grep _main | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+       rm -rf main main.o foo.o bar.o baz.o Foo.framework Bar.framework Baz.framework
diff --git a/unit-tests/test-cases/linker_options-framework-static-chain/bar.c b/unit-tests/test-cases/linker_options-framework-static-chain/bar.c
new file mode 100644 (file)
index 0000000..981110f
--- /dev/null
@@ -0,0 +1 @@
+void bar() { }
diff --git a/unit-tests/test-cases/linker_options-framework-static-chain/baz.c b/unit-tests/test-cases/linker_options-framework-static-chain/baz.c
new file mode 100644 (file)
index 0000000..a6dd5ab
--- /dev/null
@@ -0,0 +1 @@
+void baz() { }
diff --git a/unit-tests/test-cases/linker_options-framework-static-chain/foo.c b/unit-tests/test-cases/linker_options-framework-static-chain/foo.c
new file mode 100644 (file)
index 0000000..ab39b78
--- /dev/null
@@ -0,0 +1,8 @@
+
+extern void bar();
+extern void baz();
+
+void foo() {
+    bar();
+    baz();
+}
diff --git a/unit-tests/test-cases/linker_options-framework-static-chain/main.c b/unit-tests/test-cases/linker_options-framework-static-chain/main.c
new file mode 100644 (file)
index 0000000..4f56fe0
--- /dev/null
@@ -0,0 +1,8 @@
+
+extern void foo();
+
+int main()
+{
+       foo();
+       return 0;
+}
diff --git a/unit-tests/test-cases/linker_options-framework-static/Makefile b/unit-tests/test-cases/linker_options-framework-static/Makefile
new file mode 100644 (file)
index 0000000..9e01431
--- /dev/null
@@ -0,0 +1,45 @@
+##
+# Copyright (c) 2013 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check linker options work for -framework containing static archive
+#
+
+run: all
+
+all:
+       mkdir -p Foo.framework
+       ${CC} ${CCFLAGS} foo.c -c -o foo.o
+       libtool -static foo.o -o Foo.framework/Foo
+       ${CC} ${CCFLAGS} main.c -c -o main.o
+       ${LD} -r main.o -add_linker_option '-framework Foo' -o main2.o 
+       ${CC} ${CCFLAGS} main2.o -o main -F.
+       ${DYLDINFO} -export main | grep _foo | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -export main | grep _main | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+       rm -rf main foo.o main.o main2.o Foo.framework
+       
diff --git a/unit-tests/test-cases/linker_options-framework-static/foo.c b/unit-tests/test-cases/linker_options-framework-static/foo.c
new file mode 100644 (file)
index 0000000..e704870
--- /dev/null
@@ -0,0 +1,3 @@
+
+
+void foo() { }
diff --git a/unit-tests/test-cases/linker_options-framework-static/main.c b/unit-tests/test-cases/linker_options-framework-static/main.c
new file mode 100644 (file)
index 0000000..4f56fe0
--- /dev/null
@@ -0,0 +1,8 @@
+
+extern void foo();
+
+int main()
+{
+       foo();
+       return 0;
+}
diff --git a/unit-tests/test-cases/lto-duplicate_symbols/Makefile b/unit-tests/test-cases/lto-duplicate_symbols/Makefile
new file mode 100644 (file)
index 0000000..d8d3135
--- /dev/null
@@ -0,0 +1,46 @@
+##
+# Copyright (c) 2017 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# rdar://problem/35099885
+# Check that with ThinLTO linker can still distinguish between static and
+# non-static functions of the same name, and doesn't mix them up.
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} -flto=thin static.c -c -o static.o
+       ${CC} ${CCFLAGS} -flto=thin non-static.c -c -o non-static.o
+       ${CC} ${CCFLAGS} -flto=thin main.c -c -o main.o
+       # Option -flto-codegen-only is used to avoid LTO optimizations because they
+       # can rename a static function and thus prevent from testing how linker
+       # handles duplicate names.
+       ${CC} ${CCFLAGS} -flto=thin -Wl,-flto-codegen-only static.o non-static.o main.o -o main
+       ${FAIL_IF_BAD_MACHO} main
+       nm -j main | grep --count "^_same_name$$" | grep "^2$$" | ${PASS_IFF_STDIN}
+
+clean:
+       rm -rf main static.o non-static.o main.o
diff --git a/unit-tests/test-cases/lto-duplicate_symbols/main.c b/unit-tests/test-cases/lto-duplicate_symbols/main.c
new file mode 100644 (file)
index 0000000..699e024
--- /dev/null
@@ -0,0 +1,7 @@
+int same_name();
+int other();
+
+int main(void)
+{
+    return same_name() + other();
+}
diff --git a/unit-tests/test-cases/lto-duplicate_symbols/non-static.c b/unit-tests/test-cases/lto-duplicate_symbols/non-static.c
new file mode 100644 (file)
index 0000000..00039d7
--- /dev/null
@@ -0,0 +1,4 @@
+int same_name(void)
+{
+    return 32;
+}
diff --git a/unit-tests/test-cases/lto-duplicate_symbols/static.c b/unit-tests/test-cases/lto-duplicate_symbols/static.c
new file mode 100644 (file)
index 0000000..d40d247
--- /dev/null
@@ -0,0 +1,9 @@
+static int same_name(int i)
+{
+    return i + 10;
+}
+
+int other()
+{
+    return same_name(100);
+}