#include <sys/param.h>
#include <sys/mman.h>
-
+#include <tapi/tapi.h>
#include <vector>
#include "Architectures.hpp"
#include "generic_dylib_file.hpp"
#include "textstub_dylib_file.hpp"
-namespace {
-
-///
-/// A token is a light-weight reference to the content of an nmap'ed file. It
-/// doesn't own the data and it doesn't make a copy of it. The referenced data
-/// is only valid as long as the file is mapped in.
-///
-class Token {
- const char* _p;
- size_t _size;
-
- int compareMemory(const char* lhs, const char* rhs, size_t size) const {
- if (size == 0)
- return 0;
- return ::memcmp(lhs, rhs, size);
- }
-
-public:
- Token() : _p(nullptr), _size(0) {}
-
- Token(const char* p) : _p(p), _size(0) {
- if (p)
- _size = ::strlen(p);
- }
-
- Token(const char* p, size_t s) : _p(p), _size(s) {}
-
- const char* data() const { return _p; }
-
- size_t size() const { return _size; }
-
- std::string str() const { return std::string(_p, _size); }
-
- bool empty() const { return _size == 0; }
-
- bool operator==(Token other) const {
- if (_size != other._size)
- return false;
- return compareMemory(_p, other._p, _size) == 0;
- }
-
- bool operator!=(Token other) const {
- return !(*this == other);
- }
-};
-
-///
-/// Simple text-based dynamic library file tokenizer.
-///
-class Tokenizer {
- const char* _start;
- const char* _current;
- const char* _end;
- Token _currentToken;
-
- void fetchNextToken();
- void scanToNextToken();
- void skip(unsigned distance) {
- _current += distance;
- assert(_current <= _end && "Skipped past the end");
- }
-
- const char* skipLineBreak(const char* pos) const;
- bool isDelimiter(const char* pos) const;
-
-public:
- Tokenizer(const char* data, uint64_t size) : _start(data), _current(data), _end(data + size) {}
-
- void reset() {
- _current = _start;
- fetchNextToken();
- }
-
- Token peek() { return _currentToken; }
- Token next() {
- Token token = peek();
- fetchNextToken();
- return token;
- }
-};
-
-const char* Tokenizer::skipLineBreak(const char* pos) const
-{
- if ( pos == _end )
- return pos;
-
- // Carriage return.
- if ( *pos == 0x0D ) {
- // line feed.
- if ( pos + 1 != _end && *(pos + 1) == 0x0A)
- return pos + 2;
- return pos + 1;
- }
-
- // line feed.
- if ( *pos == 0x0A )
- return pos + 1;
-
- return pos;
-}
-
-void Tokenizer::scanToNextToken() {
- while (true) {
- while ( isDelimiter(_current) )
- skip(1);
-
- const char* i = skipLineBreak(_current);
- if ( i == _current )
- break;
-
- _current = i;
- }
-}
-
-
-bool Tokenizer::isDelimiter(const char* pos) const {
- if ( pos == _end )
- return false;
- if ( *pos == ' ' || *pos == '\t' || *pos == '\r' || *pos == '\n' || *pos == ',' || *pos == ':' || *pos == '\'' || *pos == '\"' )
- return true;
- return false;
-}
-
-void Tokenizer::fetchNextToken() {
- scanToNextToken();
-
- if (_current == _end) {
- _currentToken = Token();
- return;
- }
-
- auto start = _current;
- while ( !isDelimiter(_current) ) {
- ++_current;
- }
-
- _currentToken = Token(start, _current - start);
-}
-
-///
-/// Representation of a parsed text-based dynamic library file.
-///
-struct DynamicLibrary {
- Token _installName;
- uint32_t _currentVersion;
- uint32_t _compatibilityVersion;
- uint8_t _swiftVersion;
- ld::File::ObjcConstraint _objcConstraint;
- Options::Platform _platform;
- std::vector<Token> _allowedClients;
- std::vector<Token> _reexportedLibraries;
- std::vector<Token> _symbols;
- std::vector<Token> _classes;
- std::vector<Token> _ivars;
- std::vector<Token> _weakDefSymbols;
- std::vector<Token> _tlvSymbols;
-
- DynamicLibrary() : _currentVersion(0x10000), _compatibilityVersion(0x10000), _swiftVersion(0),
- _objcConstraint(ld::File::objcConstraintNone) {}
-};
-
-///
-/// A simple text-based dynamic library file parser.
-///
-class TBDFile {
- Tokenizer _tokenizer;
-
- Token peek() { return _tokenizer.peek(); }
- Token next() { return _tokenizer.next(); }
-
- void expectToken(Token str) {
- Token token = next();
- if (token != str)
- throwf("unexpected token: %s", token.str().c_str());
- }
-
- bool hasOptionalToken(Token str) {
- auto token = peek();
- if ( token == str ) {
- next();
- return true;
- }
- return false;
- }
-
-
- void parseFlowSequence(std::function<void (Token)> func) {
- expectToken("[");
-
- while ( true ) {
- auto token = peek();
- if ( token == "]" )
- break;
-
- token = next();
- func(token);
- }
-
- expectToken("]");
- }
-
- void parseAllowedClients(DynamicLibrary& lib) {
- if ( !hasOptionalToken("allowed-clients") )
- return;
- parseFlowSequence([&](Token name) {
- lib._allowedClients.emplace_back(name);
- });
- }
-
- void parseReexportedDylibs(DynamicLibrary& lib) {
- if ( !hasOptionalToken("re-exports") )
- return;
- parseFlowSequence([&](Token name) {
- lib._reexportedLibraries.emplace_back(name);
- });
- }
-
- void parseSymbols(DynamicLibrary& lib) {
- if ( hasOptionalToken("symbols") ) {
- parseFlowSequence([&](Token name) {
- lib._symbols.emplace_back(name);
- });
- }
-
- if ( hasOptionalToken("objc-classes") ) {
- parseFlowSequence([&](Token name) {
- lib._classes.emplace_back(name);
- });
- }
-
- if ( hasOptionalToken("objc-ivars") ) {
- parseFlowSequence([&](Token name) {
- lib._ivars.emplace_back(name);
- });
- }
-
- if ( hasOptionalToken("weak-def-symbols") ) {
- parseFlowSequence([&](Token name) {
- lib._weakDefSymbols.emplace_back(name);
- });
- }
-
- if ( hasOptionalToken("thread-local-symbols") ) {
- parseFlowSequence([&](Token name) {
- lib._tlvSymbols.emplace_back(name);
- });
- }
- }
-
- std::vector<std::string> parseArchFlowSequence() {
- std::vector<std::string> availabledArchitectures;
- expectToken("archs");
- parseFlowSequence([&](Token name) {
- availabledArchitectures.emplace_back(name.str());
- });
- return availabledArchitectures;
- }
-
- bool parseArchFlowSequence(std::string &selectedArchName) {
- auto availabledArchitectures = parseArchFlowSequence();
-
- for (const auto &archName : availabledArchitectures) {
- if (archName == selectedArchName)
- return true;
- }
-
- return false;
- }
-
- void parsePlatform(DynamicLibrary& lib) {
- expectToken("platform");
-
- auto token = next();
- if (token == "macosx")
- lib._platform = Options::kPlatformOSX;
- else if (token == "ios")
- lib._platform = Options::kPlatformiOS;
- else if (token == "watchos")
- lib._platform = Options::kPlatformWatchOS;
-#if SUPPORT_APPLE_TV
- else if (token == "tvos")
- lib._platform = Options::kPlatform_tvOS;
-#endif
- else
- lib._platform = Options::kPlatformUnknown;
- }
-
- void parseInstallName(DynamicLibrary& lib) {
- expectToken("install-name");
-
- lib._installName = next();
- if ( lib._installName.empty() )
- 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;
- lib._currentVersion = parseVersionNumber32(next());
- }
-
- void parseCompatibilityVersion(DynamicLibrary& lib) {
- if ( !hasOptionalToken("compatibility-version") )
- return;
- lib._compatibilityVersion = parseVersionNumber32(next());
- }
-
- void parseSwiftVersion(DynamicLibrary& lib) {
- if ( !hasOptionalToken("swift-version") )
- return;
- auto token = next();
- if ( token == "1.0" )
- lib._swiftVersion = 1;
- else if ( token == "1.1" )
- lib._swiftVersion = 2;
- else if ( token == "2.0" )
- lib._swiftVersion = 3;
- else
- throwf("unsupported Swift ABI version: %s", token.str().c_str());
- }
-
- void parseObjCConstraint(DynamicLibrary& lib) {
- if ( !hasOptionalToken("objc-constraint") )
- return;
- auto token = next();
- if ( token == "none" )
- lib._objcConstraint = ld::File::objcConstraintNone;
- else if ( token == "retain_release" )
- lib._objcConstraint = ld::File::objcConstraintRetainRelease;
- else if ( token == "retain_release_for_simulator" )
- lib._objcConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
- else if ( token == "retain_release_or_gc" )
- lib._objcConstraint = ld::File::objcConstraintRetainReleaseOrGC;
- else if ( token == "gc" )
- lib._objcConstraint = ld::File::objcConstraintGC;
- else
- throwf("unexpected token: %s", token.str().c_str());
- }
- void parseExportsBlock(DynamicLibrary& lib, std::string &selectedArchName) {
- if ( !hasOptionalToken("exports") )
- return;
-
- if ( !hasOptionalToken("-") )
- return;
-
- while ( true ) {
- if ( !parseArchFlowSequence(selectedArchName) ) {
- Token token;
- while ( true ) {
- token = peek();
- if ( token == "archs" || token == "..." || token.empty() )
- break;
- next();
- }
- if (token == "..." || token.empty() )
- break;
-
- continue;
- }
-
- parseAllowedClients(lib);
- parseReexportedDylibs(lib);
- parseSymbols(lib);
- if ( !hasOptionalToken("-") )
- break;
- }
- }
-
- 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);
- parseInstallName(lib);
- parseCurrentVersion(lib);
- parseCompatibilityVersion(lib);
- parseSwiftVersion(lib);
- parseObjCConstraint(lib);
- parseExportsBlock(lib, selectedArchName);
- }
-
-public:
- TBDFile(const char* data, uint64_t size) : _tokenizer(data, size) {}
-
- DynamicLibrary parseFileForArch(std::string requestedArchName) {
- _tokenizer.reset();
- DynamicLibrary lib;
- expectToken("---");
- parseDocument(lib, requestedArchName);
- expectToken("...");
- return lib;
- }
-
- bool validForArch(std::string requestedArchName) {
- _tokenizer.reset();
- auto token = next();
- if ( token != "---" )
- return false;
- return !parseAndSelectArchitecture(requestedArchName).empty();
- }
-
- void dumpTokens() {
- _tokenizer.reset();
- Token token;
- do {
- token = next();
- printf("token: %s\n", token.str().c_str());
- } while ( !token.empty() );
- }
-};
-
-} // end anonymous namespace
namespace textstub {
namespace dylib {
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,
+ File(const char* path, const uint8_t* fileContent, uint64_t fileLength,
time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace,
- bool hoistImplicitPublicDylibs, Options::Platform platform,
- cpu_type_t cpuType, const char* archName, uint32_t linkMinOSVersion,
+ 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);
virtual ~File() noexcept {}
private:
- void buildExportHashTable(const DynamicLibrary &lib);
-
- cpu_type_t _cpuType;
+ void buildExportHashTable(const tapi::LinkerInterfaceFile* file);
};
+static ld::File::ObjcConstraint mapObjCConstraint(tapi::ObjCConstraint constraint) {
+ switch (constraint) {
+ case tapi::ObjCConstraint::None:
+ return ld::File::objcConstraintNone;
+ case tapi::ObjCConstraint::Retain_Release:
+ return ld::File::objcConstraintRetainRelease;
+ case tapi::ObjCConstraint::Retain_Release_For_Simulator:
+ return ld::File::objcConstraintRetainReleaseForSimulator;
+ case tapi::ObjCConstraint::Retain_Release_Or_GC:
+ return ld::File::objcConstraintRetainReleaseOrGC;
+ case tapi::ObjCConstraint::GC:
+ return ld::File::objcConstraintGC;
+ }
+
+ return ld::File::objcConstraintNone;
+}
+
+static Options::Platform mapPlatform(tapi::Platform platform) {
+ switch (platform) {
+ case tapi::Platform::Unknown:
+ return Options::kPlatformUnknown;
+ case tapi::Platform::OSX:
+ return Options::kPlatformOSX;
+ case tapi::Platform::iOS:
+ return Options::kPlatformiOS;
+ case tapi::Platform::watchOS:
+ return Options::kPlatformWatchOS;
+ case tapi::Platform::tvOS:
+ return Options::kPlatform_tvOS;
+ }
+
+ return Options::kPlatformUnknown;
+}
+
template <typename A>
-File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t mTime,
- ld::File::Ordinal ord, bool linkingFlatNamespace, bool hoistImplicitPublicDylibs,
- Options::Platform platform, cpu_type_t cpuType, const char* archName,
- uint32_t linkMinOSVersion, bool allowSimToMacOSX, bool addVers,
+ File<A>::File(const char* path, const uint8_t* fileContent, uint64_t fileLength,
+ 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,
+ bool enforceDylibSubtypesMatch, bool allowSimToMacOSX, bool addVers,
bool buildingForSimulator, bool logAllFiles, const char* targetInstallPath,
bool indirectDylib)
- : Base(strdup(path), mTime, ord, platform, linkMinOSVersion, linkingFlatNamespace,
- hoistImplicitPublicDylibs, allowSimToMacOSX, addVers),
- _cpuType(cpuType)
+ : Base(strdup(path), mTime, ord, platform, linkMinOSVersion, allowWeakImports, linkingFlatNamespace,
+ hoistImplicitPublicDylibs, allowSimToMacOSX, addVers)
{
- this->_bitcode = std::unique_ptr<ld::Bitcode>(new ld::Bitcode(nullptr, 0));
- // Text stubs are implicit app extension safe.
- this->_appExtensionSafe = true;
+ auto matchingType = enforceDylibSubtypesMatch ?
+ tapi::CpuSubTypeMatching::Exact : tapi::CpuSubTypeMatching::ABI_Compatible;
+
+ std::string errorMessage;
+ auto file = std::unique_ptr<tapi::LinkerInterfaceFile>(
+ tapi::LinkerInterfaceFile::create(path, fileContent, fileLength, cpuType,
+ cpuSubType, matchingType,
+ tapi::PackedVersion32(linkMinOSVersion), errorMessage));
+
+ if (file == nullptr)
+ throw strdup(errorMessage.c_str());
+
+ // unmap file - it is no longer needed.
+ munmap((caddr_t)fileContent, fileLength);
// write out path for -t option
if ( logAllFiles )
printf("%s\n", path);
- TBDFile stub((const char*)fileContent, fileLength);
- auto lib = stub.parseFileForArch(archName);
-
- 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);
+ this->_bitcode = std::unique_ptr<ld::Bitcode>(new ld::Bitcode(nullptr, 0));
+ this->_noRexports = !file->hasReexportedLibraries();
+ this->_hasWeakExports = file->hasWeakDefinedExports();
+ this->_dylibInstallPath = strdup(file->getInstallName().c_str());
+ this->_installPathOverride = file->isInstallNameVersionSpecific();
+ this->_dylibCurrentVersion = file->getCurrentVersion();
+ this->_dylibCompatibilityVersion = file->getCompatibilityVersion();
+ this->_swiftVersion = file->getSwiftVersion();
+ this->_objcConstraint = mapObjCConstraint(file->getObjCConstraint());
+ this->_parentUmbrella = file->getParentFrameworkName().empty() ? nullptr : strdup(file->getParentFrameworkName().c_str());
+ this->_appExtensionSafe = file->isApplicationExtensionSafe();
// if framework, capture framework name
const char* lastSlash = strrchr(this->_dylibInstallPath, '/');
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()));
- }
+ 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
- if ( !this->_allowableClients.empty() )
- this->_hasPublicInstallName = false;
+ 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()));
- if ( (lib._platform != platform) && (platform != Options::kPlatformUnknown) ) {
+ auto dylibPlatform = mapPlatform(file->getPlatform());
+ if ( (dylibPlatform != platform) && (platform != Options::kPlatformUnknown) ) {
this->_wrongOS = true;
if ( this->_addVersionLoadCommand && !indirectDylib ) {
if ( buildingForSimulator ) {
if ( !this->_allowSimToMacOSXLinking )
throwf("building for %s simulator, but linking against dylib built for %s (%s).",
- Options::platformName(platform), Options::platformName(lib._platform), 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(lib._platform), path);
+ Options::platformName(platform), Options::platformName(dylibPlatform), path);
}
}
}
- this->_dependentDylibs.reserve(lib._reexportedLibraries.size());
- for ( const auto& reexport : lib._reexportedLibraries ) {
- const char *path = strdup(reexport.str().c_str());
+ 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);
}
- // build hash table
- buildExportHashTable(lib);
+ for (const auto& symbol : file->ignoreExports())
+ this->_ignoreExports.insert(strdup(symbol.c_str()));
- munmap((caddr_t)fileContent, fileLength);
+ // 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;
+ importNames.reserve(file->undefineds().size());
+ // We do not need to strdup the name, because that will be done by the
+ // ImportAtom constructor.
+ for (const auto &sym : file->undefineds())
+ importNames.emplace_back(sym.getName().c_str());
+ this->_importAtom = new generic::dylib::ImportAtom<A>(*this, importNames);
+ }
+
+ // build hash table
+ buildExportHashTable(file.get());
}
template <typename A>
-void File<A>::buildExportHashTable(const DynamicLibrary& lib) {
+void File<A>::buildExportHashTable(const tapi::LinkerInterfaceFile* file) {
if (this->_s_logHashtable )
fprintf(stderr, "ld: building hashtable from text-stub info in %s\n", this->path());
- for (auto &sym : lib._symbols)
- this->addSymbol(sym.str().c_str());
+ for (const auto &sym : file->exports()) {
+ const char* name = sym.getName().c_str();
+ bool weakDef = sym.isWeakDefined();
+ bool tlv = sym.isThreadLocalValue();
-#if SUPPORT_ARCH_i386
- if (this->_platform == Options::kPlatformOSX && _cpuType == CPU_TYPE_I386) {
- for (auto &sym : lib._classes)
- this->addSymbol((".objc_class_name" + sym.str()).c_str());
- } else {
- for (auto &sym : lib._classes) {
- this->addSymbol(("_OBJC_CLASS_$" + sym.str()).c_str());
- this->addSymbol(("_OBJC_METACLASS_$" + sym.str()).c_str());
- }
+ typename Base::AtomAndWeak bucket = { nullptr, weakDef, tlv, 0 };
+ if ( this->_s_logHashtable )
+ fprintf(stderr, " adding %s to hash table for %s\n", name, this->path());
+ this->_atoms[strdup(name)] = bucket;
}
-#else
- for (auto &sym : lib._classes) {
- this->addSymbol(("_OBJC_CLASS_$" + sym.str()).c_str());
- this->addSymbol(("_OBJC_METACLASS_$" + sym.str()).c_str());
- }
-#endif
-
- for (auto &sym : lib._ivars)
- this->addSymbol(("_OBJC_IVAR_$" + sym.str()).c_str());
-
- for (auto &sym : lib._weakDefSymbols)
- this->addSymbol(sym.str().c_str(), /*weak=*/true);
-
- for (auto &sym : lib._tlvSymbols)
- this->addSymbol(sym.str().c_str(), /*weak=*/false, /*tlv=*/true);
}
template <typename A>
public:
using P = typename A::P;
- 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,
+ static ld::dylib::File* parse(const char* path, const uint8_t* fileContent,
+ uint64_t fileLength, time_t mTime,
+ ld::File::Ordinal ordinal, const Options& opts,
bool indirectDylib)
{
- return new File<A>(fileContent, fileLength, path, mTime, ordinal,
+ return new File<A>(path, fileContent, fileLength,mTime, ordinal,
opts.flatNamespace(),
+ opts.linkingMainExecutable(),
opts.implicitlyLinkIndirectPublicDylibs(),
opts.platform(),
- opts.architecture(),
- opts.architectureName(),
opts.minOSversion(),
+ opts.allowWeakImports(),
+ opts.architecture(),
+ opts.subArchitecture(),
+ opts.enforceDylibSubtypesMatch(),
opts.allowSimulatorToLinkWithMacOSX(),
opts.addVersionLoadCommand(),
opts.targetIOSSimulator(),
}
};
-template <typename A>
-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;
-
- TBDFile stub((const char*)fileContent, fileLength);
- if ( !stub.validForArch(archName) )
- throwf("missing required architecture %s in file %s", archName, path.c_str());
-
- return true;
-}
-
//
// main function used by linker to instantiate ld::Files
//
time_t modTime, const Options& opts, ld::File::Ordinal ordinal,
bool bundleLoader, bool indirectDylib)
{
+
switch ( opts.architecture() ) {
#if SUPPORT_ARCH_x86_64
case CPU_TYPE_X86_64:
- if ( Parser<x86_64>::validFile(fileContent, fileLength, path, opts.architectureName()) )
- return Parser<x86_64>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
- break;
+ if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength))
+ return Parser<x86_64>::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib);
#endif
#if SUPPORT_ARCH_i386
case CPU_TYPE_I386:
- if ( Parser<x86>::validFile(fileContent, fileLength, path, opts.architectureName()) )
- return Parser<x86>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
- break;
+ if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength))
+ return Parser<x86>::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib);
#endif
#if SUPPORT_ARCH_arm_any
case CPU_TYPE_ARM:
- if ( Parser<arm>::validFile(fileContent, fileLength, path, opts.architectureName()) )
- return Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
- break;
+ if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength))
+ return Parser<arm>::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib);
#endif
#if SUPPORT_ARCH_arm64
case CPU_TYPE_ARM64:
- if ( Parser<arm64>::validFile(fileContent, fileLength, path, opts.architectureName()) )
- return Parser<arm64>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
- break;
+ if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength))
+ return Parser<arm64>::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib);
#endif
}
return nullptr;