diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp --- a/lld/ELF/Arch/AArch64.cpp +++ b/lld/ELF/Arch/AArch64.cpp @@ -112,6 +112,7 @@ case R_AARCH64_MOVW_UABS_G2: case R_AARCH64_MOVW_UABS_G2_NC: case R_AARCH64_MOVW_UABS_G3: + case R_AARCH64_AUTH_ABS64: return R_ABS; case R_AARCH64_TLSDESC_ADR_PAGE21: return R_AARCH64_TLSDESC_PAGE; @@ -395,6 +396,10 @@ case R_AARCH64_PREL64: write64(loc, val); break; + case R_AARCH64_AUTH_ABS64: + checkIntUInt(loc, val, 32, rel); + write32(loc, val); + break; case R_AARCH64_ADD_ABS_LO12_NC: or32AArch64Imm(loc, val); break; diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -269,6 +269,7 @@ bool relocatable; bool relrGlibc = false; bool relrPackDynRelocs = false; + bool relrPackAuthDynRelocs = false; llvm::DenseSet saveTempsArgs; llvm::SmallVector, 0> shuffleSections; bool singleRoRx; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -537,6 +537,7 @@ "nognustack", "nokeep-text-section-prefix", "nopack-relative-relocs", + "nopack-relative-auth-relocs", "norelro", "noseparate-code", "nostart-stop-gc", @@ -545,6 +546,7 @@ "origin", "pac-plt", "pack-relative-relocs", + "pack-relative-auth-relocs", "rel", "rela", "relro", @@ -1576,6 +1578,9 @@ getPackDynRelocs(args); } + config->relrPackAuthDynRelocs = getZFlag( + args, "pack-relative-auth-relocs", "nopack-relative-auth-relocs", false); + if (auto *arg = args.getLastArg(OPT_symbol_ordering_file)){ if (args.hasArg(OPT_call_graph_ordering_file)) error("--symbol-ordering-file and --call-graph-order-file " diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -1438,6 +1438,32 @@ } } + if (config->emachine == EM_AARCH64 && type == R_AARCH64_AUTH_ABS64) { + // Assume relocations from relocatable objects are RELA. + assert(RelTy::IsRela); + std::lock_guard lock(relocMutex); + // For a preemptible symbol, we can't use a relative relocation. For an + // undefined symbol, we can't compute offset at link-time and use a relative + // relocation. Use a symbolic relocation instead. + Partition &part = sec->getPartition(); + if (sym.isPreemptible || sym.isUndefined()) { + part.relaDyn->addSymbolReloc(type, *sec, offset, sym, addend, type); + } else if (part.relrAuthDyn && sec->addralign >= 2 && offset % 2 == 0 && + isInt<32>(sym.getVA(addend))) { + // Implicit addend is below 32-bits so we can use the compressed + // relative relocation section. The R_AARCH64_AUTH_RELATIVE + // has a smaller addend fielf as bits [63:32] encode the signing-schema. + sec->addReloc({expr, type, offset, addend, &sym}); + part.relrAuthDyn->relocsVec[parallel::getThreadIndex()].push_back( + {sec, offset}); + } else { + part.relaDyn->addReloc({R_AARCH64_AUTH_RELATIVE, sec, offset, + DynamicReloc::AddendOnlyWithTargetVA, sym, addend, + R_ABS}); + } + return; + } + // If the relocation does not emit a GOT or GOTPLT entry but its computation // uses their addresses, we need GOT or GOTPLT to be created. // diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -543,7 +543,8 @@ static bool classof(const SectionBase *d) { return SyntheticSection::classof(d) && (d->type == llvm::ELF::SHT_RELA || d->type == llvm::ELF::SHT_REL || - d->type == llvm::ELF::SHT_RELR); + d->type == llvm::ELF::SHT_RELR || + d->type == llvm::ELF::SHT_AARCH64_AUTH_RELR); } int32_t dynamicTag, sizeDynamicTag; SmallVector relocs; @@ -599,7 +600,7 @@ class RelrBaseSection : public SyntheticSection { public: - RelrBaseSection(unsigned concurrency); + RelrBaseSection(unsigned concurrency, bool isAArch64Auth = false); void mergeRels(); bool isNeeded() const override { return !relocs.empty() || @@ -617,7 +618,7 @@ using Elf_Relr = typename ELFT::Relr; public: - RelrSection(unsigned concurrency); + RelrSection(unsigned concurrency, bool isAArch64Auth = false); bool updateAllocSize() override; size_t getSize() const override { return relrRelocs.size() * this->entsize; } @@ -1309,6 +1310,7 @@ std::unique_ptr packageMetadataNote; std::unique_ptr relaDyn; std::unique_ptr relrDyn; + std::unique_ptr relrAuthDyn; std::unique_ptr verDef; std::unique_ptr verNeed; std::unique_ptr verSym; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1405,6 +1405,12 @@ addInt(config->useAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT, sizeof(Elf_Relr)); } + if (part.relrAuthDyn && part.relrAuthDyn->getParent() && + !part.relrAuthDyn->relocs.empty()) { + addInSec(DT_AARCH64_AUTH_RELR, *part.relrAuthDyn); + addInt(DT_AARCH64_AUTH_RELRSZ, part.relrAuthDyn->getParent()->size); + addInt(DT_AARCH64_AUTH_RELRENT, sizeof(Elf_Relr)); + } // .rel[a].plt section usually consists of two parts, containing plt and // iplt relocations. It is possible to have only iplt relocations in the // output. In that case relaPlt is empty and have zero offset, the same offset @@ -1716,10 +1722,13 @@ } } -RelrBaseSection::RelrBaseSection(unsigned concurrency) - : SyntheticSection(SHF_ALLOC, - config->useAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR, - config->wordsize, ".relr.dyn"), +RelrBaseSection::RelrBaseSection(unsigned concurrency, bool isAArch64Auth) + : SyntheticSection( + SHF_ALLOC, + isAArch64Auth + ? SHT_AARCH64_AUTH_RELR + : (config->useAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR), + config->wordsize, isAArch64Auth ? ".relr.auth.dyn" : ".relr.dyn"), relocsVec(concurrency) {} void RelrBaseSection::mergeRels() { @@ -1987,8 +1996,8 @@ } template -RelrSection::RelrSection(unsigned concurrency) - : RelrBaseSection(concurrency) { +RelrSection::RelrSection(unsigned concurrency, bool isAArch64Auth) + : RelrBaseSection(concurrency, isAArch64Auth) { this->entsize = config->wordsize; } diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -397,6 +397,12 @@ add(*part.relrDyn); } + if (config->relrPackAuthDynRelocs) { + part.relrAuthDyn = std::make_unique>( + threadCount, /*isAArch64Auth*/ true); + add(*part.relrAuthDyn); + } + if (!config->relocatable) { if (config->ehFrameHdr) { part.ehFrameHdr = std::make_unique(); @@ -1657,6 +1663,8 @@ changed |= part.relaDyn->updateAllocSize(); if (part.relrDyn) changed |= part.relrDyn->updateAllocSize(); + if (part.relrAuthDyn) + changed |= part.relrAuthDyn->updateAllocSize(); if (part.memtagDescriptors) changed |= part.memtagDescriptors->updateAllocSize(); } @@ -2102,6 +2110,10 @@ part.relrDyn->mergeRels(); finalizeSynthetic(part.relrDyn.get()); } + if (part.relrAuthDyn) { + part.relrAuthDyn->mergeRels(); + finalizeSynthetic(part.relrAuthDyn.get()); + } finalizeSynthetic(part.dynSymTab.get()); finalizeSynthetic(part.gnuHashTab.get()); diff --git a/llvm/include/llvm/BinaryFormat/DynamicTags.def b/llvm/include/llvm/BinaryFormat/DynamicTags.def --- a/llvm/include/llvm/BinaryFormat/DynamicTags.def +++ b/llvm/include/llvm/BinaryFormat/DynamicTags.def @@ -132,6 +132,14 @@ AARCH64_DYNAMIC_TAG(AARCH64_MEMTAG_GLOBALS, 0x7000000d) AARCH64_DYNAMIC_TAG(AARCH64_MEMTAG_GLOBALSSZ, 0x7000000f) +// AArch64 specific dynamic table entries for RELR auth relocations as described here: +// https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#dynamic-section +// FIXME: this should be 0x70000005, but it overlaps with AARCH64_VARIANT_PCS +// See https://reviews.llvm.org/D93044 when it was first introduced. +AARCH64_DYNAMIC_TAG(AARCH64_AUTH_RELRSZ, 0x70000008) +AARCH64_DYNAMIC_TAG(AARCH64_AUTH_RELR, 0x70000006) +AARCH64_DYNAMIC_TAG(AARCH64_AUTH_RELRENT, 0x70000007) + // Hexagon specific dynamic table entries HEXAGON_DYNAMIC_TAG(HEXAGON_SYMSZ, 0x70000000) HEXAGON_DYNAMIC_TAG(HEXAGON_VER, 0x70000001) diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -1056,6 +1056,9 @@ SHT_ARM_ATTRIBUTES = 0x70000003U, SHT_ARM_DEBUGOVERLAY = 0x70000004U, SHT_ARM_OVERLAYSECTION = 0x70000005U, + // Special aarch64-specific section for MTE support, as described in: + // https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#section-types + SHT_AARCH64_AUTH_RELR = 0x70000004U, // Special aarch64-specific sections for MTE support, as described in: // https://github.com/ARM-software/abi-aa/blob/main/memtagabielf64/memtagabielf64.rst#7section-types SHT_AARCH64_MEMTAG_GLOBALS_STATIC = 0x70000007U, diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/AArch64.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/AArch64.def --- a/llvm/include/llvm/BinaryFormat/ELFRelocs/AArch64.def +++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/AArch64.def @@ -135,6 +135,7 @@ ELF_RELOC(R_AARCH64_TLSDESC, 0x407) ELF_RELOC(R_AARCH64_IRELATIVE, 0x408) ELF_RELOC(R_AARCH64_AUTH_ABS64, 0xe100) +ELF_RELOC(R_AARCH64_AUTH_RELATIVE, 0xe200) // ELF_RELOC(R_AARCH64_P32_NONE, 0) ELF_RELOC(R_AARCH64_P32_ABS32, 0x001) diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp --- a/llvm/lib/Object/ELF.cpp +++ b/llvm/lib/Object/ELF.cpp @@ -299,6 +299,7 @@ STRINGIFY_ENUM_CASE(ELF, SHT_GROUP); STRINGIFY_ENUM_CASE(ELF, SHT_SYMTAB_SHNDX); STRINGIFY_ENUM_CASE(ELF, SHT_RELR); + STRINGIFY_ENUM_CASE(ELF, SHT_AARCH64_AUTH_RELR); STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_REL); STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_RELA); STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_RELR); diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -669,6 +669,7 @@ ECase(SHT_GROUP); ECase(SHT_SYMTAB_SHNDX); ECase(SHT_RELR); + ECase(SHT_AARCH64_AUTH_RELR); ECase(SHT_ANDROID_REL); ECase(SHT_ANDROID_RELA); ECase(SHT_ANDROID_RELR); diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -2077,21 +2077,40 @@ break; case ELF::DT_RELR: case ELF::DT_ANDROID_RELR: + case ELF::DT_AARCH64_AUTH_RELR: DynRelrRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); break; case ELF::DT_RELRSZ: case ELF::DT_ANDROID_RELRSZ: + case ELF::DT_AARCH64_AUTH_RELRSZ: DynRelrRegion.Size = Dyn.getVal(); - DynRelrRegion.SizePrintName = Dyn.d_tag == ELF::DT_RELRSZ - ? "DT_RELRSZ value" - : "DT_ANDROID_RELRSZ value"; + DynRelrRegion.SizePrintName = [&Dyn]() { + switch (Dyn.d_tag) { + case ELF::DT_RELRSZ: + return "DT_RELRSZ value"; + case ELF::DT_ANDROID_RELRSZ: + return "DT_ANDROID_RELRSZ value"; + case ELF::DT_AARCH64_AUTH_RELRSZ: + return "DT_AARCH64_AUTH_RELRSZ value"; + } + llvm_unreachable("Unexpected Dyn.d_tag value"); + }(); break; case ELF::DT_RELRENT: case ELF::DT_ANDROID_RELRENT: + case ELF::DT_AARCH64_AUTH_RELRENT: DynRelrRegion.EntSize = Dyn.getVal(); - DynRelrRegion.EntSizePrintName = Dyn.d_tag == ELF::DT_RELRENT - ? "DT_RELRENT value" - : "DT_ANDROID_RELRENT value"; + DynRelrRegion.EntSizePrintName = [&Dyn]() { + switch (Dyn.d_tag) { + case ELF::DT_RELRENT: + return "DT_RELRENT value"; + case ELF::DT_ANDROID_RELRENT: + return "DT_ANDROID_RELRENT value"; + case ELF::DT_AARCH64_AUTH_RELRENT: + return "DT_AARCH64_AUTH_RELRENT value"; + } + llvm_unreachable("Unexpected Dyn.d_tag value"); + }(); break; case ELF::DT_PLTREL: if (Dyn.getVal() == DT_REL) @@ -2454,6 +2473,8 @@ case DT_PREINIT_ARRAYSZ: case DT_RELRSZ: case DT_RELRENT: + case DT_AARCH64_AUTH_RELRSZ: + case DT_AARCH64_AUTH_RELRENT: case DT_ANDROID_RELSZ: case DT_ANDROID_RELASZ: return std::to_string(Value) + " (bytes)"; @@ -3788,7 +3809,8 @@ template static void printRelocHeaderFields(formatted_raw_ostream &OS, unsigned SType) { bool IsRela = SType == ELF::SHT_RELA || SType == ELF::SHT_ANDROID_RELA; - bool IsRelr = SType == ELF::SHT_RELR || SType == ELF::SHT_ANDROID_RELR; + bool IsRelr = SType == ELF::SHT_RELR || SType == ELF::SHT_ANDROID_RELR || + SType == ELF::SHT_AARCH64_AUTH_RELR; if (ELFT::Is64Bits) OS << " "; else @@ -3821,7 +3843,8 @@ return Sec.sh_type == ELF::SHT_REL || Sec.sh_type == ELF::SHT_RELA || Sec.sh_type == ELF::SHT_RELR || Sec.sh_type == ELF::SHT_ANDROID_REL || Sec.sh_type == ELF::SHT_ANDROID_RELA || - Sec.sh_type == ELF::SHT_ANDROID_RELR; + Sec.sh_type == ELF::SHT_ANDROID_RELR || + Sec.sh_type == ELF::SHT_AARCH64_AUTH_RELR; } template void GNUELFDumper::printRelocations() { @@ -3837,8 +3860,9 @@ return RelasOrErr->size(); } - if (!opts::RawRelr && (Sec.sh_type == ELF::SHT_RELR || - Sec.sh_type == ELF::SHT_ANDROID_RELR)) { + if (!opts::RawRelr && + (Sec.sh_type == ELF::SHT_RELR || Sec.sh_type == ELF::SHT_ANDROID_RELR || + Sec.sh_type == ELF::SHT_AARCH64_AUTH_RELR)) { Expected RelrsOrErr = this->Obj.relrs(Sec); if (!RelrsOrErr) return RelrsOrErr.takeError(); @@ -6172,11 +6196,12 @@ toString(std::move(E))); }; - // SHT_RELR/SHT_ANDROID_RELR sections do not have an associated symbol table. - // For them we should not treat the value of the sh_link field as an index of - // a symbol table. + // SHT_RELR/SHT_ANDROID_RELR/SHT_AARCH64_AUTH_RELR sections do not have an + // associated symbol table. For them we should not treat the value of the + // sh_link field as an index of a symbol table. const Elf_Shdr *SymTab; - if (Sec.sh_type != ELF::SHT_RELR && Sec.sh_type != ELF::SHT_ANDROID_RELR) { + if (Sec.sh_type != ELF::SHT_RELR && Sec.sh_type != ELF::SHT_ANDROID_RELR && + Sec.sh_type != ELF::SHT_AARCH64_AUTH_RELR) { Expected SymTabOrErr = Obj.getSection(Sec.sh_link); if (!SymTabOrErr) { Warn(SymTabOrErr.takeError(), "unable to locate a symbol table for"); @@ -6205,6 +6230,7 @@ } break; case ELF::SHT_RELR: + case ELF::SHT_AARCH64_AUTH_RELR: case ELF::SHT_ANDROID_RELR: { Expected RangeOrErr = Obj.relrs(Sec); if (!RangeOrErr) {