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 @@ -187,6 +187,7 @@ llvm::StringRef cmseOutputLib; StringRef zBtiReport = "none"; StringRef zCetReport = "none"; + StringRef zPauthReport = "none"; llvm::StringRef ltoBasicBlockSections; std::pair thinLTOObjectSuffixReplace; llvm::StringRef thinLTOPrefixReplaceOld; @@ -275,6 +276,7 @@ bool relocatable; bool relrGlibc = false; bool relrPackDynRelocs = false; + bool relrPackAuthDynRelocs = false; llvm::DenseSet saveTempsArgs; llvm::SmallVector, 0> shuffleSections; bool singleRoRx; @@ -492,6 +494,8 @@ void reset(); llvm::raw_fd_ostream openAuxiliaryFile(llvm::StringRef, std::error_code &); + + SmallVector aarch64PauthAbiTag; }; LLVM_LIBRARY_VISIBILITY extern Ctx ctx; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -65,6 +65,7 @@ #include "llvm/Support/TargetSelect.h" #include "llvm/Support/TimeProfiler.h" #include "llvm/Support/raw_ostream.h" +#include #include #include #include @@ -459,6 +460,8 @@ error("-z force-bti only supported on AArch64"); if (config->zBtiReport != "none") error("-z bti-report only supported on AArch64"); + if (config->zPauthReport != "none") + error("-z pauth-report only supported on AArch64"); } if (config->emachine != EM_386 && config->emachine != EM_X86_64 && @@ -558,6 +561,7 @@ "nognustack", "nokeep-text-section-prefix", "nopack-relative-relocs", + "nopack-relative-auth-relocs", "norelro", "noseparate-code", "nostart-stop-gc", @@ -566,6 +570,7 @@ "origin", "pac-plt", "pack-relative-relocs", + "pack-relative-auth-relocs", "rel", "rela", "relro", @@ -583,7 +588,7 @@ static bool isKnownZFlag(StringRef s) { return llvm::is_contained(knownZFlags, s) || s.starts_with("common-page-size=") || s.starts_with("bti-report=") || - s.starts_with("cet-report=") || + s.starts_with("cet-report=") || s.starts_with("pauth-report=") || s.starts_with("dead-reloc-in-nonalloc=") || s.starts_with("max-page-size=") || s.starts_with("stack-size=") || s.starts_with("start-stop-visibility="); @@ -1514,7 +1519,8 @@ } auto reports = {std::make_pair("bti-report", &config->zBtiReport), - std::make_pair("cet-report", &config->zCetReport)}; + std::make_pair("cet-report", &config->zCetReport), + std::make_pair("pauth-report", &config->zPauthReport)}; for (opt::Arg *arg : args.filtered(OPT_z)) { std::pair option = StringRef(arg->getValue()).split('='); @@ -1671,6 +1677,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 " @@ -2657,6 +2666,43 @@ return ret; } +static void getAarch64PauthInfo() { + if (ctx.objectFiles.empty()) + return; + + auto NonEmptyIt = std::find_if( + ctx.objectFiles.begin(), ctx.objectFiles.end(), + [](const ELFFileBase *f) { return !f->aarch64PauthAbiTag.empty(); }); + if (NonEmptyIt == ctx.objectFiles.end()) + return; + + ctx.aarch64PauthAbiTag = (*NonEmptyIt)->aarch64PauthAbiTag; + StringRef f1 = (*NonEmptyIt)->getName(); + for (ELFFileBase *f : ArrayRef(ctx.objectFiles)) { + StringRef f2 = f->getName(); + const SmallVector &d1 = ctx.aarch64PauthAbiTag; + const SmallVector &d2 = f->aarch64PauthAbiTag; + if (d1.empty() != d2.empty()) { + Twine Msg = (d1.empty() ? f1 : f2) + + " has no AArch64 PAuth compatibility info while " + + (d1.empty() ? f2 : f1) + + " has one; either all or no input files must have it"; + if (config->zPauthReport == "warning") + warn(Msg); + else if (config->zPauthReport == "error") + error(Msg); + } + + if (!d1.empty() && !d2.empty() && + !std::equal(d1.begin(), d1.end(), d2.begin(), d2.end())) + errorOrWarn( + "incompatible values of AArch64 PAuth compatibility info found" + "\n" + + f1 + ": 0x" + toHex(ArrayRef(d1.data(), d1.size())) + "\n" + f2 + + ": 0x" + toHex(ArrayRef(d2.data(), d2.size()))); + } +} + static void initSectionsAndLocalSyms(ELFFileBase *file, bool ignoreComdats) { switch (file->ekind) { case ELF32LEKind: @@ -2994,6 +3040,9 @@ // contain a hint to tweak linker's and loader's behaviors. config->andFeatures = getAndFeatures(); + if (config->emachine == EM_AARCH64) + getAarch64PauthInfo(); + // The Target instance handles target-specific stuff, such as applying // relocations or writing a PLT section. It also contains target-dependent // values such as a default image base address. diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -218,6 +218,7 @@ public: uint32_t andFeatures = 0; bool hasCommonSyms = false; + SmallVector aarch64PauthAbiTag; }; // .o file. diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -937,6 +937,44 @@ return featuresSet; } +// Extract compatibility info for aarch64 pointer authentication from the +// .note.AARCH64-PAUTH-ABI-tag section and write it to the corresponding ObjFile +// field. See the following ABI documentation: +// https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#elf-marking +template +static void readAArch64PauthAbiTag(const InputSection &sec, ObjFile &f) { + using Elf_Nhdr = typename ELFT::Nhdr; + using Elf_Note = typename ELFT::Note; + ArrayRef data = sec.content(); + auto reportError = [&](const Twine &msg) { + errorOrWarn(toString(sec.file) + ":(" + sec.name + "): " + msg); + }; + + auto *nhdr = reinterpret_cast(data.data()); + if (data.size() < sizeof(Elf_Nhdr) || + data.size() < nhdr->getSize(sec.addralign)) { + reportError("section is too short"); + return; + } + + Elf_Note note(*nhdr); + if (nhdr->n_type != NT_ARM_TYPE_PAUTH_ABI_TAG) + reportError("invalid type field value " + Twine(nhdr->n_type) + " (" + + Twine(NT_ARM_TYPE_PAUTH_ABI_TAG) + " expected)"); + if (note.getName() != "ARM") + reportError("invalid name field value " + note.getName() + + " (ARM expected)"); + + ArrayRef desc = note.getDesc(sec.addralign); + if (desc.size() < 16) { + reportError("too short AArch64 PAuth compatibility info " + "(at least 16 bytes expected)"); + return; + } + + f.aarch64PauthAbiTag = SmallVector(iterator_range(desc)); +} + template InputSectionBase *ObjFile::getRelocTarget(uint32_t idx, const Elf_Shdr &sec, @@ -995,6 +1033,12 @@ return &InputSection::discarded; } + if (config->emachine == EM_AARCH64 && + name == ".note.AARCH64-PAUTH-ABI-tag") { + readAArch64PauthAbiTag(InputSection(*this, sec, name), *this); + return &InputSection::discarded; + } + // Split stacks is a feature to support a discontiguous stack, // commonly used in the programming language Go. For the details, // see https://gcc.gnu.org/wiki/SplitStacks. An object file compiled 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 @@ -144,6 +144,16 @@ size_t getSize() const override; }; +// .note.AARCH64-PAUTH-ABI-tag section. See +// https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#elf-marking +class AArch64PauthAbiTag final : public SyntheticSection { +public: + AArch64PauthAbiTag(); + void writeTo(uint8_t *buf) override; + size_t getSize() const override; + bool isNeeded() const override; +}; + // .note.gnu.build-id section. class BuildIdSection : public SyntheticSection { // First 16 bytes are a header. @@ -543,7 +553,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 +610,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 +628,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; } @@ -1319,6 +1330,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; @@ -1363,6 +1375,7 @@ std::unique_ptr strTab; std::unique_ptr symTab; std::unique_ptr symTabShndx; + std::unique_ptr aarch64PauthAbiTag; void reset(); }; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -331,6 +331,29 @@ size_t GnuPropertySection::getSize() const { return config->is64 ? 32 : 28; } +AArch64PauthAbiTag::AArch64PauthAbiTag() + : SyntheticSection(llvm::ELF::SHF_ALLOC, llvm::ELF::SHT_NOTE, + config->wordsize, ".note.AARCH64-PAUTH-ABI-tag") {} + +bool AArch64PauthAbiTag::isNeeded() const { + return !ctx.aarch64PauthAbiTag.empty(); +} + +void AArch64PauthAbiTag::writeTo(uint8_t *buf) { + const SmallVector &data = ctx.aarch64PauthAbiTag; + write32(buf, 4); // Name size + write32(buf + 4, data.size()); // Content size + write32(buf + 8, NT_ARM_TYPE_PAUTH_ABI_TAG); // Type + memcpy(buf + 12, "ARM", 4); // Name string + memcpy(buf + 16, data.data(), data.size()); + memset(buf + 16 + data.size(), 0, getSize() - 16 - data.size()); // Padding +} + +size_t AArch64PauthAbiTag::getSize() const { + return alignToPowerOf2(16 + ctx.aarch64PauthAbiTag.size(), + config->is64 ? 8 : 4); +} + BuildIdSection::BuildIdSection() : SyntheticSection(SHF_ALLOC, SHT_NOTE, 4, ".note.gnu.build-id"), hashSize(getHashSize()) {} @@ -1405,6 +1428,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 +1745,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 +2019,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(); @@ -518,6 +524,11 @@ if (config->andFeatures) add(*make()); + if (!ctx.aarch64PauthAbiTag.empty()) { + in.aarch64PauthAbiTag = std::make_unique(); + add(*in.aarch64PauthAbiTag); + } + // .note.GNU-stack is always added when we are creating a re-linkable // object file. Other linkers are using the presence of this marker // section to control the executable-ness of the stack area, but that @@ -1679,6 +1690,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(); } @@ -2124,6 +2137,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/lld/test/ELF/aarch64-feature-pauth.s b/lld/test/ELF/aarch64-feature-pauth.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/aarch64-feature-pauth.s @@ -0,0 +1,83 @@ +# REQUIRES: aarch64 + +# RUN: rm -rf %t && split-file %s %t && cd %t + +# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu abi-tag1.s -o tag11.o +# RUN: cp tag11.o tag12.o +# RUN: ld.lld -shared tag11.o tag12.o -o tagok.so +# RUN: llvm-readelf -n tagok.so | FileCheck --check-prefix OK %s + +# OK: AArch64 PAuth ABI tag: platform 0x2a, version 0x1 + +# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu abi-tag2.s -o tag2.o +# RUN: not ld.lld tag11.o tag12.o tag2.o -o /dev/null 2>&1 | FileCheck --check-prefix ERR1 %s + +# ERR1: error: incompatible values of AArch64 PAuth compatibility info found +# ERR1: {{.*}}: 0x2A000000000000000{{1|2}}00000000000000 +# ERR1: {{.*}}: 0x2A000000000000000{{1|2}}00000000000000 + +# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu abi-tag-errs.s -o errs.o +# RUN: not ld.lld errs.o -o /dev/null 2>&1 | FileCheck --check-prefix ERR2 %s + +# ERR2: error: {{.*}}: invalid type field value 42 (1 expected) +# ERR2-NEXT: error: {{.*}}: invalid name field value XXX (ARM expected) +# ERR2-NEXT: error: {{.*}}: too short AArch64 PAuth compatibility info (at least 16 bytes expected) + +# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu abi-tag-short.s -o short.o +# RUN: not ld.lld short.o -o /dev/null 2>&1 | FileCheck --check-prefix ERR3 %s + +# ERR3: error: {{.*}}: section is too short + +# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu no-info.s -o noinfo1.o +# RUN: cp noinfo1.o noinfo2.o +# RUN: not ld.lld -z pauth-report=error tag11.o noinfo1.o noinfo2.o -o /dev/null 2>&1 | FileCheck --check-prefix ERR4 %s +# RUN: ld.lld -z pauth-report=warning tag11.o noinfo1.o noinfo2.o -o /dev/null 2>&1 | FileCheck --check-prefix WARN %s +# RUN: ld.lld -z pauth-report=none tag11.o noinfo1.o noinfo2.o -o /dev/null 2>&1 | FileCheck --check-prefix NONE %s + +# ERR4: error: {{.*}}noinfo1.o has no AArch64 PAuth compatibility info while {{.*}}tag11.o has one; either all or no input files must have it +# ERR4-NEXT: error: {{.*}}noinfo2.o has no AArch64 PAuth compatibility info while {{.*}}tag11.o has one; either all or no input files must have it +# WARN: warning: {{.*}}noinfo1.o has no AArch64 PAuth compatibility info while {{.*}}tag11.o has one; either all or no input files must have it +# WARN-NEXT: warning: {{.*}}noinfo2.o has no AArch64 PAuth compatibility info while {{.*}}tag11.o has one; either all or no input files must have it +# NONE-NOT: {{.*}} has no AArch64 PAuth compatibility info while {{.*}} has one; either all or no input files must have it + +#--- abi-tag-short.s + +.section ".note.AARCH64-PAUTH-ABI-tag", "a" +.long 4 +.long 8 + +#--- abi-tag-errs.s + +.section ".note.AARCH64-PAUTH-ABI-tag", "a" +.long 4 +.long 8 +.long 42 +.asciz "XXX" + +.quad 42 + +#--- abi-tag1.s + +.section ".note.AARCH64-PAUTH-ABI-tag", "a" +.long 4 +.long 16 +.long 1 +.asciz "ARM" + +.quad 42 // platform +.quad 1 // version + +#--- abi-tag2.s + +.section ".note.AARCH64-PAUTH-ABI-tag", "a" +.long 4 +.long 16 +.long 1 +.asciz "ARM" + +.quad 42 // platform +.quad 2 // version + +#--- no-info.s + +.section ".test", "a" diff --git a/lld/test/ELF/aarch64-ptrauth.s b/lld/test/ELF/aarch64-ptrauth.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/aarch64-ptrauth.s @@ -0,0 +1,156 @@ +// REQUIRES: aarch64 + +// RUN: llvm-mc -filetype=obj -triple=aarch64 %p/Inputs/shared2.s -o %t.so.o +// RUN: ld.lld -shared %t.so.o -soname=so -o %t.so +// RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o +// RUN: ld.lld -pie -z nopack-relative-auth-relocs %t.o %t.so -o %t2 +// RUN: llvm-readobj -r %t2 | FileCheck --check-prefix=UNPACKED %s + +// UNPACKED: Section ({{.+}}) .rela.dyn { +// UNPACKED-NEXT: 0x30680 R_AARCH64_AUTH_RELATIVE - 0x1 +// UNPACKED-NEXT: 0x30688 R_AARCH64_AUTH_RELATIVE - 0x2 +// UNPACKED-NEXT: 0x30690 R_AARCH64_AUTH_RELATIVE - 0x3 +// UNPACKED-NEXT: 0x30698 R_AARCH64_AUTH_RELATIVE - 0x4 +// UNPACKED-NEXT: 0x306A0 R_AARCH64_AUTH_RELATIVE - 0x5 +// UNPACKED-NEXT: 0x306A8 R_AARCH64_AUTH_RELATIVE - 0x6 +// UNPACKED-NEXT: 0x306B0 R_AARCH64_AUTH_RELATIVE - 0x7 +// UNPACKED-NEXT: 0x306B8 R_AARCH64_AUTH_RELATIVE - 0x8 +// UNPACKED-NEXT: 0x306C8 R_AARCH64_AUTH_RELATIVE - 0x1 +// UNPACKED-NEXT: 0x306D0 R_AARCH64_AUTH_RELATIVE - 0x2 +// UNPACKED-NEXT: 0x306D8 R_AARCH64_AUTH_RELATIVE - 0x3 +// UNPACKED-NEXT: 0x306E0 R_AARCH64_AUTH_RELATIVE - 0x4 +// UNPACKED-NEXT: 0x306E8 R_AARCH64_AUTH_RELATIVE - 0x5 +// UNPACKED-NEXT: 0x306F0 R_AARCH64_AUTH_RELATIVE - 0x6 +// UNPACKED-NEXT: 0x306F8 R_AARCH64_AUTH_RELATIVE - 0x7 +// UNPACKED-NEXT: 0x30710 R_AARCH64_AUTH_RELATIVE - 0x1 +// UNPACKED-NEXT: 0x30718 R_AARCH64_AUTH_RELATIVE - 0x2 +// UNPACKED-NEXT: 0x30720 R_AARCH64_AUTH_RELATIVE - 0x3 +// UNPACKED-NEXT: 0x30728 R_AARCH64_AUTH_RELATIVE - 0x4 +// UNPACKED-NEXT: 0x30730 R_AARCH64_AUTH_RELATIVE - 0x5 +// UNPACKED-NEXT: 0x30738 R_AARCH64_AUTH_RELATIVE - 0x6 +// UNPACKED-NEXT: 0x30740 R_AARCH64_AUTH_RELATIVE - 0x7 +// UNPACKED-NEXT: 0x30748 R_AARCH64_AUTH_RELATIVE - 0x8 +// UNPACKED-NEXT: 0x30750 R_AARCH64_AUTH_RELATIVE - 0x9 +// UNPACKED-NEXT: 0x30759 R_AARCH64_AUTH_RELATIVE - 0xA +// UNPACKED-NEXT: 0x306C0 R_AARCH64_AUTH_ABS64 bar2 0x1 +// UNPACKED-NEXT: 0x30708 R_AARCH64_AUTH_ABS64 bar2 0x0 +// UNPACKED-NEXT: 0x30761 R_AARCH64_AUTH_ABS64 bar2 0x0 +// UNPACKED-NEXT: 0x30769 R_AARCH64_AUTH_ABS64 bar2 0x0 +// UNPACKED-NEXT: 0x30771 R_AARCH64_AUTH_ABS64 bar2 0x1 +// UNPACKED-NEXT: 0x30779 R_AARCH64_AUTH_ABS64 bar2 0x1 +// UNPACKED-NEXT: 0x30781 R_AARCH64_AUTH_ABS64 bar2 0x0 +// UNPACKED-NEXT: 0x30700 R_AARCH64_AUTH_ABS64 zed2 0x0 +// UNPACKED-NEXT: } + +// RUN: ld.lld -pie -z pack-relative-auth-relocs %t.o %t.so -o %t2 +// RUN: llvm-readobj -S --dynamic-table %t2 | FileCheck --check-prefix=RELR-HEADERS %s +// RUN: llvm-readobj -r --raw-relr %t2 | FileCheck --check-prefix=RAW-RELR %s +// RUN: llvm-readobj -r %t2 | FileCheck --check-prefix=RELR %s + +// RELR-HEADERS: Index: 1 +// RELR-HEADERS-NEXT: Name: .dynsym + +// RELR-HEADERS: Name: .relr.auth.dyn +// RELR-HEADERS-NEXT: Type: SHT_AARCH64_AUTH_RELR +// RELR-HEADERS-NEXT: Flags [ (0x2) +// RELR-HEADERS-NEXT: SHF_ALLOC (0x2) +// RELR-HEADERS-NEXT: ] +// RELR-HEADERS-NEXT: Address: [[ADDR:.*]] +// RELR-HEADERS-NEXT: Offset: [[ADDR]] +// RELR-HEADERS-NEXT: Size: 16 +// RELR-HEADERS-NEXT: Link: 0 +// RELR-HEADERS-NEXT: Info: 0 +// RELR-HEADERS-NEXT: AddressAlignment: 8 +// RELR-HEADERS-NEXT: EntrySize: 8 + +// RELR-HEADERS: 0x0000000070000012 AARCH64_AUTH_RELR [[ADDR]] +// RELR-HEADERS: 0x0000000070000011 AARCH64_AUTH_RELRSZ 16 (bytes) +// RELR-HEADERS: 0x0000000070000013 AARCH64_AUTH_RELRENT 8 (bytes) + +/// SHT_RELR section contains address/bitmap entries +/// encoding the offsets for relative relocation. +// RAW-RELR: Section ({{.+}}) .relr.auth.dyn { +// RAW-RELR-NEXT: 0x30480 +// RAW-RELR-NEXT: 0x7FCFEFF +// RAW-RELR-NEXT: } + +/// Decoded SHT_RELR section is same as UNPACKED, +/// but contains only the relative relocations. +/// Any relative relocations with odd offset stay in SHT_RELA. + +// RELR: Section ({{.+}}) .rela.dyn { +// RELR-NEXT: 0x30559 R_AARCH64_AUTH_RELATIVE - 0xA +// RELR-NEXT: 0x304C0 R_AARCH64_AUTH_ABS64 bar2 0x1 +// RELR-NEXT: 0x30508 R_AARCH64_AUTH_ABS64 bar2 0x0 +// RELR-NEXT: 0x30561 R_AARCH64_AUTH_ABS64 bar2 0x0 +// RELR-NEXT: 0x30569 R_AARCH64_AUTH_ABS64 bar2 0x0 +// RELR-NEXT: 0x30571 R_AARCH64_AUTH_ABS64 bar2 0x1 +// RELR-NEXT: 0x30579 R_AARCH64_AUTH_ABS64 bar2 0x1 +// RELR-NEXT: 0x30581 R_AARCH64_AUTH_ABS64 bar2 0x0 +// RELR-NEXT: 0x30500 R_AARCH64_AUTH_ABS64 zed2 0x0 +// RELR-NEXT: } +// RELR-NEXT: Section ({{.+}}) .relr.auth.dyn { +// RELR-NEXT: 0x30480 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x30488 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x30490 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x30498 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x304A0 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x304A8 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x304B0 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x304B8 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x304C8 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x304D0 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x304D8 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x304E0 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x304E8 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x304F0 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x304F8 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x30510 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x30518 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x30520 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x30528 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x30530 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x30538 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x30540 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x30548 R_AARCH64_RELATIVE - +// RELR-NEXT: 0x30550 R_AARCH64_RELATIVE - +// RELR-NEXT: } + +.section .test, "aw" +.p2align 3 +.quad (__ehdr_start + 1)@AUTH(da,42) +.quad (__ehdr_start + 2)@AUTH(da,42) +.quad (__ehdr_start + 3)@AUTH(da,42) +.quad (__ehdr_start + 4)@AUTH(da,42) +.quad (__ehdr_start + 5)@AUTH(da,42) +.quad (__ehdr_start + 6)@AUTH(da,42) +.quad (__ehdr_start + 7)@AUTH(da,42) +.quad (__ehdr_start + 8)@AUTH(da,42) +.quad (bar2 + 1)@AUTH(ia,42) + +.quad (__ehdr_start + 1)@AUTH(da,65535) +.quad (__ehdr_start + 2)@AUTH(da,65535) +.quad (__ehdr_start + 3)@AUTH(da,65535) +.quad (__ehdr_start + 4)@AUTH(da,65535) +.quad (__ehdr_start + 5)@AUTH(da,65535) +.quad (__ehdr_start + 6)@AUTH(da,65535) +.quad (__ehdr_start + 7)@AUTH(da,65535) +.quad zed2@AUTH(da,42) +.quad bar2@AUTH(ia,42) + +.quad (__ehdr_start + 1)@AUTH(da,0) +.quad (__ehdr_start + 2)@AUTH(da,0) +.quad (__ehdr_start + 3)@AUTH(da,0) +.quad (__ehdr_start + 4)@AUTH(da,0) +.quad (__ehdr_start + 5)@AUTH(da,0) +.quad (__ehdr_start + 6)@AUTH(da,0) +.quad (__ehdr_start + 7)@AUTH(da,0) +.quad (__ehdr_start + 8)@AUTH(da,0) +.quad (__ehdr_start + 9)@AUTH(da,0) +.byte 00 +.quad (__ehdr_start + 10)@AUTH(da,0) +.quad bar2@AUTH(ia,42) +.quad bar2@AUTH(ia,42) +.quad (bar2 + 1)@AUTH(ia,42) +.quad (bar2 + 1)@AUTH(ia,42) +.quad bar2@AUTH(ia,42)