X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/2a0ed0a31db9961dcb7c87964091b22401c4d69b..0a8dc3df050bd5c0a70486b9ebdb9dccce439f3e:/src/ld/parsers/textstub_dylib_file.cpp diff --git a/src/ld/parsers/textstub_dylib_file.cpp b/src/ld/parsers/textstub_dylib_file.cpp index fb452d8..5854462 100644 --- a/src/ld/parsers/textstub_dylib_file.cpp +++ b/src/ld/parsers/textstub_dylib_file.cpp @@ -25,7 +25,7 @@ #include #include - +#include #include #include "Architectures.hpp" @@ -35,469 +35,6 @@ #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 _allowedClients; - std::vector _reexportedLibraries; - std::vector _symbols; - std::vector _classes; - std::vector _ivars; - std::vector _weakDefSymbols; - std::vector _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 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 parseArchFlowSequence() { - std::vector 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 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 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 { @@ -513,51 +50,94 @@ class File final : public generic::dylib::File using Base = generic::dylib::File; 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 -File::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::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(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::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(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, '/'); @@ -571,100 +151,69 @@ File::File(const uint8_t* fileContent, uint64_t fileLength, const char* path, this->_frameworkName = leafName; } - // TEMPORARY HACK BEGIN: Support ancient re-export command LC_SUB_FRAMEWORK. - // [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())); // [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 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(*this, importNames); + } + + // build hash table + buildExportHashTable(file.get()); } template -void File::buildExportHashTable(const DynamicLibrary& lib) { +void File::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 @@ -673,19 +222,21 @@ class Parser 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(fileContent, fileLength, path, mTime, ordinal, + return new File(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(), @@ -695,20 +246,6 @@ public: } }; -template -bool Parser::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 // @@ -716,30 +253,27 @@ ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, const ch 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::validFile(fileContent, fileLength, path, opts.architectureName()) ) - return Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib); - break; + if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength)) + return Parser::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib); #endif #if SUPPORT_ARCH_i386 case CPU_TYPE_I386: - if ( Parser::validFile(fileContent, fileLength, path, opts.architectureName()) ) - return Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib); - break; + if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength)) + return Parser::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib); #endif #if SUPPORT_ARCH_arm_any case CPU_TYPE_ARM: - if ( Parser::validFile(fileContent, fileLength, path, opts.architectureName()) ) - return Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib); - break; + if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength)) + return Parser::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib); #endif #if SUPPORT_ARCH_arm64 case CPU_TYPE_ARM64: - if ( Parser::validFile(fileContent, fileLength, path, opts.architectureName()) ) - return Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib); - break; + if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength)) + return Parser::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib); #endif } return nullptr;