X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/f410558f5d60087e4c310119a1751b437121c3b9..e456bf1059cf7e6b8b71545d1b2f2092b55a9684:/src/ld/parsers/macho_relocatable_file.cpp diff --git a/src/ld/parsers/macho_relocatable_file.cpp b/src/ld/parsers/macho_relocatable_file.cpp index ae3be5f..00d5feb 100644 --- a/src/ld/parsers/macho_relocatable_file.cpp +++ b/src/ld/parsers/macho_relocatable_file.cpp @@ -80,11 +80,10 @@ public: _dwarfTranslationUnitPath(NULL), _dwarfDebugInfoSect(NULL), _dwarfDebugAbbrevSect(NULL), _dwarfDebugLineSect(NULL), _dwarfDebugStringSect(NULL), - _objConstraint(ld::File::objcConstraintNone), + _hasObjC(false), _swiftVersion(0), _cpuSubType(0), _minOSVersion(0), - _platform(Options::kPlatformUnknown), _canScatterAtoms(false), _hasllvmProfiling(false), _objcHasCategoryClassPropertiesField(false), @@ -95,11 +94,10 @@ public: virtual bool forEachAtom(ld::File::AtomHandler&) const; virtual bool justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const { return false; } - virtual uint32_t minOSVersion() const { return _minOSVersion; } - virtual uint32_t platform() const { return _platform; } + virtual const ld::VersionSet& platforms() const { return _platforms; } // overrides of ld::relocatable::File - virtual ObjcConstraint objCConstraint() const { return _objConstraint; } + virtual bool hasObjC() const { return _hasObjC; } virtual bool objcHasCategoryClassPropertiesField() const { return _objcHasCategoryClassPropertiesField; } virtual uint32_t cpuSubType() const { return _cpuSubType; } @@ -144,11 +142,11 @@ private: const macho_section

* _dwarfDebugAbbrevSect; const macho_section

* _dwarfDebugLineSect; const macho_section

* _dwarfDebugStringSect; - ld::File::ObjcConstraint _objConstraint; + bool _hasObjC; uint8_t _swiftVersion; uint32_t _cpuSubType; uint32_t _minOSVersion; - Options::Platform _platform; + ld::VersionSet _platforms; bool _canScatterAtoms; bool _hasllvmProfiling; bool _objcHasCategoryClassPropertiesField; @@ -995,7 +993,7 @@ public: static bool validFile(const uint8_t* fileContent, bool subtypeMustMatch=false, cpu_subtype_t subtype=0); static const char* fileKind(const uint8_t* fileContent); - static Options::Platform findPlatform(const macho_header* header); + static ld::Platform findPlatform(const macho_header* header, uint32_t* minOsVers); static bool hasObjC2Categories(const uint8_t* fileContent); static bool hasObjC1Categories(const uint8_t* fileContent); static bool getNonLocalSymbols(const uint8_t* fileContnet, std::vector &syms); @@ -1026,6 +1024,9 @@ public: const char* name; // only used if targetAtom is NULL int64_t addend; bool weakImport; // only used if targetAtom is NULL +#if SUPPORT_ARCH_arm64e + ld::Fixup::AuthData authData; // only used for authenticated pointers +#endif }; struct FixupInAtom { @@ -1044,6 +1045,11 @@ public: FixupInAtom(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, uint64_t addend) : fixup(src.offsetInAtom, c, k, addend), atom(src.atom) { src.atom->incrementFixupCount(); } +#if SUPPORT_ARCH_arm64e + FixupInAtom(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, ld::Fixup::AuthData authData) : + fixup(src.offsetInAtom, c, k, authData), atom(src.atom) { src.atom->incrementFixupCount(); } +#endif + FixupInAtom(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k) : fixup(src.offsetInAtom, c, k, (uint64_t)0), atom(src.atom) { src.atom->incrementFixupCount(); } @@ -1071,6 +1077,12 @@ public: _allFixups.push_back(FixupInAtom(src, c, k, addend)); } +#if SUPPORT_ARCH_arm64e + void addFixup(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, ld::Fixup::AuthData authData) { + _allFixups.push_back(FixupInAtom(src, c, k, authData)); + } +#endif + void addFixup(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k) { _allFixups.push_back(FixupInAtom(src, c, k)); } @@ -1210,7 +1222,8 @@ private: bool verboseOptimizationHints, bool ignoreMismatchPlatform); ld::relocatable::File* parse(const ParserOptions& opts); static uint8_t loadCommandSizeMask(); - bool parseLoadCommands(Options::Platform platform, uint32_t minOSVersion, bool simulator, bool ignoreMismatchPlatform); + static bool useSimulatorVariant(); + bool parseLoadCommands(ld::VersionSet platforms, bool simulator, bool ignoreMismatchPlatform); void makeSections(); void prescanSymbolTable(); void makeSortedSymbolsArray(uint32_t symArray[], const uint32_t sectionArray[]); @@ -1284,6 +1297,9 @@ private: const macho_section

* _stubsMachOSection; std::vector _dtraceProviderInfo; std::vector _allFixups; +#if SUPPORT_ARCH_arm64e + bool _supportsAuthenticatedPointers; +#endif }; @@ -1371,6 +1387,8 @@ bool Parser::validFile(const uint8_t* fileContent, bool subtypeMustMatch, return false; if ( header->filetype() != MH_OBJECT ) return false; + if ( subtypeMustMatch && (header->cpusubtype() != (uint32_t)subtype) ) + return false; return true; } @@ -1562,16 +1580,27 @@ template bool Parser::LabelAndCFIBreakIterator::next(Parser& parser, const Section& sect, uint32_t sectNum, pint_t startAddr, pint_t endAddr, pint_t* addr, pint_t* size, const macho_nlist

** symbol) { + bool cfiApplicable = (sect.machoSection()->flags() & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS)); // may not be a label on start of section, but need atom demarcation there if ( newSection ) { newSection = false; // advance symIndex until we get to the first label at or past the start of this section while ( symIndex < sortedSymbolCount ) { - const macho_nlist

& sym = parser.symbolFromIndex(sortedSymbolIndexes[symIndex]); - if ( ! sect.ignoreLabel(parser.nameFromSymbol(sym)) ) { - pint_t nextSymbolAddr = sym.n_value(); + const macho_nlist

* sym = &parser.symbolFromIndex(sortedSymbolIndexes[symIndex]); + // if compile threw in "ltmp*" symbol at start of section and there is another real label at same location, ignore ltmp one + if ( symIndex+1 < sortedSymbolCount ) { + const macho_nlist

* sym2 = &parser.symbolFromIndex(sortedSymbolIndexes[symIndex+1]); + if ( (sym->n_sect() == sym2->n_sect()) && (sym->n_value() == sym2->n_value()) ) { + if ( strncmp(parser.nameFromSymbol(*sym), "ltmp", 4) == 0 ) { + ++symIndex; + sym = sym2; + } + } + } + if ( ! sect.ignoreLabel(parser.nameFromSymbol(*sym)) ) { + pint_t nextSymbolAddr = sym->n_value(); //fprintf(stderr, "sectNum=%d, nextSymbolAddr=0x%08llX, name=%s\n", sectNum, (uint64_t)nextSymbolAddr, parser.nameFromSymbol(sym)); - if ( (nextSymbolAddr > startAddr) || ((nextSymbolAddr == startAddr) && (sym.n_sect() == sectNum)) ) + if ( (nextSymbolAddr > startAddr) || ((nextSymbolAddr == startAddr) && (sym->n_sect() == sectNum)) ) break; } ++symIndex; @@ -1621,7 +1650,7 @@ bool Parser::LabelAndCFIBreakIterator::next(Parser& parser, const Section< return true; } // no symbols in section, check CFI - if ( cfiIndex < cfiStartsCount ) { + if ( cfiApplicable && (cfiIndex < cfiStartsCount) ) { pint_t nextCfiAddr = cfiStartsArray[cfiIndex]; if ( nextCfiAddr < endAddr ) { // use cfi @@ -1749,6 +1778,10 @@ ld::relocatable::File* Parser::parse(const ParserOptions& opts) _treateBitcodeAsData = opts.treateBitcodeAsData; _usingBitcode = opts.usingBitcode; +#if SUPPORT_ARCH_arm64e + _supportsAuthenticatedPointers = opts.supportsAuthenticatedPointers; +#endif + // respond to -t option if ( opts.logAllFiles ) printf("%s\n", _path); @@ -1757,7 +1790,7 @@ ld::relocatable::File* Parser::parse(const ParserOptions& opts) _maxDefaultCommonAlignment = opts.maxDefaultCommonAlignment; // parse start of mach-o file - if ( ! parseLoadCommands(opts.platform, opts.minOSVersion, opts.simulator, opts.ignoreMismatchPlatform) ) + if ( ! parseLoadCommands(opts.platforms, opts.simulator, opts.ignoreMismatchPlatform) ) return _file; // make array of @@ -1999,9 +2032,13 @@ template <> uint8_t Parser::loadCommandSizeMask() { return 0x03; } template <> uint8_t Parser::loadCommandSizeMask() { return 0x07; } template <> uint8_t Parser::loadCommandSizeMask() { return 0x03; } template <> uint8_t Parser::loadCommandSizeMask() { return 0x07; } +template <> bool Parser::useSimulatorVariant() { return true; } +template <> bool Parser::useSimulatorVariant() { return true; } +template bool Parser::useSimulatorVariant() { return false; } + template -bool Parser::parseLoadCommands(Options::Platform platform, uint32_t linkMinOSVersion, bool simulator, bool ignoreMismatchPlatform) +bool Parser::parseLoadCommands(ld::VersionSet platforms, bool simulator, bool ignoreMismatchPlatform) { const macho_header

* header = (const macho_header

*)_fileContent; @@ -2015,7 +2052,7 @@ bool Parser::parseLoadCommands(Options::Platform platform, uint32_t linkMinOS // an empty .o file with zero load commands will crash linker if ( cmd_count == 0 ) return false; - Options::Platform lcPlatform = Options::kPlatformUnknown; + ld::VersionSet lcPlatforms; const macho_load_command

* const cmds = (macho_load_command

*)((char*)header + sizeof(macho_header

)); const macho_load_command

* const cmdsEnd = (macho_load_command

*)((char*)header + sizeof(macho_header

) + header->sizeofcmds()); const macho_load_command

* cmd = cmds; @@ -2097,23 +2134,19 @@ bool Parser::parseLoadCommands(Options::Platform platform, uint32_t linkMinOS case LC_VERSION_MIN_MACOSX: case LC_VERSION_MIN_IPHONEOS: case LC_VERSION_MIN_WATCHOS: - #if SUPPORT_APPLE_TV case LC_VERSION_MIN_TVOS: - #endif if ( ignoreMismatchPlatform ) break; - lcPlatform = Options::platformForLoadCommand(cmd->cmd()); - _file->_platform = lcPlatform; - _file->_minOSVersion = ((macho_version_min_command

*)cmd)->version(); + lcPlatforms.add({Options::platformForLoadCommand(cmd->cmd(), useSimulatorVariant()), ((macho_version_min_command

*)cmd)->version()}); + _file->_platforms.add({Options::platformForLoadCommand(cmd->cmd(), useSimulatorVariant()), ((macho_version_min_command

*)cmd)->version()}); break; case LC_BUILD_VERSION: { const macho_build_version_command

* buildVersCmd = (macho_build_version_command

*)cmd; if ( ignoreMismatchPlatform ) break; - lcPlatform = (Options::Platform)buildVersCmd->platform(); - _file->_platform = lcPlatform; - _file->_minOSVersion = buildVersCmd->minos(); + lcPlatforms.add({(ld::Platform)buildVersCmd->platform(), buildVersCmd->minos()}); + _file->_platforms.add({(ld::Platform)buildVersCmd->platform(), buildVersCmd->minos()}); const macho_build_tool_version

* entry = (macho_build_tool_version

*)((uint8_t*)cmd + sizeof(macho_build_version_command

)); for (uint32_t t=0; t < buildVersCmd->ntools(); ++t) { _file->_toolVersions.push_back(std::make_pair(entry->tool(), entry->version())); @@ -2134,80 +2167,63 @@ bool Parser::parseLoadCommands(Options::Platform platform, uint32_t linkMinOS if ( cmd > cmdsEnd ) throwf("malformed mach-o file, load command #%d is outside size of load commands", i); } + // arm/arm64 objects are default to ios platform if not set. // rdar://problem/21746314 - if (lcPlatform == Options::kPlatformUnknown && + if (lcPlatforms.empty() && (std::is_same::value || std::is_same::value)) - lcPlatform = Options::kPlatformiOS; + lcPlatforms.add({ld::kPlatform_iOS,0}); // Check platform cross-linking. if ( !ignoreMismatchPlatform ) { - if ( lcPlatform != platform ) { - switch (platform) { - case Options::kPlatformOSX: - case Options::kPlatformiOS: - if ( lcPlatform == Options::kPlatformUnknown ) - break; - // fall through if the Platform is not Unknown - case Options::kPlatform_bridgeOS: - case Options::kPlatformWatchOS: - // Error when using bitcocde, warning otherwise. - if (_usingBitcode) - throwf("building for %s%s, but linking in object file built for %s,", - Options::platformName(platform), (simulator ? " simulator" : ""), - Options::platformName(lcPlatform)); - else - warning("URGENT: building for %s%s, but linking in object file (%s) built for %s. " - "Note: This will be an error in the future.", - Options::platformName(platform), (simulator ? " simulator" : ""), path(), - Options::platformName(lcPlatform)); - break; - #if SUPPORT_APPLE_TV - case Options::kPlatform_tvOS: - // Error when using bitcocde, warning otherwise. - if (_usingBitcode) - throwf("building for %s%s, but linking in object file built for %s,", - Options::platformName(platform), (simulator ? " simulator" : ""), - Options::platformName(lcPlatform)); - else - warning("URGENT: building for %s%s, but linking in object file (%s) built for %s. " - "Note: This will be an error in the future.", - Options::platformName(platform), (simulator ? " simulator" : ""), path(), - Options::platformName(lcPlatform)); - break; - #endif - case Options::kPlatformUnknown: - // skip if the target platform is unknown - break; + __block bool warned = false; + platforms.forEach(^(ld::Platform platform, uint32_t version, bool &stop) { + if ( !warned && !lcPlatforms.contains(platform) ) { + if (_usingBitcode) + throwf("building for %s, but linking in object file built for %s,", + platforms.to_str().c_str(), lcPlatforms.to_str().c_str()); +#if 0 +// FIXME: Re-enable once clang supports zippering +// Turn off "urgent:" linker warning about iOSMac / macOS mismatch + else + warning("URGENT: building for %s, but linking in object file (%s) built for %s. " + "Note: This will be an error in the future.", + platforms.to_str().c_str(), path(), lcPlatforms.to_str().c_str()); +#endif + warned = true; } - } - if ( linkMinOSVersion && (_file->_minOSVersion > linkMinOSVersion) ) { - char t1[32]; - char t2[32]; - versionToString(_file->_minOSVersion, t1); - versionToString(linkMinOSVersion, t2); - warning("object file (%s) was built for newer %s version (%s) than being linked (%s)", - _path, Options::platformName(lcPlatform), t1, t2); - } + if ( version && (lcPlatforms.minOS(platform) > version) ) { + char t1[32]; + char t2[32]; + versionToString(lcPlatforms.minOS(platform), t1); + versionToString(version, t2); + warning("object file (%s) was built for newer %s version (%s) than being linked (%s)", + _path, Options::platformName(platform), t1, t2); + } + }); } - - // record range of sections + // validate just one segment if ( segment == NULL ) throw "missing LC_SEGMENT"; + if ( segment->filesize() > _fileLength ) + throw "LC_SEGMENT filesize too large"; + + // record and validate sections _sectionsStart = (macho_section

*)((char*)segment + sizeof(macho_segment_command

)); _machOSectionsCount = segment->nsects(); if ( (sizeof(macho_segment_command

) + _machOSectionsCount * sizeof(macho_section

)) > segment->cmdsize() ) throw "too many sections for size of LC_SEGMENT command"; + return true; } template -Options::Platform Parser::findPlatform(const macho_header

* header) +ld::Platform Parser::findPlatform(const macho_header

* header, uint32_t* minOsVers) { const uint32_t cmd_count = header->ncmds(); if ( cmd_count == 0 ) - return Options::kPlatformUnknown; + return ld::kPlatform_unknown; const macho_load_command

* const cmds = (macho_load_command

*)((char*)header + sizeof(macho_header

)); const macho_load_command

* const cmdsEnd = (macho_load_command

*)((char*)header + sizeof(macho_header

) + header->sizeofcmds()); const macho_load_command

* cmd = cmds; @@ -2218,25 +2234,37 @@ Options::Platform Parser::findPlatform(const macho_header

* header) const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize(); if ( endOfCmd > (uint8_t*)cmdsEnd ) throwf("load command #%d extends beyond the end of the load commands", i); + const macho_version_min_command

* versCmd = (macho_version_min_command

*)cmd; + const macho_build_version_command

* buildVersCmd = (macho_build_version_command

*)cmd; + *minOsVers = versCmd->version(); switch (cmd->cmd()) { case LC_VERSION_MIN_MACOSX: - return Options::kPlatformOSX; + return ld::kPlatform_macOS; case LC_VERSION_MIN_IPHONEOS: - return Options::kPlatformiOS; + if (useSimulatorVariant()) + return ld::kPlatform_iOSSimulator; + else + return ld::kPlatform_iOS; case LC_VERSION_MIN_WATCHOS: - return Options::kPlatformWatchOS; - #if SUPPORT_APPLE_TV + if (useSimulatorVariant()) + return ld::kPlatform_watchOSSimulator; + else + return ld::kPlatform_watchOS; case LC_VERSION_MIN_TVOS: - return Options::kPlatform_tvOS; - #endif + if (useSimulatorVariant()) + return ld::kPlatform_tvOSSimulator; + else + return ld::kPlatform_tvOS; case LC_BUILD_VERSION: - return (Options::Platform)((macho_build_version_command

*)cmd)->platform(); + *minOsVers = buildVersCmd->minos(); + return (ld::Platform)buildVersCmd->platform(); } cmd = (const macho_load_command

*)(((char*)cmd)+cmd->cmdsize()); if ( cmd > cmdsEnd ) throwf("malformed mach-o file, load command #%d is outside size of load commands", i); } - return Options::kPlatformUnknown; + *minOsVers = 0; + return ld::kPlatform_unknown; } @@ -2578,14 +2606,7 @@ void Parser::makeSections() const uint32_t* contents = (uint32_t*)(_file->fileContent()+sect->offset()); if ( (sect->size() >= 8) && (contents[0] == 0) ) { uint32_t flags = E::get32(contents[1]); - if ( (flags & 4) == 4 ) - _file->_objConstraint = ld::File::objcConstraintGC; - else if ( (flags & 2) == 2 ) - _file->_objConstraint = ld::File::objcConstraintRetainReleaseOrGC; - else if ( (flags & 32) == 32 ) - _file->_objConstraint = ld::File::objcConstraintRetainReleaseForSimulator; - else - _file->_objConstraint = ld::File::objcConstraintRetainRelease; + _file->_hasObjC = true; _file->_swiftVersion = ((flags >> 8) & 0xFF); _file->_objcHasCategoryClassPropertiesField = (flags & 64); if ( sect->size() > 8 ) { @@ -3055,6 +3076,13 @@ void Parser::addFixups(const SourceLocation& src, ld::Fixup::Kind setKind, co ld::Fixup::Cluster cl = ld::Fixup::k1of3; ld::Fixup::Kind firstKind = ld::Fixup::kindSetTargetAddress; bool combined = false; + +#if SUPPORT_ARCH_arm64e + bool isAuthenticated = setKind == ld::Fixup::kindStoreLittleEndianAuth64; + // Authenticated pointers need an extra fixup for the auth data. + if (isAuthenticated) + cl = ld::Fixup::k2of4; +#endif if ( target.addend == 0 ) { cl = ld::Fixup::k1of1; combined = true; @@ -3114,6 +3142,12 @@ void Parser::addFixups(const SourceLocation& src, ld::Fixup::Kind setKind, co case ld::Fixup::kindStoreARM64TLVPLoadPageOff12: firstKind = ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12; break; +#endif +#if SUPPORT_ARCH_arm64e + case ld::Fixup::kindStoreLittleEndianAuth64: + firstKind = ld::Fixup::kindStoreTargetAddressLittleEndianAuth64; + cl = ld::Fixup::k2of2; + break; #endif default: combined = false; @@ -3122,6 +3156,19 @@ void Parser::addFixups(const SourceLocation& src, ld::Fixup::Kind setKind, co } } +#if SUPPORT_ARCH_arm64e + // As the auth data is independent of the addend and target, we can just always + // put it first. + if (isAuthenticated) { + if (cl == ld::Fixup::k2of2) { + addFixup(src, ld::Fixup::k1of2, ld::Fixup::kindSetAuthData, target.authData); + } else { + assert(cl == ld::Fixup::k2of4); + addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetAuthData, target.authData); + } + } +#endif + if ( target.atom != NULL ) { if ( target.atom->scope() == ld::Atom::scopeTranslationUnit ) { addFixup(src, cl, firstKind, target.atom); @@ -3146,12 +3193,24 @@ void Parser::addFixups(const SourceLocation& src, ld::Fixup::Kind setKind, co addFixup(src, cl, firstKind, target.weakImport, target.name); } if ( target.addend == 0 ) { +#if SUPPORT_ARCH_arm64e + if (isAuthenticated) + assert(combined); +#endif if ( ! combined ) addFixup(src, ld::Fixup::k2of2, setKind); } else { - addFixup(src, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, target.addend); - addFixup(src, ld::Fixup::k3of3, setKind); +#if SUPPORT_ARCH_arm64e + if (isAuthenticated) { + addFixup(src, ld::Fixup::k3of4, ld::Fixup::kindAddAddend, target.addend); + addFixup(src, ld::Fixup::k4of4, setKind); + } else +#endif + { + addFixup(src, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, target.addend); + addFixup(src, ld::Fixup::k3of3, setKind); + } } } @@ -5470,7 +5529,7 @@ uint32_t ImplicitSizeSection::appendAtoms(class Parser& parser, uint8_t* p } else { // make named atom for label - //fprintf(stderr, " 0x%08llX make labeled\n", (uint64_t)foundAddr); + //fprintf(stderr, " 0x%08llX make labeled: %s\n", (uint64_t)foundAddr, parser.nameFromSymbol(*foundLabel)); new (allocatedSpace) Atom(*this, parser, *foundLabel, labeledAtomSize); } if ( !skip ) { @@ -6308,6 +6367,8 @@ bool Section::addRelocFixup(class Parser& parser, const macho_re Parser::TargetDesc target; Parser::TargetDesc toTarget; src.atom = this->findAtomByAddress(srcAddr); + if ( src.atom == NULL ) + throwf("malformed mach-o, reloc addr 0x%llX not in any atom", srcAddr); src.offsetInAtom = srcAddr - src.atom->_objAddress; const uint8_t* fixUpPtr = file().fileContent() + sect->offset() + reloc->r_address(); uint64_t contentValue = 0; @@ -7524,6 +7585,52 @@ bool Section::addRelocFixup(class Parser& parser, const macho_relo parser.addFixups(src, ld::Fixup::kindStoreARM64PointerToGOT, target); } break; +#if SUPPORT_ARCH_arm64e + case ARM64_RELOC_AUTHENTICATED_POINTER: { + if ( reloc->r_pcrel() ) + throw "pcrel and ARM64_RELOC_AUTHENTICATED_POINTER not supported"; + if ( ! reloc->r_extern() ) + throw "r_extern == 0 and ARM64_RELOC_AUTHENTICATED_POINTER not supported"; + // An authenticated pointer is: + // { + // int32_t addend; + // uint16_t diversityData; + // uint16_t hasAddressDiversity : 1; + // uint16_t key : 2; + // uint16_t zeroes : 11; + // uint16_t zero : 1; + // uint16_t authenticated : 1; + // } + target.addend = (int32_t)(contentValue & 0xFFFFFFFF); + if (parser._supportsAuthenticatedPointers) { + target.authData.discriminator = (uint16_t)(contentValue >> 32); + target.authData.hasAddressDiversity = (contentValue & (1ULL << 48)) != 0; + target.authData.key = (ld::Fixup::AuthData::ptrauth_key)((contentValue >> 49) & 0x3); + } else { + static bool emittedWarning = false; + if (!emittedWarning) { + emittedWarning = true; + warning("stripping authenticated relocation as image uses -preload or -static"); + } + } + bool isAuthenticated = (contentValue & (1ULL << 63)) != 0; + if (!isAuthenticated) + throw "ARM64_RELOC_AUTHENTICATED_POINTER value must have authenticated bit set"; + switch ( reloc->r_length() ) { + case 0: + case 1: + case 2: + throw "length < 3 and ARM64_RELOC_AUTHENTICATED_POINTER not supported"; + case 3: + if (parser._supportsAuthenticatedPointers) + parser.addFixups(src, ld::Fixup::kindStoreLittleEndianAuth64, target); + else + parser.addFixups(src, ld::Fixup::kindStoreLittleEndian64, target); + break; + } + break; + } +#endif default: throwf("unknown relocation type %d", reloc->r_type()); } @@ -7930,34 +8037,34 @@ bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, const ParserO // // used by linker to infer architecture when no -arch is on command line // -bool isObjectFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t* subResult, Options::Platform* platform) +bool isObjectFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t* subResult, ld::Platform* platform, uint32_t* minOsVers) { if ( mach_o::relocatable::Parser::validFile(fileContent) ) { *result = CPU_TYPE_X86_64; const macho_header >* header = (const macho_header >*)fileContent; *subResult = header->cpusubtype(); - *platform = Parser::findPlatform(header); + *platform = Parser::findPlatform(header, minOsVers); return true; } if ( mach_o::relocatable::Parser::validFile(fileContent) ) { const macho_header >* header = (const macho_header >*)fileContent; *result = CPU_TYPE_I386; *subResult = CPU_SUBTYPE_X86_ALL; - *platform = Parser::findPlatform(header); + *platform = Parser::findPlatform(header, minOsVers); return true; } if ( mach_o::relocatable::Parser::validFile(fileContent, false, 0) ) { const macho_header >* header = (const macho_header >*)fileContent; *result = CPU_TYPE_ARM; *subResult = header->cpusubtype(); - *platform = Parser::findPlatform(header); + *platform = Parser::findPlatform(header, minOsVers); return true; } if ( mach_o::relocatable::Parser::validFile(fileContent, false, 0) ) { const macho_header >* header = (const macho_header >*)fileContent; *result = CPU_TYPE_ARM64; *subResult = header->cpusubtype(); - *platform = Parser::findPlatform(header); + *platform = Parser::findPlatform(header, minOsVers); return true; } return false; @@ -8027,9 +8134,11 @@ bool getNonLocalSymbols(const uint8_t* fileContent, std::vector &sy else if ( mach_o::relocatable::Parser::validFile(fileContent, false, 0) ) { return mach_o::relocatable::Parser::getNonLocalSymbols(fileContent, syms); } +#if SUPPORT_ARCH_arm64 else if ( mach_o::relocatable::Parser::validFile(fileContent, false, 0) ) { return mach_o::relocatable::Parser::getNonLocalSymbols(fileContent, syms); } +#endif return false; }