Skip to content

Commit

Permalink
[lld][AArch64][ELF][PAC] Support AUTH relocations and AUTH ELF marking (
Browse files Browse the repository at this point in the history
#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 <[email protected]>
Co-authored-by: Fangrui Song <[email protected]>
3 people authored Apr 4, 2024
1 parent 7a8cf95 commit cca9115
Showing 16 changed files with 403 additions and 56 deletions.
4 changes: 3 additions & 1 deletion lld/ELF/Arch/AArch64.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
3 changes: 3 additions & 0 deletions lld/ELF/Config.h
Original file line number Diff line number Diff line change
@@ -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;
70 changes: 55 additions & 15 deletions lld/ELF/Driver.cpp
Original file line number Diff line number Diff line change
@@ -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
41 changes: 22 additions & 19 deletions lld/ELF/InputFiles.cpp
Original file line number Diff line number Diff line change
@@ -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;
}

1 change: 1 addition & 0 deletions lld/ELF/InputFiles.h
Original file line number Diff line number Diff line change
@@ -230,6 +230,7 @@ class ELFFileBase : public InputFile {
public:
uint32_t andFeatures = 0;
bool hasCommonSyms = false;
ArrayRef<uint8_t> aarch64PauthAbiCoreInfo;
};

// .o file.
1 change: 1 addition & 0 deletions lld/ELF/InputSection.cpp
Original file line number Diff line number Diff line change
@@ -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);
28 changes: 23 additions & 5 deletions lld/ELF/Relocations.cpp
Original file line number Diff line number Diff line change
@@ -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));
1 change: 1 addition & 0 deletions lld/ELF/Relocations.h
Original file line number Diff line number Diff line change
@@ -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,
40 changes: 30 additions & 10 deletions lld/ELF/SyntheticSections.cpp
Original file line number Diff line number Diff line change
@@ -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"),
3 changes: 2 additions & 1 deletion lld/ELF/Writer.cpp
Original file line number Diff line number Diff line change
@@ -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
3 changes: 3 additions & 0 deletions lld/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
@@ -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
----------------
5 changes: 5 additions & 0 deletions lld/docs/ld.lld.1
Original file line number Diff line number Diff line change
@@ -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
15 changes: 10 additions & 5 deletions lld/test/ELF/aarch64-bti-pac-cli-error.s
Original file line number Diff line number Diff line change
@@ -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
114 changes: 114 additions & 0 deletions lld/test/ELF/aarch64-feature-pauth.s
Original file line number Diff line number Diff line change
@@ -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:
22 changes: 22 additions & 0 deletions lld/test/ELF/aarch64-reloc-pauth-ro.s
Original file line number Diff line number Diff line change
@@ -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@AUTH(da,42)
.quad bar2@AUTH(ia,42)
.quad foo@AUTH(ia,42)
108 changes: 108 additions & 0 deletions lld/test/ELF/aarch64-reloc-pauth.s
Original file line number Diff line number Diff line change
@@ -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@AUTH(ia,50)
.byte 0x77
.quad (__ehdr_start + 4)@AUTH(da,51)
.byte 0x77
.quad (.test + 5)@AUTH(da,52)

0 comments on commit cca9115

Please sign in to comment.