[lld] [lld][AArch64][ELF][PAC] Support AUTH relocations and AUTH ELF marking (PR #72714)
Daniil Kovalev via llvm-commits
llvm-commits at lists.llvm.org
Sun Dec 10 13:30:47 PST 2023
https://github.com/kovdan01 updated https://github.com/llvm/llvm-project/pull/72714
>From c493d78e6c482bb530189de05b79e7082a224fab Mon Sep 17 00:00:00 2001
From: Daniil Kovalev <dkovalev at accesssoftek.com>
Date: Thu, 28 Sep 2023 03:14:35 +0300
Subject: [PATCH] [lld][AArch64][ELF][PAC] Support AUTH relocations and AUTH
ELF marking
This patch adds lld support for:
- Dynamic R_AARCH64_AUTH_* relocations (including RELR compressed AUTH
relocations) as described here:
https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#auth-variant-dynamic-relocations
- .note.AARCH64-PAUTH-ABI-tag section as defined here
https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#elf-marking
Co-authored-by: Peter Collingbourne <peter at pcc.me.uk>
---
lld/ELF/Arch/AArch64.cpp | 5 +
lld/ELF/Config.h | 4 +
lld/ELF/Driver.cpp | 57 +++++++++-
lld/ELF/InputFiles.cpp | 44 ++++++++
lld/ELF/InputFiles.h | 1 +
lld/ELF/Relocations.cpp | 26 +++++
lld/ELF/SyntheticSections.cpp | 44 ++++++--
lld/ELF/SyntheticSections.h | 19 +++-
lld/ELF/Writer.cpp | 17 +++
lld/test/ELF/aarch64-feature-pauth.s | 83 ++++++++++++++
lld/test/ELF/aarch64-ptrauth.s | 156 +++++++++++++++++++++++++++
11 files changed, 445 insertions(+), 11 deletions(-)
create mode 100644 lld/test/ELF/aarch64-feature-pauth.s
create mode 100644 lld/test/ELF/aarch64-ptrauth.s
diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index 048f0ec30ebd28..6828d3f57c10e8 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -112,6 +112,7 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
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 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
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
index 56229334f9a44a..1b633a79842769 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -187,6 +187,7 @@ struct Config {
llvm::StringRef cmseOutputLib;
StringRef zBtiReport = "none";
StringRef zCetReport = "none";
+ StringRef zPauthReport = "none";
llvm::StringRef ltoBasicBlockSections;
std::pair<llvm::StringRef, llvm::StringRef> thinLTOObjectSuffixReplace;
llvm::StringRef thinLTOPrefixReplaceOld;
@@ -275,6 +276,7 @@ struct Config {
bool relocatable;
bool relrGlibc = false;
bool relrPackDynRelocs = false;
+ bool relrPackAuthDynRelocs = false;
llvm::DenseSet<llvm::StringRef> saveTempsArgs;
llvm::SmallVector<std::pair<llvm::GlobPattern, uint32_t>, 0> shuffleSections;
bool singleRoRx;
@@ -492,6 +494,8 @@ struct Ctx {
void reset();
llvm::raw_fd_ostream openAuxiliaryFile(llvm::StringRef, std::error_code &);
+
+ SmallVector<uint8_t, 0> aarch64PauthAbiTag;
};
LLVM_LIBRARY_VISIBILITY extern Ctx ctx;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 6bef09eeca015a..4e8e9eb86ecf77 100644
--- 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 <algorithm>
#include <cstdlib>
#include <tuple>
#include <utility>
@@ -459,6 +460,8 @@ static void checkOptions() {
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 @@ constexpr const char *knownZFlags[] = {
"nognustack",
"nokeep-text-section-prefix",
"nopack-relative-relocs",
+ "nopack-relative-auth-relocs",
"norelro",
"noseparate-code",
"nostart-stop-gc",
@@ -566,6 +570,7 @@ constexpr const char *knownZFlags[] = {
"origin",
"pac-plt",
"pack-relative-relocs",
+ "pack-relative-auth-relocs",
"rel",
"rela",
"relro",
@@ -583,7 +588,7 @@ constexpr const char *knownZFlags[] = {
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 @@ static void readConfigs(opt::InputArgList &args) {
}
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<StringRef, StringRef> option =
StringRef(arg->getValue()).split('=');
@@ -1671,6 +1677,9 @@ static void readConfigs(opt::InputArgList &args) {
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 "
@@ -2639,6 +2648,47 @@ static uint32_t getAndFeatures() {
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<uint8_t, 0> &D1 = ctx.aarch64PauthAbiTag;
+ const SmallVector<uint8_t, 0> &D2 = F->aarch64PauthAbiTag;
+ if (D1.empty() != D2.empty()) {
+ auto Helper = [](StringRef Report, const Twine &Msg) {
+ if (Report == "warning")
+ warn(Msg);
+ else if (Report == "error")
+ error(Msg);
+ };
+
+ Helper(config->zPauthReport,
+ (D1.empty() ? F1.str() : F2.str()) +
+ " has no AArch64 PAuth compatibility info while " +
+ (D1.empty() ? F2.str() : F1.str()) +
+ " has one; either all or no input files must have it");
+ }
+
+ 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:
@@ -2976,6 +3026,9 @@ void LinkerDriver::link(opt::InputArgList &args) {
// 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.cpp b/lld/ELF/InputFiles.cpp
index cc2c5916e05c22..44c8050f2c967a 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -962,6 +962,44 @@ template <class ELFT> static uint32_t readAndFeatures(const InputSection &sec) {
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 <class ELFT>
+static void readAArch64PauthAbiTag(const InputSection &sec, ObjFile<ELFT> &f) {
+ using Elf_Nhdr = typename ELFT::Nhdr;
+ using Elf_Note = typename ELFT::Note;
+ ArrayRef<uint8_t> data = sec.content();
+ auto reportError = [&](const Twine &msg) {
+ errorOrWarn(toString(sec.file) + ":(" + sec.name + "): " + msg);
+ };
+
+ auto *nhdr = reinterpret_cast<const Elf_Nhdr *>(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<uint8_t> 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<uint8_t, 0>(iterator_range(desc));
+}
+
template <class ELFT>
InputSectionBase *ObjFile<ELFT>::getRelocTarget(uint32_t idx,
const Elf_Shdr &sec,
@@ -1020,6 +1058,12 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(uint32_t idx,
return &InputSection::discarded;
}
+ if (config->emachine == EM_AARCH64 &&
+ name == ".note.AARCH64-PAUTH-ABI-tag") {
+ readAArch64PauthAbiTag<ELFT>(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/InputFiles.h b/lld/ELF/InputFiles.h
index ab98d78fcf1455..6a74ba7fb20998 100644
--- a/lld/ELF/InputFiles.h
+++ b/lld/ELF/InputFiles.h
@@ -218,6 +218,7 @@ class ELFFileBase : public InputFile {
public:
uint32_t andFeatures = 0;
bool hasCommonSyms = false;
+ SmallVector<uint8_t, 0> aarch64PauthAbiTag;
};
// .o file.
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index fe3d7f419e84aa..5b5e6b154d52f4 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1444,6 +1444,32 @@ template <class ELFT, class RelTy> void RelocationScanner::scanOne(RelTy *&i) {
}
}
+ if (config->emachine == EM_AARCH64 && type == R_AARCH64_AUTH_ABS64) {
+ // Assume relocations from relocatable objects are RELA.
+ assert(RelTy::IsRela);
+ std::lock_guard<std::mutex> 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.cpp b/lld/ELF/SyntheticSections.cpp
index 2b32eb3a0fe355..fa7589806a7b5b 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -331,6 +331,29 @@ void GnuPropertySection::writeTo(uint8_t *buf) {
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<uint8_t, 0> &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()) {}
@@ -1406,6 +1429,12 @@ DynamicSection<ELFT>::computeContents() {
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
@@ -1717,10 +1746,13 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *buf) {
}
}
-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() {
@@ -1988,8 +2020,8 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
}
template <class ELFT>
-RelrSection<ELFT>::RelrSection(unsigned concurrency)
- : RelrBaseSection(concurrency) {
+RelrSection<ELFT>::RelrSection(unsigned concurrency, bool isAArch64Auth)
+ : RelrBaseSection(concurrency, isAArch64Auth) {
this->entsize = config->wordsize;
}
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 3a9f4ba886f6bb..d183a547c68205 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -144,6 +144,16 @@ class GnuPropertySection final : public SyntheticSection {
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 @@ class RelocationBaseSection : public SyntheticSection {
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<DynamicReloc, 0> relocs;
@@ -599,7 +610,7 @@ struct RelativeReloc {
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 @@ template <class ELFT> class RelrSection final : public RelrBaseSection {
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 @@ struct Partition {
std::unique_ptr<PackageMetadataNote> packageMetadataNote;
std::unique_ptr<RelocationBaseSection> relaDyn;
std::unique_ptr<RelrBaseSection> relrDyn;
+ std::unique_ptr<RelrBaseSection> relrAuthDyn;
std::unique_ptr<VersionDefinitionSection> verDef;
std::unique_ptr<SyntheticSection> verNeed;
std::unique_ptr<VersionTableSection> verSym;
@@ -1363,6 +1375,7 @@ struct InStruct {
std::unique_ptr<StringTableSection> strTab;
std::unique_ptr<SymbolTableBaseSection> symTab;
std::unique_ptr<SymtabShndxSection> symTabShndx;
+ std::unique_ptr<AArch64PauthAbiTag> aarch64PauthAbiTag;
void reset();
};
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index a84e4864ab0e5a..f1b569daada663 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -445,6 +445,12 @@ template <class ELFT> void elf::createSyntheticSections() {
add(*part.relrDyn);
}
+ if (config->relrPackAuthDynRelocs) {
+ part.relrAuthDyn = std::make_unique<RelrSection<ELFT>>(
+ threadCount, /*isAArch64Auth=*/true);
+ add(*part.relrAuthDyn);
+ }
+
if (!config->relocatable) {
if (config->ehFrameHdr) {
part.ehFrameHdr = std::make_unique<EhFrameHeader>();
@@ -566,6 +572,11 @@ template <class ELFT> void elf::createSyntheticSections() {
if (config->andFeatures)
add(*make<GnuPropertySection>());
+ if (!ctx.aarch64PauthAbiTag.empty()) {
+ in.aarch64PauthAbiTag = std::make_unique<AArch64PauthAbiTag>();
+ 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
@@ -1725,6 +1736,8 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
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();
}
@@ -2179,6 +2192,10 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
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
index 00000000000000..0520b2f28631e1
--- /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
index 00000000000000..db946fc4c3e55c
--- /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 at AUTH(da,42)
+.quad bar2 at 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 at AUTH(ia,42)
+.quad bar2 at AUTH(ia,42)
+.quad (bar2 + 1)@AUTH(ia,42)
+.quad (bar2 + 1)@AUTH(ia,42)
+.quad bar2 at AUTH(ia,42)
More information about the llvm-commits
mailing list