#include "bitcode.hpp"
#include "MachOFileAbstraction.hpp"
#include "MachOTrie.hpp"
+#include "generic_dylib_file.hpp"
#include "textstub_dylib_file.hpp"
namespace {
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; }
_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.
///
}
}
- 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) {
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;
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;
return;
while ( true ) {
- if ( !parseArchFlowSequence(archName) ) {
+ if ( !parseArchFlowSequence(selectedArchName) ) {
Token token;
while ( true ) {
token = peek();
}
}
- 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);
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() {
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,
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,
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);
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 {
}
}
- _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
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(),
};
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;
} // namespace dylib
} // namespace textstub
-
-