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 <dkova...@accesssoftek.com> Date: Thu, 28 Sep 2023 03:14:35 +0300 Subject: [PATCH 1/6] [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 <pe...@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 048f0ec30ebd283..6828d3f57c10e84 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 56229334f9a44ae..1b633a79842769d 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 6bef09eeca015aa..4e8e9eb86ecf77f 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 cc2c5916e05c22c..44c8050f2c967a2 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 ab98d78fcf1455a..6a74ba7fb20998c 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 fe3d7f419e84aa6..5b5e6b154d52f42 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 2b32eb3a0fe3558..fa7589806a7b5b0 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 3a9f4ba886f6bbb..d183a547c682051 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 a84e4864ab0e5a5..f1b569daada663e 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 000000000000000..0520b2f28631e10 --- /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 000000000000000..db946fc4c3e55c8 --- /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) >From 589c6455a929f41ed3a79fc7d91119586eb1ee7b Mon Sep 17 00:00:00 2001 From: Daniil Kovalev <dkova...@accesssoftek.com> Date: Tue, 12 Dec 2023 09:05:38 +0300 Subject: [PATCH 2/6] Address trivial review comments --- lld/ELF/Driver.cpp | 46 ++++++++++++------------ lld/ELF/InputFiles.cpp | 2 +- lld/test/ELF/aarch64-bti-pac-cli-error.s | 15 +++++--- lld/test/ELF/aarch64-feature-pauth.s | 2 +- 4 files changed, 35 insertions(+), 30 deletions(-) diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 4e8e9eb86ecf77f..ca5a8b8d994a4b5 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -2648,44 +2648,44 @@ static uint32_t getAndFeatures() { return ret; } -static void getAarch64PauthInfo() { +static void getAArch64PauthInfo() { if (ctx.objectFiles.empty()) return; - auto NonEmptyIt = std::find_if( + auto it = std::find_if( ctx.objectFiles.begin(), ctx.objectFiles.end(), [](const ELFFileBase *f) { return !f->aarch64PauthAbiTag.empty(); }); - if (NonEmptyIt == ctx.objectFiles.end()) + if (it == 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); + ctx.aarch64PauthAbiTag = (*it)->aarch64PauthAbiTag; + StringRef f1 = (*it)->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()) + + helper(config->zPauthReport, + (d1.empty() ? f1.str() : f2.str()) + " has no AArch64 PAuth compatibility info while " + - (D1.empty() ? F2.str() : F1.str()) + + (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())) + 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()))); + f1 + ": 0x" + toHex(ArrayRef(d1.data(), d1.size())) + "\n" + f2 + + ": 0x" + toHex(ArrayRef(d2.data(), d2.size()))); } } @@ -3027,7 +3027,7 @@ void LinkerDriver::link(opt::InputArgList &args) { config->andFeatures = getAndFeatures(); if (config->emachine == EM_AARCH64) - getAarch64PauthInfo(); + getAArch64PauthInfo(); // 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 44c8050f2c967a2..d7ceaf476cf9bf1 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -992,7 +992,7 @@ static void readAArch64PauthAbiTag(const InputSection &sec, ObjFile<ELFT> &f) { ArrayRef<uint8_t> desc = note.getDesc(sec.addralign); if (desc.size() < 16) { - reportError("too short AArch64 PAuth compatibility info " + reportError("AArch64 PAuth compatibility info is too short " "(at least 16 bytes expected)"); return; } diff --git a/lld/test/ELF/aarch64-bti-pac-cli-error.s b/lld/test/ELF/aarch64-bti-pac-cli-error.s index b8ab1a28fa5a869..703c0aac6ea5ac6 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 index 0520b2f28631e10..9060eb71f817572 100644 --- a/lld/test/ELF/aarch64-feature-pauth.s +++ b/lld/test/ELF/aarch64-feature-pauth.s @@ -21,7 +21,7 @@ # 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) +# ERR2-NEXT: error: {{.*}}: AArch64 PAuth compatibility info is too short (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 >From d3411595fbbe37a14b0187ff0d134bd105892931 Mon Sep 17 00:00:00 2001 From: Daniil Kovalev <dkova...@accesssoftek.com> Date: Tue, 9 Jan 2024 21:53:00 +0300 Subject: [PATCH 3/6] Use `pack-relative-relocs` for both regular and auth relr relocs --- lld/ELF/Config.h | 1 - lld/ELF/Driver.cpp | 3 --- lld/ELF/Writer.cpp | 3 --- lld/test/ELF/aarch64-ptrauth.s | 4 ++-- 4 files changed, 2 insertions(+), 9 deletions(-) diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 1b633a79842769d..e2a3cb2a61e936e 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -276,7 +276,6 @@ 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; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index ca5a8b8d994a4b5..6ab93c74bc64536 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1677,9 +1677,6 @@ 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 " diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index af2544c3fa0f7f1..81e743d67dabd1c 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -450,9 +450,6 @@ template <class ELFT> void elf::createSyntheticSections() { if (config->relrPackDynRelocs) { part.relrDyn = std::make_unique<RelrSection<ELFT>>(threadCount); add(*part.relrDyn); - } - - if (config->relrPackAuthDynRelocs) { part.relrAuthDyn = std::make_unique<RelrSection<ELFT>>( threadCount, /*isAArch64Auth=*/true); add(*part.relrAuthDyn); diff --git a/lld/test/ELF/aarch64-ptrauth.s b/lld/test/ELF/aarch64-ptrauth.s index db946fc4c3e55c8..26cc2d779e74821 100644 --- a/lld/test/ELF/aarch64-ptrauth.s +++ b/lld/test/ELF/aarch64-ptrauth.s @@ -3,7 +3,7 @@ // 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: ld.lld -pie -z nopack-relative-relocs %t.o %t.so -o %t2 // RUN: llvm-readobj -r %t2 | FileCheck --check-prefix=UNPACKED %s // UNPACKED: Section ({{.+}}) .rela.dyn { @@ -42,7 +42,7 @@ // 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: ld.lld -pie -z pack-relative-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 >From b791da9dd02f8b3bf59d2d235181f945844d3039 Mon Sep 17 00:00:00 2001 From: Daniil Kovalev <dkova...@accesssoftek.com> Date: Tue, 9 Jan 2024 21:59:35 +0300 Subject: [PATCH 4/6] Rename aarch64-ptrauth.s to aarch64-reloc-pauth.s --- lld/test/ELF/{aarch64-ptrauth.s => aarch64-reloc-pauth.s} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lld/test/ELF/{aarch64-ptrauth.s => aarch64-reloc-pauth.s} (100%) diff --git a/lld/test/ELF/aarch64-ptrauth.s b/lld/test/ELF/aarch64-reloc-pauth.s similarity index 100% rename from lld/test/ELF/aarch64-ptrauth.s rename to lld/test/ELF/aarch64-reloc-pauth.s >From b95dcf8e7cd9c3c162a25c93a9c2b09ba8bb124c Mon Sep 17 00:00:00 2001 From: Daniil Kovalev <dkova...@accesssoftek.com> Date: Tue, 9 Jan 2024 22:23:16 +0300 Subject: [PATCH 5/6] Remove unneeded test directives --- lld/test/ELF/aarch64-reloc-pauth.s | 114 +++-------------------------- 1 file changed, 12 insertions(+), 102 deletions(-) diff --git a/lld/test/ELF/aarch64-reloc-pauth.s b/lld/test/ELF/aarch64-reloc-pauth.s index 26cc2d779e74821..79e6e4246cc457c 100644 --- a/lld/test/ELF/aarch64-reloc-pauth.s +++ b/lld/test/ELF/aarch64-reloc-pauth.s @@ -7,39 +7,10 @@ // 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: 0x303C8 R_AARCH64_AUTH_RELATIVE - 0x1 +// UNPACKED-NEXT: 0x303E1 R_AARCH64_AUTH_RELATIVE - 0x2 +// UNPACKED-NEXT: 0x303D0 R_AARCH64_AUTH_ABS64 zed2 0x0 +// UNPACKED-NEXT: 0x303D8 R_AARCH64_AUTH_ABS64 bar2 0x0 // UNPACKED-NEXT: } // RUN: ld.lld -pie -z pack-relative-relocs %t.o %t.so -o %t2 @@ -57,21 +28,20 @@ // RELR-HEADERS-NEXT: ] // RELR-HEADERS-NEXT: Address: [[ADDR:.*]] // RELR-HEADERS-NEXT: Offset: [[ADDR]] -// RELR-HEADERS-NEXT: Size: 16 +// RELR-HEADERS-NEXT: Size: 8 // 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: 0x0000000070000011 AARCH64_AUTH_RELRSZ 8 (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: 0x303E8 // RAW-RELR-NEXT: } /// Decoded SHT_RELR section is same as UNPACKED, @@ -79,78 +49,18 @@ /// 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: 0x30401 R_AARCH64_AUTH_RELATIVE - 0x2 +// RELR-NEXT: 0x303F0 R_AARCH64_AUTH_ABS64 zed2 0x0 +// RELR-NEXT: 0x303F8 R_AARCH64_AUTH_ABS64 bar2 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: 0x303E8 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) +.quad (__ehdr_start + 2)@AUTH(da,42) >From 594f8a0e8331b5d11f3efc58fcaa7eae4b9fd7b4 Mon Sep 17 00:00:00 2001 From: Daniil Kovalev <dkova...@accesssoftek.com> Date: Thu, 11 Jan 2024 03:19:14 +0300 Subject: [PATCH 6/6] Do not emit AUTH relocations in read-only sections --- lld/ELF/Relocations.cpp | 85 +++++++++++++++++++-------- lld/test/ELF/aarch64-reloc-pauth-ro.s | 21 +++++++ 2 files changed, 80 insertions(+), 26 deletions(-) create mode 100644 lld/test/ELF/aarch64-reloc-pauth-ro.s diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 166407d573252a7..53f638ae2f854e2 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -1125,11 +1125,37 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset, (isa<EhInputSection>(sec) && config->emachine != EM_MIPS)); if (canWrite) { RelType rel = target->getDynRel(type); + if (config->emachine == EM_AARCH64 && type == R_AARCH64_AUTH_ABS64) { + // Assume relocations from relocatable objects are RELA. + assert(config->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 field 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 (oneof<R_GOT, R_LOONGARCH_GOT>(expr) || (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); @@ -1157,6 +1183,12 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset, } } + if (config->emachine == EM_AARCH64 && type == R_AARCH64_AUTH_ABS64) { + error("relocation " + toString(type) + " against symbol '" + toString(sym) + + "'" + " in read-only section" + getLocation(*sec, sym, offset)); + return; + } + // 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()) { @@ -1444,31 +1476,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 (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/test/ELF/aarch64-reloc-pauth-ro.s b/lld/test/ELF/aarch64-reloc-pauth-ro.s new file mode 100644 index 000000000000000..80afb921a5c26fe --- /dev/null +++ b/lld/test/ELF/aarch64-reloc-pauth-ro.s @@ -0,0 +1,21 @@ +// 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 %s + +// CHECK: error: relocation R_AARCH64_AUTH_ABS64 against symbol 'zed2' in read-only section +// CHECK-NEXT: defined in +// CHECK-NEXT: referenced by +// CHECK-SAME: :(.test+0x0) + +// CHECK: error: relocation R_AARCH64_AUTH_ABS64 against symbol 'bar2' in read-only section +// CHECK-NEXT: defined in +// CHECK-NEXT: referenced by +// CHECK-SAME: :(.test+0x8) + +.section .test, "a" +.p2align 3 +.quad zed2@AUTH(da,42) +.quad bar2@AUTH(ia,42) _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits