[lld] cca9115 - [lld][AArch64][ELF][PAC] Support AUTH relocations and AUTH ELF marking (#72714)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 4 02:38:14 PDT 2024
Author: Daniil Kovalev
Date: 2024-04-04T12:38:09+03:00
New Revision: cca9115b1c640a307b510821cb84a1f3bb76b969
URL: https://github.com/llvm/llvm-project/commit/cca9115b1c640a307b510821cb84a1f3bb76b969
DIFF: https://github.com/llvm/llvm-project/commit/cca9115b1c640a307b510821cb84a1f3bb76b969.diff
LOG: [lld][AArch64][ELF][PAC] Support AUTH relocations and AUTH ELF marking (#72714)
This patch adds lld support for:
- Dynamic R_AARCH64_AUTH_* relocations (without 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
Depends on #72713 and #85231
---------
Co-authored-by: Peter Collingbourne <peter at pcc.me.uk>
Co-authored-by: Fangrui Song <i at maskray.me>
Added:
lld/test/ELF/aarch64-feature-pauth.s
lld/test/ELF/aarch64-reloc-pauth-ro.s
lld/test/ELF/aarch64-reloc-pauth.s
Modified:
lld/ELF/Arch/AArch64.cpp
lld/ELF/Config.h
lld/ELF/Driver.cpp
lld/ELF/InputFiles.cpp
lld/ELF/InputFiles.h
lld/ELF/InputSection.cpp
lld/ELF/Relocations.cpp
lld/ELF/Relocations.h
lld/ELF/SyntheticSections.cpp
lld/ELF/Writer.cpp
lld/docs/ReleaseNotes.rst
lld/docs/ld.lld.1
lld/test/ELF/aarch64-bti-pac-cli-error.s
Removed:
################################################################################
diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index 30ccd68f7b7506..017c17c2b03d83 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -113,6 +113,8 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
case R_AARCH64_MOVW_UABS_G2_NC:
case R_AARCH64_MOVW_UABS_G3:
return R_ABS;
+ case R_AARCH64_AUTH_ABS64:
+ return R_AARCH64_AUTH;
case R_AARCH64_TLSDESC_ADR_PAGE21:
return R_AARCH64_TLSDESC_PAGE;
case R_AARCH64_TLSDESC_LD64_LO12:
@@ -204,7 +206,7 @@ bool AArch64::usesOnlyLowPageBits(RelType type) const {
}
RelType AArch64::getDynRel(RelType type) const {
- if (type == R_AARCH64_ABS64)
+ if (type == R_AARCH64_ABS64 || type == R_AARCH64_AUTH_ABS64)
return type;
return R_AARCH64_NONE;
}
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 27274d69b7f1f7..83f293ab2ce578 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";
bool ltoBBAddrMap;
llvm::StringRef ltoBasicBlockSections;
std::pair<llvm::StringRef, llvm::StringRef> thinLTOObjectSuffixReplace;
@@ -499,6 +500,8 @@ struct Ctx {
void reset();
llvm::raw_fd_ostream openAuxiliaryFile(llvm::StringRef, std::error_code &);
+
+ ArrayRef<uint8_t> aarch64PauthAbiCoreInfo;
};
LLVM_LIBRARY_VISIBILITY extern Ctx ctx;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index b43da7727e22ae..8dbff7fb86e766 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -46,6 +46,7 @@
#include "lld/Common/Strings.h"
#include "lld/Common/TargetOptionsCommandFlags.h"
#include "lld/Common/Version.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
@@ -461,6 +462,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 &&
@@ -1501,7 +1504,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('=');
@@ -2599,14 +2603,17 @@ static void redirectSymbols(ArrayRef<WrappedSymbol> wrapped) {
symtab.wrap(w.sym, w.real, w.wrap);
}
+static void reportMissingFeature(StringRef config, const Twine &report) {
+ if (config == "error")
+ error(report);
+ else if (config == "warning")
+ warn(report);
+}
+
static void checkAndReportMissingFeature(StringRef config, uint32_t features,
uint32_t mask, const Twine &report) {
- if (!(features & mask)) {
- if (config == "error")
- error(report);
- else if (config == "warning")
- warn(report);
- }
+ if (!(features & mask))
+ reportMissingFeature(config, report);
}
// To enable CET (x86's hardware-assisted control flow enforcement), each
@@ -2617,12 +2624,28 @@ static void checkAndReportMissingFeature(StringRef config, uint32_t features,
//
// This is also the case with AARCH64's BTI and PAC which use the similar
// GNU_PROPERTY_AARCH64_FEATURE_1_AND mechanism.
-static uint32_t getAndFeatures() {
+//
+// For AArch64 PAuth-enabled object files, the core info of all of them must
+// match. Missing info for some object files with matching info for remaining
+// ones can be allowed (see -z pauth-report).
+static void readSecurityNotes() {
if (config->emachine != EM_386 && config->emachine != EM_X86_64 &&
config->emachine != EM_AARCH64)
- return 0;
+ return;
+
+ config->andFeatures = -1;
+
+ StringRef referenceFileName;
+ if (config->emachine == EM_AARCH64) {
+ auto it = llvm::find_if(ctx.objectFiles, [](const ELFFileBase *f) {
+ return !f->aarch64PauthAbiCoreInfo.empty();
+ });
+ if (it != ctx.objectFiles.end()) {
+ ctx.aarch64PauthAbiCoreInfo = (*it)->aarch64PauthAbiCoreInfo;
+ referenceFileName = (*it)->getName();
+ }
+ }
- uint32_t ret = -1;
for (ELFFileBase *f : ctx.objectFiles) {
uint32_t features = f->andFeatures;
@@ -2658,14 +2681,31 @@ static uint32_t getAndFeatures() {
"GNU_PROPERTY_AARCH64_FEATURE_1_PAC property");
features |= GNU_PROPERTY_AARCH64_FEATURE_1_PAC;
}
- ret &= features;
+ config->andFeatures &= features;
+
+ if (ctx.aarch64PauthAbiCoreInfo.empty())
+ continue;
+
+ if (f->aarch64PauthAbiCoreInfo.empty()) {
+ reportMissingFeature(config->zPauthReport,
+ toString(f) +
+ ": -z pauth-report: file does not have AArch64 "
+ "PAuth core info while '" +
+ referenceFileName + "' has one");
+ continue;
+ }
+
+ if (ctx.aarch64PauthAbiCoreInfo != f->aarch64PauthAbiCoreInfo)
+ errorOrWarn("incompatible values of AArch64 PAuth core info found\n>>> " +
+ referenceFileName + ": 0x" +
+ toHex(ctx.aarch64PauthAbiCoreInfo, /*LowerCase=*/true) +
+ "\n>>> " + toString(f) + ": 0x" +
+ toHex(f->aarch64PauthAbiCoreInfo, /*LowerCase=*/true));
}
// Force enable Shadow Stack.
if (config->zShstk)
- ret |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
-
- return ret;
+ config->andFeatures |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
}
static void initSectionsAndLocalSyms(ELFFileBase *file, bool ignoreComdats) {
@@ -2944,7 +2984,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
// Read .note.gnu.property sections from input object files which
// contain a hint to tweak linker's and loader's behaviors.
- config->andFeatures = getAndFeatures();
+ readSecurityNotes();
// The Target instance handles target-specific stuff, such as applying
// relocations or writing a PLT section. It also contains target-dependent
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 6529ea072fae26..1f496026d3ae20 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -926,25 +926,18 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
handleSectionGroup<ELFT>(this->sections, entries);
}
-// If a source file is compiled with x86 hardware-assisted call flow control
-// enabled, the generated object file contains feature flags indicating that
-// fact. This function reads the feature flags and returns it.
-//
-// Essentially we want to read a single 32-bit value in this function, but this
-// function is rather complicated because the value is buried deep inside a
-// .note.gnu.property section.
-//
-// The section consists of one or more NOTE records. Each NOTE record consists
-// of zero or more type-length-value fields. We want to find a field of a
-// certain type. It seems a bit too much to just store a 32-bit value, perhaps
-// the ABI is unnecessarily complicated.
-template <class ELFT> static uint32_t readAndFeatures(const InputSection &sec) {
+// Read the following info from the .note.gnu.property section and write it to
+// the corresponding fields in `ObjFile`:
+// - Feature flags (32 bits) representing x86 or AArch64 features for
+// hardware-assisted call flow control;
+// - AArch64 PAuth ABI core info (16 bytes).
+template <class ELFT>
+void readGnuProperty(const InputSection &sec, ObjFile<ELFT> &f) {
using Elf_Nhdr = typename ELFT::Nhdr;
using Elf_Note = typename ELFT::Note;
- uint32_t featuresSet = 0;
ArrayRef<uint8_t> data = sec.content();
- auto reportFatal = [&](const uint8_t *place, const char *msg) {
+ auto reportFatal = [&](const uint8_t *place, const Twine &msg) {
fatal(toString(sec.file) + ":(" + sec.name + "+0x" +
Twine::utohexstr(place - sec.content().data()) + "): " + msg);
};
@@ -983,7 +976,19 @@ template <class ELFT> static uint32_t readAndFeatures(const InputSection &sec) {
// accumulate the bits set.
if (size < 4)
reportFatal(place, "FEATURE_1_AND entry is too short");
- featuresSet |= read32<ELFT::Endianness>(desc.data());
+ f.andFeatures |= read32<ELFT::Endianness>(desc.data());
+ } else if (config->emachine == EM_AARCH64 &&
+ type == GNU_PROPERTY_AARCH64_FEATURE_PAUTH) {
+ if (!f.aarch64PauthAbiCoreInfo.empty()) {
+ reportFatal(data.data(),
+ "multiple GNU_PROPERTY_AARCH64_FEATURE_PAUTH entries are "
+ "not supported");
+ } else if (size != 16) {
+ reportFatal(data.data(), "GNU_PROPERTY_AARCH64_FEATURE_PAUTH entry "
+ "is invalid: expected 16 bytes, but got " +
+ Twine(size));
+ }
+ f.aarch64PauthAbiCoreInfo = desc;
}
// Padding is present in the note descriptor, if necessary.
@@ -993,8 +998,6 @@ template <class ELFT> static uint32_t readAndFeatures(const InputSection &sec) {
// Go to next NOTE record to look for more FEATURE_1_AND descriptions.
data = data.slice(nhdr->getSize(sec.addralign));
}
-
- return featuresSet;
}
template <class ELFT>
@@ -1051,7 +1054,7 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(uint32_t idx,
// .note.gnu.property containing a single AND'ed bitmap, we discard an input
// file's .note.gnu.property section.
if (name == ".note.gnu.property") {
- this->andFeatures = readAndFeatures<ELFT>(InputSection(*this, sec, name));
+ readGnuProperty<ELFT>(InputSection(*this, sec, name), *this);
return &InputSection::discarded;
}
diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h
index 95197599a2e10d..834b3b63dd83b4 100644
--- a/lld/ELF/InputFiles.h
+++ b/lld/ELF/InputFiles.h
@@ -230,6 +230,7 @@ class ELFFileBase : public InputFile {
public:
uint32_t andFeatures = 0;
bool hasCommonSyms = false;
+ ArrayRef<uint8_t> aarch64PauthAbiCoreInfo;
};
// .o file.
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 4f88313b868b24..c06816bcfd5616 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -676,6 +676,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
case R_DTPREL:
case R_RELAX_TLS_LD_TO_LE_ABS:
case R_RELAX_GOT_PC_NOPIC:
+ case R_AARCH64_AUTH:
case R_RISCV_ADD:
case R_RISCV_LEB128:
return sym.getVA(a);
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 92f2e200db1107..55274344f88119 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -995,7 +995,8 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
if (e == R_GOT || e == R_PLT)
return target->usesOnlyLowPageBits(type) || !config->isPic;
- if (sym.isPreemptible)
+ // R_AARCH64_AUTH_ABS64 requires a dynamic relocation.
+ if (sym.isPreemptible || e == R_AARCH64_AUTH)
return false;
if (!config->isPic)
return true;
@@ -1141,12 +1142,26 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
(rel == target->symbolicRel && !sym.isPreemptible)) {
addRelativeReloc<true>(*sec, offset, sym, addend, expr, type);
return;
- } else if (rel != 0) {
+ }
+ if (rel != 0) {
if (config->emachine == EM_MIPS && rel == target->symbolicRel)
rel = target->relativeRel;
std::lock_guard<std::mutex> lock(relocMutex);
- sec->getPartition().relaDyn->addSymbolReloc(rel, *sec, offset, sym,
- addend, type);
+ Partition &part = sec->getPartition();
+ if (config->emachine == EM_AARCH64 && type == R_AARCH64_AUTH_ABS64) {
+ // 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.
+ if (sym.isPreemptible) {
+ part.relaDyn->addSymbolReloc(type, *sec, offset, sym, addend, type);
+ } else {
+ part.relaDyn->addReloc({R_AARCH64_AUTH_RELATIVE, sec, offset,
+ DynamicReloc::AddendOnlyWithTargetVA, sym,
+ addend, R_ABS});
+ }
+ return;
+ }
+ part.relaDyn->addSymbolReloc(rel, *sec, offset, sym, addend, type);
// MIPS ABI turns using of GOT and dynamic relocations inside out.
// While regular ABI uses dynamic relocations to fill up GOT entries
@@ -1171,7 +1186,10 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
// When producing an executable, we can perform copy relocations (for
// STT_OBJECT) and canonical PLT (for STT_FUNC) if sym is defined by a DSO.
- if (!config->shared && sym.isShared()) {
+ // Copy relocations/canonical PLT entries are unsupported for
+ // R_AARCH64_AUTH_ABS64.
+ if (!config->shared && sym.isShared() &&
+ !(config->emachine == EM_AARCH64 && type == R_AARCH64_AUTH_ABS64)) {
if (!canDefineSymbolInExecutable(sym)) {
errorOrWarn("cannot preempt symbol: " + toString(sym) +
getLocation(*sec, sym, offset));
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index 7eb8a811e6934f..b7b9c09e1b8922 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -87,6 +87,7 @@ enum RelExpr {
R_AARCH64_PAGE_PC,
R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
R_AARCH64_TLSDESC_PAGE,
+ R_AARCH64_AUTH,
R_ARM_PCA,
R_ARM_SBREL,
R_MIPS_GOTREL,
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index d4dc713b4e2703..4427a120086809 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -314,22 +314,42 @@ GnuPropertySection::GnuPropertySection()
config->wordsize, ".note.gnu.property") {}
void GnuPropertySection::writeTo(uint8_t *buf) {
+ write32(buf, 4); // Name size
+ write32(buf + 4, getSize() - 16); // Content size
+ write32(buf + 8, NT_GNU_PROPERTY_TYPE_0); // Type
+ memcpy(buf + 12, "GNU", 4); // Name string
+
uint32_t featureAndType = config->emachine == EM_AARCH64
? GNU_PROPERTY_AARCH64_FEATURE_1_AND
: GNU_PROPERTY_X86_FEATURE_1_AND;
- write32(buf, 4); // Name size
- write32(buf + 4, config->is64 ? 16 : 12); // Content size
- write32(buf + 8, NT_GNU_PROPERTY_TYPE_0); // Type
- memcpy(buf + 12, "GNU", 4); // Name string
- write32(buf + 16, featureAndType); // Feature type
- write32(buf + 20, 4); // Feature size
- write32(buf + 24, config->andFeatures); // Feature flags
- if (config->is64)
- write32(buf + 28, 0); // Padding
+ unsigned offset = 16;
+ if (config->andFeatures != 0) {
+ write32(buf + offset + 0, featureAndType); // Feature type
+ write32(buf + offset + 4, 4); // Feature size
+ write32(buf + offset + 8, config->andFeatures); // Feature flags
+ if (config->is64)
+ write32(buf + offset + 12, 0); // Padding
+ offset += 16;
+ }
+
+ if (!ctx.aarch64PauthAbiCoreInfo.empty()) {
+ write32(buf + offset + 0, GNU_PROPERTY_AARCH64_FEATURE_PAUTH);
+ write32(buf + offset + 4, ctx.aarch64PauthAbiCoreInfo.size());
+ memcpy(buf + offset + 8, ctx.aarch64PauthAbiCoreInfo.data(),
+ ctx.aarch64PauthAbiCoreInfo.size());
+ }
}
-size_t GnuPropertySection::getSize() const { return config->is64 ? 32 : 28; }
+size_t GnuPropertySection::getSize() const {
+ uint32_t contentSize = 0;
+ if (config->andFeatures != 0)
+ contentSize += config->is64 ? 16 : 12;
+ if (!ctx.aarch64PauthAbiCoreInfo.empty())
+ contentSize += 4 + 4 + ctx.aarch64PauthAbiCoreInfo.size();
+ assert(contentSize != 0);
+ return contentSize + 16;
+}
BuildIdSection::BuildIdSection()
: SyntheticSection(SHF_ALLOC, SHT_NOTE, 4, ".note.gnu.build-id"),
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 40d617b7fdf324..fc9084f40044df 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -24,6 +24,7 @@
#include "lld/Common/CommonLinkerContext.h"
#include "lld/Common/Filesystem.h"
#include "lld/Common/Strings.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/BLAKE3.h"
#include "llvm/Support/Parallel.h"
@@ -564,7 +565,7 @@ template <class ELFT> void elf::createSyntheticSections() {
in.iplt = std::make_unique<IpltSection>();
add(*in.iplt);
- if (config->andFeatures)
+ if (config->andFeatures || !ctx.aarch64PauthAbiCoreInfo.empty())
add(*make<GnuPropertySection>());
// .note.GNU-stack is always added when we are creating a re-linkable
diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst
index 97ed0604891005..bf0c8e55d103e8 100644
--- a/lld/docs/ReleaseNotes.rst
+++ b/lld/docs/ReleaseNotes.rst
@@ -29,6 +29,9 @@ ELF Improvements
* ``--compress-sections <section-glib>=[none|zlib|zstd]`` is added to compress
matched output sections without the ``SHF_ALLOC`` flag.
(`#84855 <https://github.com/llvm/llvm-project/pull/84855>`_)
+* ``GNU_PROPERTY_AARCH64_FEATURE_PAUTH`` notes, ``R_AARCH64_AUTH_ABS64`` and
+ ``R_AARCH64_AUTH_RELATIVE`` relocations are now supported.
+ (`#72714 <https://github.com/llvm/llvm-project/pull/72714>`_)
Breaking changes
----------------
diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1
index 65e50e349c8cc0..e0316730f442ed 100644
--- a/lld/docs/ld.lld.1
+++ b/lld/docs/ld.lld.1
@@ -762,6 +762,11 @@ Specify how to report the missing GNU_PROPERTY_X86_FEATURE_1_IBT or GNU_PROPERTY
.Cm none
is the default, linker will not report the missing property otherwise will be reported as a warning or an error.
.Pp
+.It Cm pauth-report Ns = Ns Ar [none|warning|error]
+Specify how to report the missing GNU_PROPERTY_AARCH64_FEATURE_PAUTH property.
+.Cm none
+is the default, linker will not report the missing property otherwise will be reported as a warning or an error.
+.Pp
.It Cm force-bti
Force enable AArch64 BTI instruction in PLT, warn if Input ELF file does not have GNU_PROPERTY_AARCH64_FEATURE_1_BTI property.
.Pp
diff --git a/lld/test/ELF/aarch64-bti-pac-cli-error.s b/lld/test/ELF/aarch64-bti-pac-cli-error.s
index b8ab1a28fa5a86..703c0aac6ea5ac 100644
--- a/lld/test/ELF/aarch64-bti-pac-cli-error.s
+++ b/lld/test/ELF/aarch64-bti-pac-cli-error.s
@@ -1,17 +1,22 @@
# REQUIRES: x86
# RUN: llvm-mc --triple=x86_64-pc-linux --filetype=obj -o %t.o %s
-# RUN: not ld.lld -z pac-plt -z force-bti -z bti-report=error %t.o -o /dev/null 2>&1 | FileCheck %s
+# RUN: not ld.lld -z pac-plt -z force-bti -z bti-report=error \
+# RUN: -z pauth-report=error %t.o -o /dev/null 2>&1 | FileCheck %s
+# RUN: not ld.lld -z pac-plt -z force-bti -z bti-report=warning \
+# RUN: -z pauth-report=warning %t.o -o /dev/null 2>&1 | FileCheck %s
#
-## Check that we error if -z pac-plt, -z force-bti and -z bti-report=error are used when target is not
-## aarch64
+## Check that we error if -z pac-plt, -z force-bti are present and
+## -z bti-report and -z pauth-report are not none when target is not aarch64
# CHECK: error: -z pac-plt only supported on AArch64
# CHECK-NEXT: error: -z force-bti only supported on AArch64
# CHECK-NEXT: error: -z bti-report only supported on AArch64
+# CHECK-NEXT: error: -z pauth-report only supported on AArch64
-# RUN: not ld.lld -z bti-report=something %t.o -o /dev/null 2>&1 | \
-# RUN: FileCheck --check-prefix=REPORT_INVALID %s
+# RUN: not ld.lld -z bti-report=something -z pauth-report=something \
+# RUN: %t.o -o /dev/null 2>&1 | FileCheck --check-prefix=REPORT_INVALID %s
# REPORT_INVALID: error: -z bti-report= parameter something is not recognized
+# REPORT_INVALID: error: -z pauth-report= parameter something is not recognized
# REPORT_INVALID-EMPTY:
.globl start
diff --git a/lld/test/ELF/aarch64-feature-pauth.s b/lld/test/ELF/aarch64-feature-pauth.s
new file mode 100644
index 00000000000000..699a650d72295a
--- /dev/null
+++ b/lld/test/ELF/aarch64-feature-pauth.s
@@ -0,0 +1,114 @@
+# 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 tag1.o
+# RUN: cp tag1.o tag1a.o
+# RUN: ld.lld -shared tag1.o tag1a.o -o tagok.so
+# RUN: llvm-readelf -n tagok.so | FileCheck --check-prefix OK %s
+
+# OK: AArch64 PAuth ABI core info: platform 0x2a (unknown), version 0x1
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu abi-tag2.s -o tag2.o
+# RUN: not ld.lld tag1.o tag1a.o tag2.o -o /dev/null 2>&1 | FileCheck --check-prefix ERR1 %s
+
+# ERR1: error: incompatible values of AArch64 PAuth core info found
+# ERR1-NEXT: >>> tag1.o: 0x2a000000000000000{{1|2}}00000000000000
+# ERR1-NEXT: >>> tag2.o: 0x2a000000000000000{{1|2}}00000000000000
+
+# 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 ERR2 %s
+
+# ERR2: error: short.o:(.note.gnu.property+0x0): GNU_PROPERTY_AARCH64_FEATURE_PAUTH entry is invalid: expected 16 bytes, but got 12
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu abi-tag-long.s -o long.o
+# RUN: not ld.lld long.o -o /dev/null 2>&1 | FileCheck --check-prefix ERR3 %s
+
+# ERR3: error: long.o:(.note.gnu.property+0x0): GNU_PROPERTY_AARCH64_FEATURE_PAUTH entry is invalid: expected 16 bytes, but got 24
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu abi-tag-multiple.s -o multiple.o
+# RUN: not ld.lld multiple.o -o /dev/null 2>&1 | FileCheck --check-prefix ERR4 %s
+# ERR4: error: multiple.o:(.note.gnu.property+0x0): multiple GNU_PROPERTY_AARCH64_FEATURE_PAUTH entries are not supported
+
+# 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 noinfo1.o tag1.o noinfo2.o -o /dev/null 2>&1 | FileCheck --check-prefix ERR5 %s
+# RUN: ld.lld -z pauth-report=warning noinfo1.o tag1.o noinfo2.o -o /dev/null 2>&1 | FileCheck --check-prefix WARN %s
+# RUN: ld.lld -z pauth-report=none noinfo1.o tag1.o noinfo2.o --fatal-warnings -o /dev/null
+
+# ERR5: error: noinfo1.o: -z pauth-report: file does not have AArch64 PAuth core info while 'tag1.o' has one
+# ERR5-NEXT: error: noinfo2.o: -z pauth-report: file does not have AArch64 PAuth core info while 'tag1.o' has one
+# WARN: warning: noinfo1.o: -z pauth-report: file does not have AArch64 PAuth core info while 'tag1.o' has one
+# WARN-NEXT: warning: noinfo2.o: -z pauth-report: file does not have AArch64 PAuth core info while 'tag1.o' has one
+
+#--- abi-tag-short.s
+
+.section ".note.gnu.property", "a"
+.long 4
+.long 20
+.long 5
+.asciz "GNU"
+.long 0xc0000001
+.long 12
+.quad 2
+.long 31
+
+#--- abi-tag-long.s
+
+.section ".note.gnu.property", "a"
+.long 4
+.long 32
+.long 5
+.asciz "GNU"
+.long 0xc0000001
+.long 24
+.quad 2
+.quad 31
+.quad 0
+
+#--- abi-tag-multiple.s
+
+.section ".note.gnu.property", "a"
+.long 4
+.long 48
+.long 5
+.asciz "GNU"
+.long 0xc0000001
+.long 16
+.quad 42 // platform
+.quad 1 // version
+.long 0xc0000001
+.long 16
+.quad 42 // platform
+.quad 1 // version
+
+#--- abi-tag1.s
+
+.section ".note.gnu.property", "a"
+.long 4
+.long 24
+.long 5
+.asciz "GNU"
+.long 0xc0000001
+.long 16
+.quad 42 // platform
+.quad 1 // version
+
+#--- abi-tag2.s
+
+.section ".note.gnu.property", "a"
+.long 4
+.long 24
+.long 5
+.asciz "GNU"
+.long 0xc0000001
+.long 16
+.quad 42 // platform
+.quad 2 // version
+
+#--- no-info.s
+
+## define _start to avoid missing entry warning and use --fatal-warnings to assert no diagnostic
+## allow multiple definitions of _start for simplicity
+.weak _start;
+_start:
diff --git a/lld/test/ELF/aarch64-reloc-pauth-ro.s b/lld/test/ELF/aarch64-reloc-pauth-ro.s
new file mode 100644
index 00000000000000..1be78ba4666e9f
--- /dev/null
+++ b/lld/test/ELF/aarch64-reloc-pauth-ro.s
@@ -0,0 +1,22 @@
+# 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: not ld.lld -pie %t.o %t.so -o %t2 2>&1 | FileCheck -DFILE=%t %s --implicit-check-not=error:
+
+# CHECK: error: relocation R_AARCH64_AUTH_ABS64 cannot be used against symbol 'zed2'; recompile with -fPIC
+# CHECK-NEXT: >>> defined in [[FILE]].so
+# CHECK-NEXT: >>> referenced by [[FILE]].o:(.ro+0x0)
+
+# CHECK: error: relocation R_AARCH64_AUTH_ABS64 cannot be used against symbol 'bar2'; recompile with -fPIC
+# CHECK: error: relocation R_AARCH64_AUTH_ABS64 cannot be used against local symbol; recompile with -fPIC
+
+foo:
+.type foo, @function
+
+.section .ro, "a"
+.p2align 3
+.quad zed2 at AUTH(da,42)
+.quad bar2 at AUTH(ia,42)
+.quad foo at AUTH(ia,42)
diff --git a/lld/test/ELF/aarch64-reloc-pauth.s b/lld/test/ELF/aarch64-reloc-pauth.s
new file mode 100644
index 00000000000000..b603d8ffdcabd3
--- /dev/null
+++ b/lld/test/ELF/aarch64-reloc-pauth.s
@@ -0,0 +1,108 @@
+# REQUIRES: aarch64
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64 %p/Inputs/shared2.s -o %t.a.o
+# RUN: ld.lld -shared %t.a.o -soname=so -o %t.a.so
+# RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o
+
+# RUN: ld.lld -pie %t.o %t.a.so -o %t
+# RUN: llvm-readobj -r %t | FileCheck --check-prefix=UNPACKED %s
+
+# UNPACKED: Section ({{.+}}) .rela.dyn {
+# UNPACKED-NEXT: 0x30470 R_AARCH64_AUTH_RELATIVE - 0x1
+# UNPACKED-NEXT: 0x30478 R_AARCH64_AUTH_RELATIVE - 0x30472
+# UNPACKED-NEXT: 0x30480 R_AARCH64_AUTH_RELATIVE - 0xFFFFFFFFFFFFFFFD
+# UNPACKED-NEXT: 0x30488 R_AARCH64_AUTH_RELATIVE - 0x12345678
+# UNPACKED-NEXT: 0x30490 R_AARCH64_AUTH_RELATIVE - 0x123456789A
+# UNPACKED-NEXT: 0x30498 R_AARCH64_AUTH_RELATIVE - 0xFFFFFFEDCBA98766
+# UNPACKED-NEXT: 0x304A0 R_AARCH64_AUTH_RELATIVE - 0x8003046F
+# UNPACKED-NEXT: 0x304B9 R_AARCH64_AUTH_RELATIVE - 0x4
+# UNPACKED-NEXT: 0x304C2 R_AARCH64_AUTH_RELATIVE - 0x30475
+# UNPACKED-NEXT: 0x304A8 R_AARCH64_AUTH_ABS64 zed2 0x1111
+# UNPACKED-NEXT: 0x304B0 R_AARCH64_AUTH_ABS64 bar2 0x0
+# UNPACKED-NEXT: }
+
+# RUN: ld.lld %t.o %t.a.so -o %t.nopie
+# RUN: llvm-readobj -r %t.nopie | FileCheck --check-prefix=NOPIE %s
+
+# NOPIE: Section ({{.+}}) .rela.dyn {
+# NOPIE: 0x230460 R_AARCH64_AUTH_RELATIVE - 0x200001
+# NOPIE-NEXT: 0x230468 R_AARCH64_AUTH_RELATIVE - 0x230462
+# NOPIE-NEXT: 0x230470 R_AARCH64_AUTH_RELATIVE - 0x1FFFFD
+# NOPIE-NEXT: 0x230478 R_AARCH64_AUTH_RELATIVE - 0x12545678
+# NOPIE-NEXT: 0x230480 R_AARCH64_AUTH_RELATIVE - 0x123476789A
+# NOPIE-NEXT: 0x230488 R_AARCH64_AUTH_RELATIVE - 0xFFFFFFEDCBC98766
+# NOPIE-NEXT: 0x230490 R_AARCH64_AUTH_RELATIVE - 0x8023045F
+# NOPIE-NEXT: 0x2304A9 R_AARCH64_AUTH_RELATIVE - 0x200004
+# NOPIE-NEXT: 0x2304B2 R_AARCH64_AUTH_RELATIVE - 0x230465
+# NOPIE-NEXT: 0x230498 R_AARCH64_AUTH_ABS64 zed2 0x1111
+# NOPIE-NEXT: 0x2304A0 R_AARCH64_AUTH_ABS64 bar2 0x0
+# NOPIE-NEXT: }
+
+# RUN: ld.lld -pie %t.o %t.a.so -o %t.pie
+# RUN: llvm-readelf -S -d -r -x .test %t.pie | FileCheck --check-prefixes=PIE,HEX %s
+
+# PIE: Section Headers:
+# PIE-NEXT: Name Type Address Off Size ES Flg Lk Inf Al
+# PIE: .rela.dyn RELA {{0*}}[[#%x,ADDR1:]]
+# PIE-SAME: {{0*}}[[#ADDR1]] 000108 18 A 1 0 8
+
+# PIE: Relocation section '.rela.dyn' at offset 0x[[#ADDR1]] contains 11 entries:
+# PIE-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend
+# PIE-NEXT: 0000000000030470 0000000000000411 R_AARCH64_AUTH_RELATIVE 1
+# PIE-NEXT: 0000000000030478 0000000000000411 R_AARCH64_AUTH_RELATIVE 30472
+# PIE-NEXT: 0000000000030480 0000000000000411 R_AARCH64_AUTH_RELATIVE fffffffffffffffd
+# PIE-NEXT: 0000000000030488 0000000000000411 R_AARCH64_AUTH_RELATIVE 12345678
+# PIE-NEXT: 0000000000030490 0000000000000411 R_AARCH64_AUTH_RELATIVE 123456789a
+# PIE-NEXT: 0000000000030498 0000000000000411 R_AARCH64_AUTH_RELATIVE ffffffedcba98766
+# PIE-NEXT: 00000000000304a0 0000000000000411 R_AARCH64_AUTH_RELATIVE 8003046f
+# PIE-NEXT: 00000000000304b9 0000000000000411 R_AARCH64_AUTH_RELATIVE 4
+# PIE-NEXT: 00000000000304c2 0000000000000411 R_AARCH64_AUTH_RELATIVE 30475
+# PIE-NEXT: 00000000000304a8 0000000100000244 R_AARCH64_AUTH_ABS64 0000000000000000 zed2 + 1111
+# PIE-NEXT: 00000000000304b0 0000000200000244 R_AARCH64_AUTH_ABS64 0000000000000000 bar2 + 0
+
+# HEX: Hex dump of section '.test':
+# HEX-NEXT: 0x00030470 00000000 2a000020 00000000 2b000000
+## ^^^^ Discr = 42
+## ^^ Key (bits 5..6) = DA
+## ^^^^ Discr = 43
+## ^^ Key (bits 5..6) = IA
+# HEX-NEXT: 0x00030480 00000000 2c000080 00000000 2d000020
+## ^^^^ Discr = 44
+## ^^ Key (bits 5..6) = IA
+## ^^ Addr diversity (bit 7) = true
+## ^^^^ Discr = 45
+## ^^ Key (bits 5..6) = DA
+# HEX-NEXT: 0x00030490 00000000 2e000020 00000000 2f000020
+## ^^^^ Discr = 46
+## ^^ Key (bits 5..6) = DA
+## ^^^^ Discr = 47
+## ^^ Key (bits 5..6) = DA
+# HEX-NEXT: 0x000304a0 00000000 30000020 00000000 31000020
+## ^^^^ Discr = 48
+## ^^ Key (bits 5..6) = DA
+## ^^^^ Discr = 49
+## ^^ Key (bits 5..6) = DA
+# HEX-NEXT: 0x000304b0 00000000 32000000 77000000 00330000
+## ^^^^ Discr = 50
+## ^^ Key (bits 5..6) = IA
+## ^^^^ Discr = 51
+# HEX-NEXT: 0x000304c0 20770000 00003400 0020{{\ }}
+## ^^ Key (bits 5..6) = DA
+## ^^^^ Discr = 52
+## ^^ Key (bits 5..6) = DA
+
+.section .test, "aw"
+.p2align 3
+.quad (__ehdr_start + 1)@AUTH(da,42)
+.quad (.test + 2)@AUTH(ia,43)
+.quad (__ehdr_start - 3)@AUTH(ia,44,addr)
+.quad (__ehdr_start + 0x12345678)@AUTH(da,45)
+.quad (__ehdr_start + 0x123456789A)@AUTH(da,46)
+.quad (__ehdr_start - 0x123456789A)@AUTH(da,47)
+.quad (.test + 0x7FFFFFFF)@AUTH(da,48)
+.quad (zed2 + 0x1111)@AUTH(da,49)
+.quad bar2 at AUTH(ia,50)
+.byte 0x77
+.quad (__ehdr_start + 4)@AUTH(da,51)
+.byte 0x77
+.quad (.test + 5)@AUTH(da,52)
More information about the llvm-commits
mailing list