]> git.saurik.com Git - apple/ld64.git/blobdiff - src/ld/parsers/textstub_dylib_file.cpp
ld64-264.3.101.tar.gz
[apple/ld64.git] / src / ld / parsers / textstub_dylib_file.cpp
index cde33446b6c319e55dd07f6e9658f2d523a392ba..fb452d8b6fcb9590234b1fb2e2aebd1c216af69b 100644 (file)
@@ -32,6 +32,7 @@
 #include "bitcode.hpp"
 #include "MachOFileAbstraction.hpp"
 #include "MachOTrie.hpp"
+#include "generic_dylib_file.hpp"
 #include "textstub_dylib_file.hpp"
 
 namespace {
@@ -65,7 +66,7 @@ public:
 
        size_t size() const { return _size; }
 
-       std::string str() const { return std::move(std::string(_p, _size)); }
+       std::string str() const { return std::string(_p, _size); }
 
        bool empty() const { return _size == 0; }
 
@@ -195,33 +196,6 @@ struct DynamicLibrary {
                _objcConstraint(ld::File::objcConstraintNone)  {}
 };
 
-static uint32_t parseVersionNumber32(Token token) {
-       if ( token.size() >= 128 )
-               throwf("malformed version number");
-
-       char buffer[128];
-       uint32_t x = 0;
-       uint32_t y = 0;
-       uint32_t z = 0;
-       char* end;
-
-       // Make a null-terminated string.
-       ::memcpy(buffer, token.data(), token.size());
-       buffer[token.size()] = '\0';
-
-       x = strtoul(buffer, &end, 10);
-       if ( *end == '.' ) {
-               y = strtoul(&end[1], &end, 10);
-               if ( *end == '.' ) {
-                       z = strtoul(&end[1], &end, 10);
-               }
-       }
-       if ( (x > 0xffff) || (y > 0xff) || (z > 0xff) )
-               throwf("malformed 32-bit x.y.z version number: %s", buffer);
-
-       return (x << 16) | ( y << 8 ) | z;
-}
-
 ///
 /// A simple text-based dynamic library file parser.
 ///
@@ -310,16 +284,24 @@ class TBDFile {
                }
        }
 
-       bool parseArchFlowSequence(Token archName) {
+       std::vector<std::string> parseArchFlowSequence() {
+               std::vector<std::string> availabledArchitectures;
                expectToken("archs");
-
-               bool foundArch = false;
                parseFlowSequence([&](Token name) {
-                       if ( name == archName )
-                               foundArch = true;
-                       });
+                       availabledArchitectures.emplace_back(name.str());
+               });
+               return availabledArchitectures;
+       }
+
+       bool parseArchFlowSequence(std::string &selectedArchName) {
+               auto availabledArchitectures = parseArchFlowSequence();
 
-               return foundArch;
+               for (const auto &archName : availabledArchitectures) {
+                       if (archName == selectedArchName)
+                               return true;
+               }
+
+               return false;
        }
 
        void parsePlatform(DynamicLibrary& lib) {
@@ -348,6 +330,18 @@ class TBDFile {
                        throwf("no install name specified");
        }
 
+       uint32_t parseVersionNumber32(Token token) {
+               if ( token.size() >= 128 )
+                       throwf("malformed version number");
+
+               // Make a null-terminated string.
+               char buffer[128];
+               ::memcpy(buffer, token.data(), token.size());
+               buffer[token.size()] = '\0';
+
+               return Options::parseVersionNumber32(buffer);
+       }
+
        void parseCurrentVersion(DynamicLibrary& lib) {
                if ( !hasOptionalToken("current-version") )
                        return;
@@ -391,7 +385,7 @@ class TBDFile {
                else
                        throwf("unexpected token: %s", token.str().c_str());
        }
-       void parseExportsBlock(DynamicLibrary& lib, Token archName) {
+       void parseExportsBlock(DynamicLibrary& lib, std::string &selectedArchName) {
                if ( !hasOptionalToken("exports") )
                        return;
 
@@ -399,7 +393,7 @@ class TBDFile {
                        return;
 
                while ( true ) {
-                       if ( !parseArchFlowSequence(archName) ) {
+                       if ( !parseArchFlowSequence(selectedArchName) ) {
                                Token token;
                                while ( true ) {
                                        token = peek();
@@ -421,8 +415,47 @@ class TBDFile {
                }
        }
 
-       void parseDocument(DynamicLibrary& lib, Token archName) {
-               if ( !parseArchFlowSequence(archName) )
+       std::vector<std::string> getCompatibleArchList(std::string &requestedArchName) {
+               if (requestedArchName == "i386")
+                       return {"i386"};
+               else if (requestedArchName == "x86_64" || requestedArchName == "x86_64h")
+                       return {"x86_64", "x86_64h"};
+               else if (requestedArchName == "armv7" || requestedArchName == "armv7s")
+                       return {"armv7", "armv7s"};
+               else if (requestedArchName == "armv7k")
+                       return {"armv7k"};
+               else if (requestedArchName == "arm64")
+                       return {"arm64"};
+               else
+                       return {};
+       }
+
+       std::string parseAndSelectArchitecture(std::string &requestedArchName) {
+               auto availabledArchitectures = parseArchFlowSequence();
+
+               // First try to find an exact match (cpu type and sub-cpu type).
+               if (std::find(availabledArchitectures.begin(), availabledArchitectures.end(), requestedArchName)
+                       != availabledArchitectures.end())
+                       return requestedArchName;
+
+               // If there is no exact match, then try to find an ABI compatible slice.
+               auto compatibleArchitectures = getCompatibleArchList(requestedArchName);
+               std::vector<std::string> result;
+               std::sort(availabledArchitectures.begin(), availabledArchitectures.end());
+               std::sort(compatibleArchitectures.begin(), compatibleArchitectures.end());
+               std::set_intersection(availabledArchitectures.begin(), availabledArchitectures.end(),
+                                                         compatibleArchitectures.begin(), compatibleArchitectures.end(),
+                                                         std::back_inserter(result));
+
+               if (result.empty())
+                       return std::string();
+               else
+                       return result.front();
+       }
+
+       void parseDocument(DynamicLibrary& lib, std::string &requestedArchName) {
+               auto selectedArchName = parseAndSelectArchitecture(requestedArchName);
+               if (selectedArchName.empty())
                        throwf("invalid arch");
 
                parsePlatform(lib);
@@ -431,27 +464,27 @@ class TBDFile {
                parseCompatibilityVersion(lib);
                parseSwiftVersion(lib);
                parseObjCConstraint(lib);
-               parseExportsBlock(lib, archName);
+               parseExportsBlock(lib, selectedArchName);
        }
 
 public:
        TBDFile(const char* data, uint64_t size) : _tokenizer(data, size) {}
 
-       DynamicLibrary parseFileForArch(Token archName) {
+       DynamicLibrary parseFileForArch(std::string requestedArchName) {
                _tokenizer.reset();
                DynamicLibrary lib;
                expectToken("---");
-               parseDocument(lib, archName);
+               parseDocument(lib, requestedArchName);
                expectToken("...");
-               return std::move(lib);
+               return lib;
        }
 
-       bool validForArch(Token archName) {
+       bool validForArch(std::string requestedArchName) {
                _tokenizer.reset();
                auto token = next();
                if ( token != "---" )
                        return false;
-               return parseArchFlowSequence(archName);
+               return !parseAndSelectArchitecture(requestedArchName).empty();
        }
 
        void dumpTokens() {
@@ -469,52 +502,16 @@ public:
 namespace textstub {
 namespace dylib {
 
-// forward reference
-template <typename A> class File;
-
-
-//
-// An ExportAtom has no content.  It exists so that the linker can track which imported
-// symbols came from which dynamic libraries.
-//
-template <typename A>
-class ExportAtom : public ld::Atom
-{
-public:
-       ExportAtom(const File<A>& f, const char* nm, bool weakDef, bool tlv)
-               : ld::Atom(f._importProxySection, ld::Atom::definitionProxy,
-                                  (weakDef? ld::Atom::combineByName : ld::Atom::combineNever),
-                                  ld::Atom::scopeLinkageUnit,
-                                  (tlv ? ld::Atom::typeTLV : ld::Atom::typeUnclassified),
-                                  symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)),
-                                  _file(f), _name(nm) {}
-       // overrides of ld::Atom
-       virtual const ld::File*                 file() const            { return &_file; }
-       virtual const char*                             name() const            { return _name; }
-       virtual uint64_t                                size() const            { return 0; }
-       virtual uint64_t                                objectAddress() const { return 0; }
-       virtual void                                    copyRawContent(uint8_t buffer[]) const { }
-       virtual void                                    setScope(Scope)         { }
-
-protected:
-       typedef typename A::P                   P;
-       typedef typename A::P::uint_t   pint_t;
-
-       virtual                                                 ~ExportAtom() {}
-
-       const File<A>&                                  _file;
-       const char*                                             _name;
-};
-
-
 //
 // The reader for a dylib extracts all exported symbols names from the memory-mapped
 // dylib, builds a hash table, then unmaps the file.  This is an important memory
 // savings for large dylibs.
 //
 template <typename A>
-class File : public ld::dylib::File
+class File final : public generic::dylib::File<A>
 {
+       using Base = generic::dylib::File<A>;
+
 public:
        static bool             validFile(const uint8_t* fileContent, bool executableOrDylib);
                                        File(const uint8_t* fileContent, uint64_t fileLength, const char* path,
@@ -523,91 +520,13 @@ public:
                                                 cpu_type_t cpuType, const char* archName, uint32_t linkMinOSVersion,
                                                 bool allowSimToMacOSX, bool addVers, bool buildingForSimulator,
                                                 bool logAllFiles, const char* installPath, bool indirectDylib);
-       virtual                 ~File() {}
-
-       // overrides of ld::File
-       virtual bool                                                    forEachAtom(ld::File::AtomHandler&) const;
-       virtual bool                                                    justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const;
-       virtual ld::File::ObjcConstraint                objCConstraint() const          { return _objcConstraint; }
-       virtual uint8_t                                                 swiftVersion() const            { return _swiftVersion; }
-
-       // overrides of ld::dylib::File
-       virtual void                                                    processIndirectLibraries(ld::dylib::File::DylibHandler*, bool);
-       virtual bool                                                    providedExportAtom() const      { return _providedAtom; }
-       virtual const char*                                             parentUmbrella() const { return nullptr; }
-       virtual const std::vector<const char*>* allowableClients() const        { return _allowableClients.size() != 0 ? &_allowableClients : nullptr; }
-       virtual bool                                                    hasWeakExternals() const        { return _hasWeakExports; }
-       virtual bool                                                    deadStrippable() const          { return false; }
-       virtual bool                                                    hasPublicInstallName() const{ return _hasPublicInstallName; }
-       virtual bool                                                    hasWeakDefinition(const char* name) const;
-       virtual bool                                                    allSymbolsAreWeakImported() const;
-       virtual bool                                                    installPathVersionSpecific() const { return _installPathOverride; }
-       // All text-based stubs are per definition AppExtensionSafe.
-       virtual bool                                                    appExtensionSafe() const        { return true; };
-       virtual ld::Bitcode*                                    getBitcode() const                      { return _bitcode.get(); }
-
-
-protected:
-       virtual void                                                    assertNoReExportCycles(ReExportChain*) const;
+       virtual                 ~File() noexcept {}
 
 private:
-       typedef typename A::P                                   P;
-       typedef typename A::P::E                                E;
-       typedef typename A::P::uint_t                   pint_t;
-
-       friend class ExportAtom<A>;
-
-       struct CStringHash {
-               std::size_t operator()(const char* __s) const {
-                       unsigned long __h = 0;
-                       for ( ; *__s; ++__s)
-                               __h = 5 * __h + *__s;
-                       return size_t(__h);
-               };
-       };
-       struct AtomAndWeak { ld::Atom* atom; bool weakDef; bool tlv; };
-       typedef std::unordered_map<const char*, AtomAndWeak, ld::CStringHash, ld::CStringEquals> NameToAtomMap;
-       typedef std::unordered_set<const char*, CStringHash, ld::CStringEquals>  NameSet;
-
-       struct Dependent { const char* path; File<A>* dylib; };
-
-       virtual std::pair<bool, bool>                   hasWeakDefinitionImpl(const char* name) const;
-       virtual bool                                                    containsOrReExports(const char* name, bool& weakDef, bool& tlv, uint64_t& address) const;
-
-       void                                                                    buildExportHashTable(const DynamicLibrary &lib);
-       bool                                                                    isPublicLocation(const char* pth);
-       bool                                                                    wrongOS() { return _wrongOS; }
-       void                                                                    addSymbol(const char* name, bool weak, bool tlv);
-
-       const Options::Platform                                 _platform;
-       cpu_type_t                                                              _cpuType;
-       const uint32_t                                                  _linkMinOSVersion;
-       const bool                                                              _allowSimToMacOSXLinking;
-       const bool                                                              _addVersionLoadCommand;
-       bool                                                                    _linkingFlat;
-       bool                                                                    _implicitlyLinkPublicDylibs;
-       ld::File::ObjcConstraint                                _objcConstraint;
-       uint8_t                                                                 _swiftVersion;
-       ld::Section                                                             _importProxySection;
-       ld::Section                                                             _flatDummySection;
-       std::vector<Dependent>                                  _dependentDylibs;
-       std::vector<const char*>                                _allowableClients;
-       mutable NameToAtomMap                                   _atoms;
-       NameSet                                                                 _ignoreExports;
-       bool                                                                    _noRexports;
-       bool                                                                    _hasWeakExports;
-       bool                                                                    _hasPublicInstallName;
-       mutable bool                                                    _providedAtom;
-       bool                                                                    _wrongOS;
-       bool                                                                    _installPathOverride;
-       bool                                                                    _indirectDylibsProcessed;
-       std::unique_ptr<ld::Bitcode>                    _bitcode;
-       static bool                                                             _s_logHashtable;
-};
-
-template <typename A>
-bool File<A>::_s_logHashtable = false;
+       void                    buildExportHashTable(const DynamicLibrary &lib);
 
+       cpu_type_t              _cpuType;
+};
 
 template <typename A>
 File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t mTime,
@@ -616,18 +535,14 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* path,
                          uint32_t linkMinOSVersion, bool allowSimToMacOSX, bool addVers,
                          bool buildingForSimulator, bool logAllFiles, const char* targetInstallPath,
                          bool indirectDylib)
-       : ld::dylib::File(strdup(path), mTime, ord), _platform(platform), _cpuType(cpuType),
-         _linkMinOSVersion(linkMinOSVersion), _allowSimToMacOSXLinking(allowSimToMacOSX),
-         _addVersionLoadCommand(addVers), _linkingFlat(linkingFlatNamespace),
-         _implicitlyLinkPublicDylibs(hoistImplicitPublicDylibs),
-         _objcConstraint(ld::File::objcConstraintNone), _swiftVersion(0),
-         _importProxySection("__TEXT", "__import", ld::Section::typeImportProxies, true),
-         _flatDummySection("__LINKEDIT", "__flat_dummy", ld::Section::typeLinkEdit, true),
-         _noRexports(false), _hasWeakExports(false),
-         _hasPublicInstallName(false), _providedAtom(false), _wrongOS(false),
-         _installPathOverride(false), _indirectDylibsProcessed(false),
-         _bitcode(new ld::Bitcode(nullptr, 0))
+       : Base(strdup(path), mTime, ord, platform, linkMinOSVersion, linkingFlatNamespace,
+                  hoistImplicitPublicDylibs, allowSimToMacOSX, addVers),
+         _cpuType(cpuType)
 {
+       this->_bitcode = std::unique_ptr<ld::Bitcode>(new ld::Bitcode(nullptr, 0));
+       // Text stubs are implicit app extension safe.
+       this->_appExtensionSafe = true;
+
        // write out path for -t option
        if ( logAllFiles )
                printf("%s\n", path);
@@ -635,27 +550,66 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* path,
        TBDFile stub((const char*)fileContent, fileLength);
        auto lib = stub.parseFileForArch(archName);
 
-       _noRexports = lib._reexportedLibraries.empty();
-       _hasWeakExports = !lib._weakDefSymbols.empty();
-       _dylibInstallPath = strdup(lib._installName.str().c_str());
-       _dylibCurrentVersion = lib._currentVersion;
-       _dylibCompatibilityVersion = lib._compatibilityVersion;
-       _swiftVersion = lib._swiftVersion;
-       _objcConstraint = lib._objcConstraint;
-       _hasPublicInstallName = isPublicLocation(_dylibInstallPath);
-
-       for (auto &client : lib._allowedClients)
-               _allowableClients.push_back(strdup(client.str().c_str()));
+       this->_noRexports = lib._reexportedLibraries.empty();
+       this->_hasWeakExports = !lib._weakDefSymbols.empty();
+       this->_dylibInstallPath = strdup(lib._installName.str().c_str());
+       this->_dylibCurrentVersion = lib._currentVersion;
+       this->_dylibCompatibilityVersion = lib._compatibilityVersion;
+       this->_swiftVersion = lib._swiftVersion;
+       this->_objcConstraint = lib._objcConstraint;
+       this->_hasPublicInstallName = this->isPublicLocation(this->_dylibInstallPath);
+
+       // if framework, capture framework name
+       const char* lastSlash = strrchr(this->_dylibInstallPath, '/');
+       if ( lastSlash != NULL ) {
+               const char* leafName = lastSlash+1;
+               char frname[strlen(leafName)+32];
+               strcpy(frname, leafName);
+               strcat(frname, ".framework/");
+
+               if ( strstr(this->_dylibInstallPath, frname) != NULL )
+                       this->_frameworkName = leafName;
+       }
+
+  // TEMPORARY HACK BEGIN: Support ancient re-export command LC_SUB_FRAMEWORK.
+       // <rdar://problem/23614899> [TAPI] Support LC_SUB_FRAMEWORK as re-export indicator.
+       auto installName = std::string(this->_dylibInstallPath);
+
+       // All sub-frameworks of ApplicationServices use LC_SUB_FRAMEWORK.
+       if (installName.find("/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/") == 0 &&
+                       installName.find(".dylib") == std::string::npos) {
+               this->_parentUmbrella = "ApplicationServices";
+       } else if (installName.find("/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/") == 0) {
+               this->_parentUmbrella = "Carbon";
+       } else if (installName.find("/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/") == 0 &&
+                                        installName.find(".dylib") == std::string::npos) {
+               this->_parentUmbrella = "CoreServices";
+       } else if (installName.find("/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLinearAlgebra.dylib") == 0 ||
+                                        installName.find("/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libQuadrature.dylib") == 0 ||
+                                        installName.find("System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libSparseBLAS.dylib") == 0) {
+               this->_parentUmbrella = "vecLib";
+       } else if (installName.find("/System/Library/Frameworks/WebKit.framework/Versions/A/Frameworks/WebCore.framework/Versions/A/WebCore") == 0) {
+               this->_parentUmbrella = "WebKit";
+       } else if (installName.find("/usr/lib/system/") == 0 &&
+                          installName != "/usr/lib/system/libkxld.dylib") {
+               this->_parentUmbrella = "System";
+       }
+       // TEMPORARY HACK END
+
+       for (auto &client : lib._allowedClients) {
+               if ((this->_parentUmbrella != nullptr) && (client.str() != this->_parentUmbrella))
+                       this->_allowableClients.push_back(strdup(client.str().c_str()));
+       }
 
        // <rdar://problem/20659505> [TAPI] Don't hoist "public" (in /usr/lib/) dylibs that should not be directly linked
-       if ( !_allowableClients.empty() )
-               _hasPublicInstallName = false;
+       if ( !this->_allowableClients.empty() )
+               this->_hasPublicInstallName = false;
 
        if ( (lib._platform != platform) && (platform != Options::kPlatformUnknown) ) {
-               _wrongOS = true;
-               if ( _addVersionLoadCommand && !indirectDylib ) {
+               this->_wrongOS = true;
+               if ( this->_addVersionLoadCommand && !indirectDylib ) {
                        if ( buildingForSimulator ) {
-                               if ( !_allowSimToMacOSXLinking )
+                               if ( !this->_allowSimToMacOSXLinking )
                                        throwf("building for %s simulator, but linking against dylib built for %s (%s).",
                                                        Options::platformName(platform), Options::platformName(lib._platform), path);
                        } else {
@@ -665,13 +619,11 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* path,
                }
        }
 
-       _dependentDylibs.reserve(lib._reexportedLibraries.size());
-       for ( auto& reexport : lib._reexportedLibraries ) {
-               Dependent entry;
-               entry.path = strdup(reexport.str().c_str());
-               entry.dylib = nullptr;
-               if ( (targetInstallPath == nullptr) || (strcmp(targetInstallPath, entry.path) != 0) )
-                       _dependentDylibs.push_back(entry);
+       this->_dependentDylibs.reserve(lib._reexportedLibraries.size());
+       for ( const auto& reexport : lib._reexportedLibraries ) {
+               const char *path = strdup(reexport.str().c_str());
+               if ( (targetInstallPath == nullptr) || (strcmp(targetInstallPath, path) != 0) )
+                       this->_dependentDylibs.emplace_back(path, true);
        }
 
        // build hash table
@@ -682,324 +634,51 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* path,
 
 template <typename A>
 void File<A>::buildExportHashTable(const DynamicLibrary& lib) {
-       if ( _s_logHashtable )
+       if (this->_s_logHashtable )
                fprintf(stderr, "ld: building hashtable from text-stub info in %s\n", this->path());
 
        for (auto &sym : lib._symbols)
-               addSymbol(sym.str().c_str(), /*weak=*/false, /*tlv=*/false);
+               this->addSymbol(sym.str().c_str());
 
 #if SUPPORT_ARCH_i386
-       if (_platform == Options::kPlatformOSX && _cpuType == CPU_TYPE_I386) {
+       if (this->_platform == Options::kPlatformOSX && _cpuType == CPU_TYPE_I386) {
                for (auto &sym : lib._classes)
-                       addSymbol((".objc_class_name" + sym.str()).c_str(), /*weak=*/false, /*tlv=*/false);
+                       this->addSymbol((".objc_class_name" + sym.str()).c_str());
        } else {
                for (auto &sym : lib._classes) {
-                       addSymbol(("_OBJC_CLASS_$" + sym.str()).c_str(), /*weak=*/false, /*tlv=*/false);
-                       addSymbol(("_OBJC_METACLASS_$" + sym.str()).c_str(), /*weak=*/false, /*tlv=*/false);
+                       this->addSymbol(("_OBJC_CLASS_$" + sym.str()).c_str());
+                       this->addSymbol(("_OBJC_METACLASS_$" + sym.str()).c_str());
                }
        }
 #else
        for (auto &sym : lib._classes) {
-               addSymbol(("_OBJC_CLASS_$" + sym.str()).c_str(), /*weak=*/false, /*tlv=*/false);
-               addSymbol(("_OBJC_METACLASS_$" + sym.str()).c_str(), /*weak=*/false, /*tlv=*/false);
+               this->addSymbol(("_OBJC_CLASS_$" + sym.str()).c_str());
+               this->addSymbol(("_OBJC_METACLASS_$" + sym.str()).c_str());
        }
 #endif
 
        for (auto &sym : lib._ivars)
-               addSymbol(("_OBJC_IVAR_$" + sym.str()).c_str(), /*weak=*/false, /*tlv=*/false);
+               this->addSymbol(("_OBJC_IVAR_$" + sym.str()).c_str());
 
        for (auto &sym : lib._weakDefSymbols)
-               addSymbol(sym.str().c_str(), /*weak=*/true, /*tlv=*/false);
+               this->addSymbol(sym.str().c_str(), /*weak=*/true);
 
        for (auto &sym : lib._tlvSymbols)
-               addSymbol(sym.str().c_str(), /*weak=*/false, /*tlv=*/true);
-}
-
-
-template <typename A>
-void File<A>::addSymbol(const char* name, bool weakDef, bool tlv)
-{
-       // symbols that start with $ld$ are meta-data to the static linker
-       // <rdar://problem/5182537> need way for ld and dyld to see different exported symbols in a dylib
-       if ( strncmp(name, "$ld$", 4) == 0 ) {
-               //    $ld$ <action> $ <condition> $ <symbol-name>
-               const char* symAction = &name[4];
-               const char* symCond = strchr(symAction, '$');
-               if ( symCond != nullptr ) {
-                       char curOSVers[16];
-                       sprintf(curOSVers, "$os%d.%d$", (_linkMinOSVersion >> 16), ((_linkMinOSVersion >> 8) & 0xFF));
-                       if ( strncmp(symCond, curOSVers, strlen(curOSVers)) == 0 ) {
-                               const char* symName = strchr(&symCond[1], '$');
-                               if ( symName != nullptr ) {
-                                       ++symName;
-                                       if ( strncmp(symAction, "hide$", 5) == 0 ) {
-                                               if ( _s_logHashtable )
-                                                       fprintf(stderr, "  adding %s to ignore set for %s\n", symName, this->path());
-                                               _ignoreExports.insert(strdup(symName));
-                                               return;
-                                       }
-                                       else if ( strncmp(symAction, "add$", 4) == 0 ) {
-                                               this->addSymbol(symName, weakDef, false);
-                                               return;
-                                       }
-                                       else if ( strncmp(symAction, "install_name$", 13) == 0 ) {
-                                               _dylibInstallPath = strdup(symName);
-                                               _installPathOverride = true;
-                                               return;
-                                       }
-                                       else if ( strncmp(symAction, "compatibility_version$", 22) == 0 ) {
-                                               _dylibCompatibilityVersion = parseVersionNumber32(symName);
-                                               return;
-                                       }
-                                       else {
-                                               warning("bad symbol action: %s in dylib %s", name, this->path());
-                                       }
-                               }
-                       }
-               }
-               else {
-                       warning("bad symbol condition: %s in dylib %s", name, this->path());
-               }
-       }
-
-       // add symbol as possible export if we are not supposed to ignore it
-       if ( _ignoreExports.count(name) == 0 ) {
-               AtomAndWeak bucket;
-               bucket.atom = nullptr;
-               bucket.weakDef = weakDef;
-               bucket.tlv = tlv;
-               if ( _s_logHashtable )
-                       fprintf(stderr, "  adding %s to hash table for %s\n", name, this->path());
-               _atoms[strdup(name)] = bucket;
-       }
-}
-
-
-template <typename A>
-bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
-{
-       handler.doFile(*this);
-       return false;
-}
-
-
-template <typename A>
-std::pair<bool, bool> File<A>::hasWeakDefinitionImpl(const char* name) const
-{
-       const auto pos = _atoms.find(name);
-       if ( pos != _atoms.end() )
-               return std::make_pair(true, pos->second.weakDef);
-
-       // look in children that I re-export
-       for (const auto &dep : _dependentDylibs) {
-               auto ret = dep.dylib->hasWeakDefinitionImpl(name);
-               if ( ret.first )
-                       return ret;
-       }
-       return std::make_pair(false, false);
-}
-
-
-template <typename A>
-bool File<A>::hasWeakDefinition(const char* name) const
-{
-       // if supposed to ignore this export, then pretend I don't have it
-       if ( _ignoreExports.count(name) != 0 )
-               return false;
-
-       return hasWeakDefinitionImpl(name).second;
-}
-
-
-// <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
-template <typename A>
-bool File<A>::allSymbolsAreWeakImported() const
-{
-       bool foundNonWeakImport = false;
-       bool foundWeakImport = false;
-       for (const auto &it : _atoms) {
-               const ld::Atom* atom = it.second.atom;
-               if ( atom != nullptr ) {
-                       if ( atom->weakImported() )
-                               foundWeakImport = true;
-                       else
-                               foundNonWeakImport = true;
-               }
-       }
-
-       // don't automatically weak link dylib with no imports
-       // so at least one weak import symbol and no non-weak-imported symbols must be found
-       return foundWeakImport && !foundNonWeakImport;
-}
-
-
-template <typename A>
-bool File<A>::containsOrReExports(const char* name, bool& weakDef, bool& tlv, uint64_t& addr) const
-{
-       if ( _ignoreExports.count(name) != 0 )
-               return false;
-
-       // check myself
-       const auto pos = _atoms.find(name);
-       if ( pos != _atoms.end() ) {
-               weakDef = pos->second.weakDef;
-               tlv = pos->second.tlv;
-               addr = 0;
-               return true;
-       }
-
-       // check dylibs I re-export
-       for (const auto& lib : _dependentDylibs) {
-               if ( !lib.dylib->implicitlyLinked() ) {
-                       if ( lib.dylib->containsOrReExports(name, weakDef, tlv, addr) )
-                               return true;
-               }
-       }
-
-       return false;
-}
-
-
-template <typename A>
-bool File<A>::justInTimeforEachAtom(const char* name, ld::File::AtomHandler& handler) const
-{
-       // if supposed to ignore this export, then pretend I don't have it
-       if ( _ignoreExports.count(name) != 0 )
-               return false;
-
-
-       AtomAndWeak bucket;
-       uint64_t addr;
-       if ( this->containsOrReExports(name, bucket.weakDef, bucket.tlv, addr) ) {
-               bucket.atom = new ExportAtom<A>(*this, name, bucket.weakDef, bucket.tlv);
-               _atoms[name] = bucket;
-               _providedAtom = true;
-               if ( _s_logHashtable )
-                       fprintf(stderr, "getJustInTimeAtomsFor: %s found in %s\n", name, this->path());
-               // call handler with new export atom
-               handler.doAtom(*bucket.atom);
-               return true;
-       }
-
-       return false;
-}
-
-
-
-template <typename A>
-bool File<A>::isPublicLocation(const char* path)
-{
-       // -no_implicit_dylibs disables this optimization
-       if ( ! _implicitlyLinkPublicDylibs )
-               return false;
-
-       // /usr/lib is a public location
-       if ( (strncmp(path, "/usr/lib/", 9) == 0) && (strchr(&path[9], '/') == nullptr) )
-               return true;
-
-       // /System/Library/Frameworks/ is a public location
-       if ( strncmp(path, "/System/Library/Frameworks/", 27) == 0 ) {
-               const char* frameworkDot = strchr(&path[27], '.');
-               // but only top level framework
-               // /System/Library/Frameworks/Foo.framework/Versions/A/Foo                 ==> true
-               // /System/Library/Frameworks/Foo.framework/Resources/libBar.dylib         ==> false
-               // /System/Library/Frameworks/Foo.framework/Frameworks/Bar.framework/Bar   ==> false
-               // /System/Library/Frameworks/Foo.framework/Frameworks/Xfoo.framework/XFoo ==> false
-               if ( frameworkDot != nullptr ) {
-                       int frameworkNameLen = frameworkDot - &path[27];
-                       if ( strncmp(&path[strlen(path)-frameworkNameLen-1], &path[26], frameworkNameLen+1) == 0 )
-                               return true;
-               }
-       }
-
-       return false;
-}
-
-template <typename A>
-void File<A>::processIndirectLibraries(ld::dylib::File::DylibHandler* handler, bool addImplicitDylibs)
-{
-       // only do this once
-       if ( _indirectDylibsProcessed )
-               return;
-
-       const static bool log = false;
-       if ( log ) fprintf(stderr, "processIndirectLibraries(%s)\n", this->installPath());
-       if ( _linkingFlat ) {
-               for (auto& lib : _dependentDylibs) {
-                       lib.dylib = (File<A>*)handler->findDylib(lib.path, this->path());
-               }
-       }
-       else if ( _noRexports ) {
-               // MH_NO_REEXPORTED_DYLIBS bit set, then nothing to do
-       }
-       else {
-               // two-level, might have re-exports
-               for (auto& lib : _dependentDylibs) {
-                       if ( log )
-                               fprintf(stderr, "processIndirectLibraries() parent=%s, child=%s\n", this->installPath(), lib.path);
-                       // a LC_REEXPORT_DYLIB, LC_SUB_UMBRELLA or LC_SUB_LIBRARY says we re-export this child
-                       lib.dylib = (File<A>*)handler->findDylib(lib.path, this->path());
-                       if ( lib.dylib->hasPublicInstallName() && !lib.dylib->wrongOS() ) {
-                               // promote this child to be automatically added as a direct dependent if this already is
-                               if ( (this->explicitlyLinked() || this->implicitlyLinked()) && (strcmp(lib.path, lib.dylib->installPath()) == 0) ) {
-                                       if ( log )
-                                               fprintf(stderr, "processIndirectLibraries() implicitly linking %s\n", lib.dylib->installPath());
-                                       lib.dylib->setImplicitlyLinked();
-                               }
-                               else if ( lib.dylib->explicitlyLinked() || lib.dylib->implicitlyLinked() ) {
-                                       if ( log )
-                                               fprintf(stderr, "processIndirectLibraries() parent is not directly linked, but child is, so no need to re-export child\n");
-                               } else {
-                                       if ( log )
-                                               fprintf(stderr, "processIndirectLibraries() parent is not directly linked, so parent=%s will re-export child=%s\n", this->installPath(), lib.path);
-                               }
-                       } else {
-                               // add all child's symbols to me
-                               if ( log )
-                                       fprintf(stderr, "processIndirectLibraries() child is not public, so parent=%s will re-export child=%s\n", this->installPath(), lib.path);
-                       }
-               }
-       }
-
-       // check for re-export cycles
-       ReExportChain chain;
-       chain.prev = nullptr;
-       chain.file = this;
-       this->assertNoReExportCycles(&chain);
-
-       _indirectDylibsProcessed = true;
+               this->addSymbol(sym.str().c_str(), /*weak=*/false, /*tlv=*/true);
 }
 
-template <typename A>
-void File<A>::assertNoReExportCycles(ReExportChain* prev) const
-{
-       // recursively check my re-exported dylibs
-       ReExportChain chain;
-       chain.prev = prev;
-       chain.file = this;
-       for (const auto& dep : _dependentDylibs) {
-               ld::File* child = dep.dylib;
-               // check child is not already in chain
-               for (ReExportChain* p = prev; p != nullptr; p = p->prev) {
-                       if ( p->file == child )
-                               throwf("cycle in dylib re-exports with %s and %s", child->path(), this->path());
-               }
-               if ( dep.dylib != nullptr )
-                       dep.dylib->assertNoReExportCycles(&chain);
-       }
-}
-
-
 template <typename A>
 class Parser
 {
 public:
-       typedef typename A::P   P;
+       using P = typename A::P;
 
-       static bool                             validFile(const uint8_t* fileContent, uint64_t fileLength, const std::string &path, const char* archName);
+       static bool                             validFile(const uint8_t* fileContent, uint64_t fileLength,
+                                                                         const std::string &path, const char* archName);
        static ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path,
                                                                  time_t mTime, ld::File::Ordinal ordinal, const Options& opts,
-                                                                 bool indirectDylib) {
+                                                                 bool indirectDylib)
+       {
                return new File<A>(fileContent, fileLength, path, mTime, ordinal,
                                                   opts.flatNamespace(),
                                                   opts.implicitlyLinkIndirectPublicDylibs(),
@@ -1017,7 +696,8 @@ public:
 };
 
 template <typename A>
-bool Parser<A>::validFile(const uint8_t* fileContent, uint64_t fileLength, const std::string &path, const char* archName)
+bool Parser<A>::validFile(const uint8_t* fileContent, uint64_t fileLength, const std::string &path,
+                                                 const char* archName)
 {
        if ( path.find(".tbd", path.size()-4) == std::string::npos )
                return false;
@@ -1068,5 +748,3 @@ ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, const ch
        
 } // namespace dylib
 } // namespace textstub
-
-