[lld] [llvm] [lld][AArch64][Build Attributes] Add support for AArch64 Build Attributes (PR #142637)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 4 03:50:26 PDT 2025


https://github.com/sivan-shani updated https://github.com/llvm/llvm-project/pull/142637

>From 5ff6e9e700c52b9dba38a1caa892ba44b34ac633 Mon Sep 17 00:00:00 2001
From: Sivan Shani <sivan.shani at arm.com>
Date: Wed, 28 May 2025 13:01:27 +0100
Subject: [PATCH 1/2] [lld] Refactor storage of PAuth ABI core info

Previously, the AArch64 PAuth ABI core values were stored as an ArrayRef<uint8_t>, introducing unnecessary indirection.
This patch replaces the ArrayRef with two explicit uint64_t fields: aarch64PauthAbiPlatform and aarch64PauthAbiVersion. This simplifies the representation and improves readability.
No functional change intended, aside from improved error messages.
---
 lld/ELF/Arch/AArch64.cpp             |  3 +--
 lld/ELF/Config.h                     | 19 ++++++++++++++++++-
 lld/ELF/Driver.cpp                   | 27 +++++++++++++++++----------
 lld/ELF/InputFiles.cpp               |  6 ++++--
 lld/ELF/InputFiles.h                 |  2 +-
 lld/ELF/SyntheticSections.cpp        | 14 +++++++-------
 lld/test/ELF/aarch64-feature-pauth.s |  8 ++++++--
 7 files changed, 54 insertions(+), 25 deletions(-)

diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index 9538dd4a70bae..30ce41e4effa8 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -1044,8 +1044,7 @@ AArch64BtiPac::AArch64BtiPac(Ctx &ctx) : AArch64(ctx) {
   // instructions.
 
   if (ctx.arg.zPacPlt) {
-    if (llvm::any_of(ctx.aarch64PauthAbiCoreInfo,
-                     [](uint8_t c) { return c != 0; }))
+    if (ctx.aarch64PauthAbiCoreInfo && ctx.aarch64PauthAbiCoreInfo->isValid())
       pacEntryKind = PEK_Auth;
     else
       pacEntryKind = PEK_AuthHint;
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index f0e9592d85dd6..d8d9e3fd1699e 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -139,6 +139,23 @@ enum class GcsPolicy { Implicit, Never, Always };
 // For some options that resemble -z bti-report={none,warning,error}
 enum class ReportPolicy { None, Warning, Error };
 
+// Describes the signing schema for a file using the PAuth ABI extension.
+// Two files are considered compatible when both `platform` and `version` match.
+// The pair (0, 0) is reserved to indicate incompatibility with the PAuth ABI.
+struct AArch64PauthAbiCoreInfo {
+  uint64_t platform;
+  uint64_t version;
+  // Returns true if the core info is not the reserved (0, 0) value.
+  bool isValid() const { return platform || version; }
+  static constexpr size_t size() { return sizeof(platform) + sizeof(version); }
+  bool operator==(const AArch64PauthAbiCoreInfo &other) const {
+    return platform == other.platform && version == other.version;
+  }
+  bool operator!=(const AArch64PauthAbiCoreInfo &other) const {
+    return !(*this == other);
+  }
+};
+
 struct SymbolVersion {
   llvm::StringRef name;
   bool isExternCpp;
@@ -695,7 +712,7 @@ struct Ctx : CommonLinkerContext {
 
   llvm::raw_fd_ostream openAuxiliaryFile(llvm::StringRef, std::error_code &);
 
-  ArrayRef<uint8_t> aarch64PauthAbiCoreInfo;
+  std::optional<AArch64PauthAbiCoreInfo> aarch64PauthAbiCoreInfo;
 };
 
 // The first two elements of versionDefinitions represent VER_NDX_LOCAL and
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 76a37b706c5fa..da51d9fab8d07 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -2841,15 +2841,15 @@ static void readSecurityNotes(Ctx &ctx) {
   StringRef referenceFileName;
   if (ctx.arg.emachine == EM_AARCH64) {
     auto it = llvm::find_if(ctx.objectFiles, [](const ELFFileBase *f) {
-      return !f->aarch64PauthAbiCoreInfo.empty();
+      return f->aarch64PauthAbiCoreInfo.has_value();
     });
     if (it != ctx.objectFiles.end()) {
       ctx.aarch64PauthAbiCoreInfo = (*it)->aarch64PauthAbiCoreInfo;
       referenceFileName = (*it)->getName();
     }
   }
-  bool hasValidPauthAbiCoreInfo = llvm::any_of(
-      ctx.aarch64PauthAbiCoreInfo, [](uint8_t c) { return c != 0; });
+  bool hasValidPauthAbiCoreInfo =
+      ctx.aarch64PauthAbiCoreInfo && ctx.aarch64PauthAbiCoreInfo->isValid();
 
   auto report = [&](ReportPolicy policy) -> ELFSyncStream {
     return {ctx, toDiagLevel(policy)};
@@ -2909,10 +2909,10 @@ static void readSecurityNotes(Ctx &ctx) {
     }
     ctx.arg.andFeatures &= features;
 
-    if (ctx.aarch64PauthAbiCoreInfo.empty())
+    if (!ctx.aarch64PauthAbiCoreInfo)
       continue;
 
-    if (f->aarch64PauthAbiCoreInfo.empty()) {
+    if (!f->aarch64PauthAbiCoreInfo) {
       report(ctx.arg.zPauthReport)
           << f
           << ": -z pauth-report: file does not have AArch64 "
@@ -2922,11 +2922,18 @@ static void readSecurityNotes(Ctx &ctx) {
     }
 
     if (ctx.aarch64PauthAbiCoreInfo != f->aarch64PauthAbiCoreInfo)
-      Err(ctx) << "incompatible values of AArch64 PAuth core info found\n>>> "
-               << referenceFileName << ": 0x"
-               << toHex(ctx.aarch64PauthAbiCoreInfo, /*LowerCase=*/true)
-               << "\n>>> " << f << ": 0x"
-               << toHex(f->aarch64PauthAbiCoreInfo, /*LowerCase=*/true);
+      Err(ctx)
+          << "incompatible values of AArch64 PAuth core info found\n"
+          << "platform:\n"
+          << ">>> " << referenceFileName << ": 0x"
+          << toHex(ctx.aarch64PauthAbiCoreInfo->platform, /*LowerCase=*/true)
+          << "\n>>> " << f << ": 0x"
+          << toHex(f->aarch64PauthAbiCoreInfo->platform, /*LowerCase=*/true)
+          << "\nversion:\n"
+          << ">>> " << referenceFileName << ": 0x"
+          << toHex(ctx.aarch64PauthAbiCoreInfo->version, /*LowerCase=*/true)
+          << "\n>>> " << f << ": 0x"
+          << toHex(f->aarch64PauthAbiCoreInfo->version, /*LowerCase=*/true);
   }
 
   // Force enable Shadow Stack.
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 5f6d2b6b647ee..817af15a841ec 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -950,7 +950,7 @@ static void parseGnuPropertyNote(Ctx &ctx, ELFFileBase &f,
     } else if (ctx.arg.emachine == EM_AARCH64 &&
                type == GNU_PROPERTY_AARCH64_FEATURE_PAUTH) {
       ArrayRef<uint8_t> contents = data ? *data : desc;
-      if (!f.aarch64PauthAbiCoreInfo.empty()) {
+      if (f.aarch64PauthAbiCoreInfo) {
         return void(
             err(contents.data())
             << "multiple GNU_PROPERTY_AARCH64_FEATURE_PAUTH entries are "
@@ -961,7 +961,9 @@ static void parseGnuPropertyNote(Ctx &ctx, ELFFileBase &f,
                        "is invalid: expected 16 bytes, but got "
                     << size);
       }
-      f.aarch64PauthAbiCoreInfo = desc;
+      f.aarch64PauthAbiCoreInfo = {
+          support::endian::read64<ELFT::Endianness>(&desc[0]),
+          support::endian::read64<ELFT::Endianness>(&desc[8])};
     }
 
     // Padding is present in the note descriptor, if necessary.
diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h
index 808cb5d24079f..ba844ad18f637 100644
--- a/lld/ELF/InputFiles.h
+++ b/lld/ELF/InputFiles.h
@@ -241,7 +241,7 @@ class ELFFileBase : public InputFile {
   StringRef sourceFile;
   uint32_t andFeatures = 0;
   bool hasCommonSyms = false;
-  ArrayRef<uint8_t> aarch64PauthAbiCoreInfo;
+  std::optional<AArch64PauthAbiCoreInfo> aarch64PauthAbiCoreInfo;
 };
 
 // .o file.
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 46591e909ba4f..eb902767746de 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -344,11 +344,11 @@ void GnuPropertySection::writeTo(uint8_t *buf) {
     offset += 16;
   }
 
-  if (!ctx.aarch64PauthAbiCoreInfo.empty()) {
+  if (ctx.aarch64PauthAbiCoreInfo) {
     write32(ctx, buf + offset + 0, GNU_PROPERTY_AARCH64_FEATURE_PAUTH);
-    write32(ctx, buf + offset + 4, ctx.aarch64PauthAbiCoreInfo.size());
-    memcpy(buf + offset + 8, ctx.aarch64PauthAbiCoreInfo.data(),
-           ctx.aarch64PauthAbiCoreInfo.size());
+    write32(ctx, buf + offset + 4, AArch64PauthAbiCoreInfo::size());
+    write64(ctx, buf + offset + 8, ctx.aarch64PauthAbiCoreInfo->platform);
+    write64(ctx, buf + offset + 16, ctx.aarch64PauthAbiCoreInfo->version);
   }
 }
 
@@ -356,8 +356,8 @@ size_t GnuPropertySection::getSize() const {
   uint32_t contentSize = 0;
   if (ctx.arg.andFeatures != 0)
     contentSize += ctx.arg.is64 ? 16 : 12;
-  if (!ctx.aarch64PauthAbiCoreInfo.empty())
-    contentSize += 4 + 4 + ctx.aarch64PauthAbiCoreInfo.size();
+  if (ctx.aarch64PauthAbiCoreInfo)
+    contentSize += 4 + 4 + AArch64PauthAbiCoreInfo::size();
   assert(contentSize != 0);
   return contentSize + 16;
 }
@@ -4959,7 +4959,7 @@ template <class ELFT> void elf::createSyntheticSections(Ctx &ctx) {
   ctx.in.iplt = std::make_unique<IpltSection>(ctx);
   add(*ctx.in.iplt);
 
-  if (ctx.arg.andFeatures || !ctx.aarch64PauthAbiCoreInfo.empty()) {
+  if (ctx.arg.andFeatures || ctx.aarch64PauthAbiCoreInfo) {
     ctx.in.gnuProperty = std::make_unique<GnuPropertySection>(ctx);
     add(*ctx.in.gnuProperty);
   }
diff --git a/lld/test/ELF/aarch64-feature-pauth.s b/lld/test/ELF/aarch64-feature-pauth.s
index bc58f69d32f2b..e8c900b9cb134 100644
--- a/lld/test/ELF/aarch64-feature-pauth.s
+++ b/lld/test/ELF/aarch64-feature-pauth.s
@@ -13,8 +13,12 @@
 # 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
+# ERR1-NEXT: platform:
+# ERR1-NEXT: >>> tag1.o: 0x2a
+# ERR1-NEXT: >>> tag2.o: 0x2a
+# ERR1-NEXT: version:
+# ERR1-NEXT: >>> tag1.o: 0x01
+# ERR1-NEXT: >>> tag2.o: 0x02
 
 # 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

>From 80268efaf5ae932bb6fd032bbbd76a76f5630d87 Mon Sep 17 00:00:00 2001
From: Sivan Shani <sivan.shani at arm.com>
Date: Tue, 3 Jun 2025 17:06:31 +0100
Subject: [PATCH 2/2] [lld][AArch64][Build Attributes] Add support for AArch64
 Build Attributes

This patch enables lld to read AArch64 Build Attributes and convert them into GNU Properties.

Changes:
- Parses AArch64 Build Attributes from input object files.
- Converts known attributes into corresponding GNU Properties.
- Merges attributes when linking multiple objects.
---
 lld/ELF/InputFiles.cpp                        | 101 ++++++++++--
 lld/ELF/InputFiles.h                          |   5 +
 .../ELF/Inputs/aarch64-func3-pac-replace.s    |  10 ++
 lld/test/ELF/Inputs/aarch64-pac1-replace.s    |  13 ++
 lld/test/ELF/aarch64-build-attributes-be.s    |  50 ++++++
 lld/test/ELF/aarch64-build-attributes-err.s   |  35 +++++
 .../ELF/aarch64-build-attributes-malformed.s  |  16 ++
 lld/test/ELF/aarch64-build-attributes-mixed.s |  62 ++++++++
 lld/test/ELF/aarch64-build-attributes.s       |  57 +++++--
 lld/test/ELF/aarch64-feature-pac-replace.s    | 148 ++++++++++++++++++
 .../llvm/Support/AArch64AttributeParser.h     |  11 ++
 llvm/lib/Support/AArch64AttributeParser.cpp   |  27 ++++
 12 files changed, 509 insertions(+), 26 deletions(-)
 create mode 100644 lld/test/ELF/Inputs/aarch64-func3-pac-replace.s
 create mode 100644 lld/test/ELF/Inputs/aarch64-pac1-replace.s
 create mode 100644 lld/test/ELF/aarch64-build-attributes-be.s
 create mode 100644 lld/test/ELF/aarch64-build-attributes-err.s
 create mode 100644 lld/test/ELF/aarch64-build-attributes-malformed.s
 create mode 100644 lld/test/ELF/aarch64-build-attributes-mixed.s
 create mode 100644 lld/test/ELF/aarch64-feature-pac-replace.s

diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 817af15a841ec..1eb95a99d792a 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -22,6 +22,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/LTO/LTO.h"
 #include "llvm/Object/IRObjectFile.h"
+#include "llvm/Support/AArch64AttributeParser.h"
 #include "llvm/Support/ARMAttributeParser.h"
 #include "llvm/Support/ARMBuildAttributes.h"
 #include "llvm/Support/Endian.h"
@@ -539,6 +540,42 @@ uint32_t ObjFile<ELFT>::getSectionIndex(const Elf_Sym &sym) const {
       this);
 }
 
+template <class ELFT>
+static void
+handleAArch64BAAndGnuProperties(ObjFile<ELFT> *file, Ctx &ctx, bool hasGP,
+                                const AArch64BuildAttrSubsections &baInfo,
+                                const GnuPropertiesInfo &gpInfo) {
+  if (hasGP) {
+    // Check for data mismatch
+    if (gpInfo.pauthAbiCoreInfo) {
+      if (baInfo.Pauth.TagPlatform != gpInfo.pauthAbiCoreInfo->platform)
+        Err(ctx)
+            << file
+            << " Pauth Data mismatch: file contains both GNU properties and "
+               "AArch64 build attributes sections with different Pauth data";
+    }
+    if (baInfo.AndFeatures != gpInfo.andFeatures)
+      Err(ctx) << file
+               << " Features Data mismatch: file contains both GNU "
+                  "properties and AArch64 build attributes sections with "
+                  "different And Features data";
+  } else {
+    // Write missing data
+    // We can only know when Pauth is missing.
+    // Unlike AArch64 Build Attributes, GNU properties does not give a way to
+    // distinguish between no-value given to value of '0' given.
+    if (baInfo.Pauth.TagPlatform || baInfo.Pauth.TagSchema) {
+      file->aarch64PauthAbiCoreInfo = {baInfo.Pauth.TagPlatform,
+                                       baInfo.Pauth.TagSchema};
+    }
+    file->andFeatures = baInfo.AndFeatures;
+  }
+}
+
+template <typename ELFT>
+static GnuPropertiesInfo readGnuProperty(Ctx &, const InputSection &,
+                                         ObjFile<ELFT> &);
+
 template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
   object::ELFFile<ELFT> obj = this->getObj();
   // Read a section table. justSymbols is usually false.
@@ -554,8 +591,31 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
   StringRef shstrtab = CHECK2(obj.getSectionStringTable(objSections), this);
   uint64_t size = objSections.size();
   sections.resize(size);
+
+  // For handling AArch64 Build attributes and GNU properties
+  AArch64BuildAttrSubsections aarch64BAsubSections;
+  GnuPropertiesInfo gnuProperty;
+  bool hasAArch64BuildAttributes = false;
+  bool hasGNUProperties = false;
+
   for (size_t i = 0; i != size; ++i) {
     const Elf_Shdr &sec = objSections[i];
+    // Object files that use processor features such as Intel Control-Flow
+    // Enforcement (CET) or AArch64 Branch Target Identification BTI, use a
+    // .note.gnu.property section containing a bitfield of feature bits like the
+    // GNU_PROPERTY_X86_FEATURE_1_IBT flag. Read a bitmap containing the flag.
+    if (check(obj.getSectionName(sec, shstrtab)) == ".note.gnu.property") {
+      gnuProperty = readGnuProperty(
+          ctx,
+          InputSection(*this, sec, check(obj.getSectionName(sec, shstrtab))),
+          *this);
+      hasGNUProperties = true;
+      // Since we merge bitmaps from multiple object files to create a new
+      // .note.gnu.property containing a single AND'ed bitmap, we discard an
+      // input file's .note.gnu.property section.
+      sections[i] = &InputSection::discarded;
+    }
+
     if (LLVM_LIKELY(sec.sh_type == SHT_PROGBITS))
       continue;
     if (LLVM_LIKELY(sec.sh_type == SHT_GROUP)) {
@@ -639,13 +699,27 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
       }
       break;
     case EM_AARCH64:
-      // FIXME: BuildAttributes have been implemented in llvm, but not yet in
-      // lld. Remove the section so that it does not accumulate in the output
-      // file. When support is implemented we expect not to output a build
-      // attributes section in files of type ET_EXEC or ET_SHARED, but ld -r
-      // ouptut will need a single merged attributes section.
-      if (sec.sh_type == SHT_AARCH64_ATTRIBUTES)
+      // At this stage AArch64 Build Attributes does not replace GNU Properties.
+      // When both exists, their values must match.
+      // When both exists and contain different attributes, they complement each
+      // other. Currently attributes are represented in the linked object file
+      // as GNU properties, which are already supported by the Linux kernel and
+      // the dynamic loader. In the future, when relocatable linking (`-r` flag)
+      // is performed, a single merged AArch64 Build Attributes section will be
+      // emitted.
+      if (sec.sh_type == SHT_AARCH64_ATTRIBUTES) {
+        ArrayRef<uint8_t> contents = check(obj.getSectionContents(sec));
+        AArch64AttributeParser attributes;
+        StringRef name = check(obj.getSectionName(sec, shstrtab));
+        InputSection isec(*this, sec, name);
+        if (Error e = attributes.parse(contents, ELFT::Endianness)) {
+          Warn(ctx) << &isec << ": " << std::move(e);
+        } else {
+          aarch64BAsubSections = extractBuildAttributesSubsections(attributes);
+          hasAArch64BuildAttributes = true;
+        }
         sections[i] = &InputSection::discarded;
+      }
       // Producing a static binary with MTE globals is not currently supported,
       // remove all SHT_AARCH64_MEMTAG_GLOBALS_STATIC sections as they're unused
       // medatada, and we don't want them to end up in the output file for
@@ -657,6 +731,14 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
     }
   }
 
+  if (hasAArch64BuildAttributes) {
+    // Handle AArch64 Build Attributes and GNU properties:
+    // - Err on mismatched values.
+    // - Store missing values as GNU properties.
+    handleAArch64BAAndGnuProperties<ELFT>(this, ctx, hasGNUProperties,
+                                          aarch64BAsubSections, gnuProperty);
+  }
+
   // Read a symbol table.
   initializeSymbols(obj);
 }
@@ -976,8 +1058,8 @@ static void parseGnuPropertyNote(Ctx &ctx, ELFFileBase &f,
 //   hardware-assisted call flow control;
 // - AArch64 PAuth ABI core info (16 bytes).
 template <class ELFT>
-static void readGnuProperty(Ctx &ctx, const InputSection &sec,
-                            ObjFile<ELFT> &f) {
+static GnuPropertiesInfo readGnuProperty(Ctx &ctx, const InputSection &sec,
+                                         ObjFile<ELFT> &f) {
   using Elf_Nhdr = typename ELFT::Nhdr;
   using Elf_Note = typename ELFT::Note;
 
@@ -993,7 +1075,7 @@ static void readGnuProperty(Ctx &ctx, const InputSection &sec,
     auto *nhdr = reinterpret_cast<const Elf_Nhdr *>(data.data());
     if (data.size() < sizeof(Elf_Nhdr) ||
         data.size() < nhdr->getSize(sec.addralign))
-      return void(err(data.data()) << "data is too short");
+      return (err(data.data()) << "data is too short", GnuPropertiesInfo{});
 
     Elf_Note note(*nhdr);
     if (nhdr->n_type != NT_GNU_PROPERTY_TYPE_0 || note.getName() != "GNU") {
@@ -1013,6 +1095,7 @@ static void readGnuProperty(Ctx &ctx, const InputSection &sec,
     // Go to next NOTE record to look for more FEATURE_1_AND descriptions.
     data = data.slice(nhdr->getSize(sec.addralign));
   }
+  return GnuPropertiesInfo{f.andFeatures, f.aarch64PauthAbiCoreInfo};
 }
 
 template <class ELFT>
diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h
index ba844ad18f637..9d40030f22fcc 100644
--- a/lld/ELF/InputFiles.h
+++ b/lld/ELF/InputFiles.h
@@ -244,6 +244,11 @@ class ELFFileBase : public InputFile {
   std::optional<AArch64PauthAbiCoreInfo> aarch64PauthAbiCoreInfo;
 };
 
+struct GnuPropertiesInfo {
+  uint32_t andFeatures = 0;
+  std::optional<AArch64PauthAbiCoreInfo> pauthAbiCoreInfo;
+};
+
 // .o file.
 template <class ELFT> class ObjFile : public ELFFileBase {
   LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
diff --git a/lld/test/ELF/Inputs/aarch64-func3-pac-replace.s b/lld/test/ELF/Inputs/aarch64-func3-pac-replace.s
new file mode 100644
index 0000000000000..b6133844d07f7
--- /dev/null
+++ b/lld/test/ELF/Inputs/aarch64-func3-pac-replace.s
@@ -0,0 +1,10 @@
+// Declare file properties exclusively with aarch64 build attributes.
+
+.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+.aeabi_attribute Tag_Feature_PAC, 1
+
+.text
+.globl func3
+.type func3, at function
+func3:
+  ret
diff --git a/lld/test/ELF/Inputs/aarch64-pac1-replace.s b/lld/test/ELF/Inputs/aarch64-pac1-replace.s
new file mode 100644
index 0000000000000..f763f9de2342a
--- /dev/null
+++ b/lld/test/ELF/Inputs/aarch64-pac1-replace.s
@@ -0,0 +1,13 @@
+// This file replace gnu properties with aarch64 build attributes.
+
+.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+.aeabi_attribute Tag_Feature_PAC, 1
+
+.text
+.globl func2
+.type func2, at function
+func2:
+  .globl func3
+  .type func3, @function
+  bl func3
+  ret
diff --git a/lld/test/ELF/aarch64-build-attributes-be.s b/lld/test/ELF/aarch64-build-attributes-be.s
new file mode 100644
index 0000000000000..985e19348cf66
--- /dev/null
+++ b/lld/test/ELF/aarch64-build-attributes-be.s
@@ -0,0 +1,50 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -triple=aarch64_be %s -filetype=obj -o %t.o
+// RUN: ld.lld %t.o --shared -o %t.so
+// RUN: llvm-readelf -n %t.so | FileCheck %s --check-prefix=NOTE
+
+/// The Build attributes section appearing in the output of
+/// llvm-mc should not appear in the output of lld, because
+/// AArch64 build attributes are being transformed into .gnu.properties.
+
+/// Test mc -> big endian, lld -> little endian
+// RUN: llvm-mc -triple=aarch64_be %s -filetype=obj -o %t.o
+// RUN: ld.lld %t.o --shared -o %t.so
+// RUN: llvm-readelf -n %t.so | FileCheck %s --check-prefix=NOTE
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readelf -n %t.so | FileCheck %s --check-prefix=NOTE
+// RUN: ld.lld -r %t.o -o %t2.o
+// RUN: llvm-readelf -n %t.so | FileCheck %s --check-prefix=NOTE
+
+/// Test mc -> little endian, lld -> big endian
+// RUN: llvm-mc -triple=aarch64 %s -filetype=obj -o %t.o
+// RUN: ld.lld --EB %t.o --shared -o %t.so
+// RUN: llvm-readelf -n %t.so | FileCheck %s --check-prefix=NOTE
+// RUN: ld.lld --EB %t.o -o %t
+// RUN: llvm-readelf -n %t.so | FileCheck %s --check-prefix=NOTE
+// RUN: ld.lld --EB -r %t.o -o %t2.o
+// RUN: llvm-readelf -n %t.so | FileCheck %s --check-prefix=NOTE
+
+/// Test mc -> big endian, lld -> big endian
+// RUN: llvm-mc -triple=aarch64_be %s -filetype=obj -o %t.o
+// RUN: ld.lld --EB %t.o --shared -o %t.so
+// RUN: llvm-readelf -n %t.so | FileCheck %s --check-prefix=NOTE
+// RUN: ld.lld --EB %t.o -o %t
+// RUN: llvm-readelf -n %t.so | FileCheck %s --check-prefix=NOTE
+// RUN: ld.lld --EB -r %t.o -o %t2.o
+// RUN: llvm-readelf -n %t.so | FileCheck %s --check-prefix=NOTE
+
+// NOTE: Displaying notes found in: .note.gnu.property
+// NOTE-NEXT: Owner Data size Description
+// NOTE-NEXT: GNU 0x00000028 NT_GNU_PROPERTY_TYPE_0 (property note)
+// NOTE-NEXT: Properties: aarch64 feature: BTI, PAC, GCS
+// NOTE-NEXT: AArch64 PAuth ABI core info: platform 0x89abcdef (unknown), version 0x89abcdef
+
+
+.aeabi_subsection aeabi_pauthabi, required, uleb128
+.aeabi_attribute Tag_PAuth_Platform, 81985529216486895
+.aeabi_attribute Tag_PAuth_Schema, 81985529216486895
+.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+.aeabi_attribute Tag_Feature_BTI, 1
+.aeabi_attribute Tag_Feature_PAC, 1
+.aeabi_attribute Tag_Feature_GCS, 1
diff --git a/lld/test/ELF/aarch64-build-attributes-err.s b/lld/test/ELF/aarch64-build-attributes-err.s
new file mode 100644
index 0000000000000..965f13673eb5c
--- /dev/null
+++ b/lld/test/ELF/aarch64-build-attributes-err.s
@@ -0,0 +1,35 @@
+// REQUIRES: aarch64
+
+// RUN: llvm-mc -triple=aarch64 %s -filetype=obj -o %t.o
+// RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR
+
+// ERR: Pauth Data mismatch: file contains both GNU properties and AArch64 build attributes sections with different Pauth data
+// ERR-NEXT: Features Data mismatch: file contains both GNU properties and AArch64 build attributes sections with different And Features data
+
+.aeabi_subsection aeabi_pauthabi, required, uleb128
+.aeabi_attribute Tag_PAuth_Platform, 5
+.aeabi_attribute Tag_PAuth_Schema, 5
+.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+.aeabi_attribute Tag_Feature_BTI, 1
+.aeabi_attribute Tag_Feature_PAC, 1
+.aeabi_attribute Tag_Feature_GCS, 1
+
+.section ".note.gnu.property", "a"
+.long 4
+.long 0x10
+.long 0x5
+.asciz "GNU"
+.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
+.long 4
+.long 2          // GNU_PROPERTY_AARCH64_FEATURE_1_PAC
+.long 0
+
+.section ".note.gnu.property", "a"
+.long 4
+.long 24
+.long 5
+.asciz "GNU"
+.long 0xc0000001
+.long 16
+.quad 305419896 // platform
+.quad 2271560481  // version
diff --git a/lld/test/ELF/aarch64-build-attributes-malformed.s b/lld/test/ELF/aarch64-build-attributes-malformed.s
new file mode 100644
index 0000000000000..7787f6e2dbf4d
--- /dev/null
+++ b/lld/test/ELF/aarch64-build-attributes-malformed.s
@@ -0,0 +1,16 @@
+# RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o %t.o
+# RUN: ld.lld %t.o /dev/null 2>&1 | FileCheck %s
+
+# CHECK: (.ARM.attributes): unexpected end of data at offset 0x3f while reading [0x3d, 0x41)
+
+.section .ARM.attributes,"",%0x70000003
+.byte 0x41                               // Tag 'A' (format version)
+.long 0x00000019                         // Subsection length
+.asciz "aeabi_pauthabi"                  // Subsection name
+.byte 0x00, 0x00                         // Optionality and Type
+.byte 0x01, 0x01, 0x02, 0x01             // PAuth_Platform and PAuth_Schema
+.long 0x00000023                         // Subsection length
+.asciz "aeabi_feature_and_bits"          // Subsection name
+.byte 0x01, 0x00                         // Optionality and Type
+.byte 0x00, 0x01, 0x01, 0x01, 0x02, 0x01 // BTI, PAC, GCS
+.byte 0x00, 0x00                         // This is the malformation, data is too long.
diff --git a/lld/test/ELF/aarch64-build-attributes-mixed.s b/lld/test/ELF/aarch64-build-attributes-mixed.s
new file mode 100644
index 0000000000000..729aebcef8d75
--- /dev/null
+++ b/lld/test/ELF/aarch64-build-attributes-mixed.s
@@ -0,0 +1,62 @@
+// RUN: rm -rf %t && split-file %s %t && cd %t
+
+// RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o %t11.o
+// RUN: llvm-mc -triple=aarch64 -filetype=obj merged-mixed-2.s -o %t12.o
+// RUN: llvm-mc -triple=aarch64 -filetype=obj merged-mixed-3.s -o %t13.o
+// RUN: ld.lld -r %t11.o %t12.o %t13.o -o %t.merged1.o
+// RUN: llvm-readelf -n %t.merged1.o | FileCheck %s --check-prefix=NOTE-MIXED
+
+// NOTE-MIXED: Displaying notes found in: .note.gnu.property
+// NOTE-MIXED-NEXT:   Owner                Data size 	Description
+// NOTE-MIXED-NEXT:   GNU                  0x00000028	NT_GNU_PROPERTY_TYPE_0 (property note)
+// NOTE-MIXED-NEXT:     Properties:    aarch64 feature: BTI, PAC
+// NOTE-MIXED-NEXT:         AArch64 PAuth ABI core info: platform 0x31 (unknown), version 0x13
+
+/// The Build attributes section appearing in the output of
+/// llvm-mc should not appear in the output of lld, because
+/// AArch64 build attributes are being transformed into .gnu.properties.
+
+// CHECK: .note.gnu.property
+// CHECK-NOT: .ARM.attributes
+
+.aeabi_subsection aeabi_pauthabi, required, uleb128
+.aeabi_attribute Tag_PAuth_Platform, 49
+.aeabi_attribute Tag_PAuth_Schema, 19
+.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+.aeabi_attribute Tag_Feature_BTI, 1
+.aeabi_attribute Tag_Feature_PAC, 1
+.aeabi_attribute Tag_Feature_GCS, 1
+
+
+//--- merged-mixed-2.s
+.section ".note.gnu.property", "a"
+  .long 4           // Name length is always 4 ("GNU")
+  .long end - begin // Data length
+  .long 5           // Type: NT_GNU_PROPERTY_TYPE_0
+  .asciz "GNU"      // Name
+  .p2align 3
+begin:
+  .long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
+  .long 4
+  .long 7          // GNU_PROPERTY_AARCH64_FEATURE_1_BTI, PAC and GCS
+  .long 0
+  // PAuth ABI property note
+  .long 0xc0000001  // Type: GNU_PROPERTY_AARCH64_FEATURE_PAUTH
+  .long 16          // Data size
+  .quad 49          // PAuth ABI platform
+  .quad 19          // PAuth ABI version
+  .p2align 3        // Align to 8 byte for 64 bit
+end:
+
+//--- merged-mixed-3.s
+.section .note.gnu.property, "a"
+  .align 4
+  .long 4                      // namesz
+  .long 0x10                   // descsz
+  .long 5                      // type (NT_GNU_PROPERTY_TYPE_0)
+  .asciz "GNU"                // name (null-terminated)
+  .align 4
+  .long 0xc0000000             // pr_type (GNU_PROPERTY_AARCH64_FEATURE_1_AND)
+  .long 4                      // pr_datasz
+  .long 7                      // pr_data: BTI (1), PAC (2), GCS (4) = 0b111 = 7
+  .long 0                      // padding or next property
diff --git a/lld/test/ELF/aarch64-build-attributes.s b/lld/test/ELF/aarch64-build-attributes.s
index 24e15f94e3d4a..90a68959a7b23 100644
--- a/lld/test/ELF/aarch64-build-attributes.s
+++ b/lld/test/ELF/aarch64-build-attributes.s
@@ -1,26 +1,49 @@
 // REQUIRES: aarch64
-// RUN: llvm-mc -triple=aarch64 %s -filetype=obj -o %t.o
-// RUN: ld.lld %t.o --shared -o %t.so
-// RUN: llvm-readelf --sections %t.so | FileCheck %s
-// RUN: ld.lld %t.o -o %t
-// RUN: llvm-readelf --sections %t | FileCheck %s
-// RUN: ld.lld -r %t.o -o %t2.o
-// RUN: llvm-readelf --sections %t2.o | FileCheck %s
-
-/// File has a Build attributes section. This should not appear in
-/// ET_EXEC or ET_SHARED files as there is no requirement for it to
-/// do so. FIXME, the ld -r (relocatable link) should output a single
-/// merged build attributes section. When full support is added in
-/// ld.lld this test should be updated.
+// RUN: rm -rf %t && split-file %s %t && cd %t
 
+// RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o %t1.o
+// RUN: llvm-mc -triple=aarch64 -filetype=obj merged-2.s -o %t2.o
+// RUN: llvm-mc -triple=aarch64 -filetype=obj merged-3.s -o %t3.o
+// RUN: ld.lld -r %t1.o %t2.o %t3.o -o %t.merged.o
+// RUN: llvm-readelf -n %t.merged.o | FileCheck %s --check-prefix=NOTE
+
+// NOTE: Displaying notes found in: .note.gnu.property
+// NOTE-NEXT:  Owner                Data size 	Description
+// NOTE-NEXT:  GNU                  0x00000028	NT_GNU_PROPERTY_TYPE_0 (property note)
+// NOTE-NEXT:    Properties:    aarch64 feature: BTI
+// NOTE-NEXT:        AArch64 PAuth ABI core info: platform 0x31 (unknown), version 0x13
+
+/// The Build attributes section appearing in the output of
+/// llvm-mc should not appear in the output of lld, because
+/// AArch64 build attributes are being transformed into .gnu.properties.
+
+// CHECK: .note.gnu.property
 // CHECK-NOT: .ARM.attributes
 
+.aeabi_subsection aeabi_pauthabi, required, uleb128
+.aeabi_attribute Tag_PAuth_Platform, 49
+.aeabi_attribute Tag_PAuth_Schema, 19
 .aeabi_subsection aeabi_feature_and_bits, optional, uleb128
 .aeabi_attribute Tag_Feature_BTI, 1
 .aeabi_attribute Tag_Feature_PAC, 1
 .aeabi_attribute Tag_Feature_GCS, 1
 
-.global _start
-.type _start, %function
-_start:
-ret
+
+//--- merged-2.s
+.aeabi_subsection aeabi_pauthabi, required, uleb128
+.aeabi_attribute Tag_PAuth_Platform, 49
+.aeabi_attribute Tag_PAuth_Schema, 19
+.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+.aeabi_attribute Tag_Feature_BTI, 1
+.aeabi_attribute Tag_Feature_PAC, 0
+.aeabi_attribute Tag_Feature_GCS, 1
+
+
+//--- merged-3.s
+.aeabi_subsection aeabi_pauthabi, required, uleb128
+.aeabi_attribute Tag_PAuth_Platform, 49
+.aeabi_attribute Tag_PAuth_Schema, 19
+.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+.aeabi_attribute Tag_Feature_BTI, 1
+.aeabi_attribute Tag_Feature_PAC, 1
+.aeabi_attribute Tag_Feature_GCS, 0
diff --git a/lld/test/ELF/aarch64-feature-pac-replace.s b/lld/test/ELF/aarch64-feature-pac-replace.s
new file mode 100644
index 0000000000000..c60a430ed850f
--- /dev/null
+++ b/lld/test/ELF/aarch64-feature-pac-replace.s
@@ -0,0 +1,148 @@
+
+### This file replace .note.gnu.property with aarch64 build attributes in order to confirm
+### interoperability.
+### (Still using gnu properties in the helper files)
+
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-pac1.s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-pac1-replace.s -o %t1-ba.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func3.s -o %t2.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func3-pac.s -o %t3.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func3-pac-replace.s -o %t3-ba.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func2.s -o %tno.o
+
+## We do not add PAC support when the inputs don't have the .note.gnu.property
+## field.
+
+# RUN: ld.lld %tno.o %t3.o --shared -o %tno.so
+# RUN: ld.lld %tno.o %t3-ba.o --shared -o %tno-ba.so
+# RUN: llvm-objdump --no-print-imm-hex -d --mattr=+v8.3a --no-show-raw-insn %tno.so | FileCheck --check-prefix=NOPAC %s
+# RUN: llvm-objdump --no-print-imm-hex -d --mattr=+v8.3a --no-show-raw-insn %tno-ba.so | FileCheck --check-prefix=NOPAC %s
+# RUN: llvm-readelf -x .got.plt %tno.so | FileCheck --check-prefix SOGOTPLT %s
+# RUN: llvm-readelf -x .got.plt %tno-ba.so | FileCheck --check-prefix SOGOTPLT %s
+# RUN: llvm-readelf --dynamic-table %tno.so | FileCheck --check-prefix NOPACDYN %s
+# RUN: llvm-readelf --dynamic-table %tno-ba.so | FileCheck --check-prefix NOPACDYN %s
+
+# NOPAC: 00000000000102b8 <func2>:
+# NOPAC-NEXT:    102b8: bl      0x102f0 <func3 at plt>
+# NOPAC-NEXT:           ret
+# NOPAC: Disassembly of section .plt:
+# NOPAC: 00000000000102d0 <.plt>:
+# NOPAC-NEXT:    102d0: stp     x16, x30, [sp, #-16]!
+# NOPAC-NEXT:           adrp    x16, 0x30000
+# NOPAC-NEXT:           ldr     x17, [x16, #960]
+# NOPAC-NEXT:           add     x16, x16, #960
+# NOPAC-NEXT:           br      x17
+# NOPAC-NEXT:           nop
+# NOPAC-NEXT:           nop
+# NOPAC-NEXT:           nop
+# NOPAC: 00000000000102f0 <func3 at plt>:
+# NOPAC-NEXT:    102f0: adrp    x16, 0x30000
+# NOPAC-NEXT:           ldr     x17, [x16, #968]
+# NOPAC-NEXT:           add     x16, x16, #968
+# NOPAC-NEXT:           br      x17
+
+# SOGOTPLT: Hex dump of section '.got.plt':
+# SOGOTPLT-NEXT: 0x000303b0 00000000 00000000 00000000 00000000
+# SOGOTPLT-NEXT: 0x000303c0 00000000 00000000 d0020100 00000000
+
+# NOPACDYN-NOT:   0x0000000070000001 (AARCH64_BTI_PLT)
+# NOPACDYN-NOT:   0x0000000070000003 (AARCH64_PAC_PLT)
+
+
+# RUN: ld.lld %t1.o %t3.o --shared --soname=t.so -o %t.so
+# RUN: ld.lld %t1-ba.o %t3-ba.o --shared --soname=t.so -o %t-ba.so
+# RUN: llvm-readelf -n %t.so | FileCheck --check-prefix PACPROP %s
+# RUN: llvm-readelf -n %t-ba.so | FileCheck --check-prefix PACPROP %s
+# RUN: llvm-objdump --no-print-imm-hex -d --mattr=+v8.3a --no-show-raw-insn %t.so | FileCheck --check-prefix PACSO %s
+# RUN: llvm-objdump --no-print-imm-hex -d --mattr=+v8.3a --no-show-raw-insn %t-ba.so | FileCheck --check-prefix PACSO %s
+# RUN: llvm-readelf -x .got.plt %t.so | FileCheck --check-prefix SOGOTPLT2 %s
+# RUN: llvm-readelf -x .got.plt %t-ba.so | FileCheck --check-prefix SOGOTPLT2 %s
+# RUN: llvm-readelf --dynamic-table %t.so |  FileCheck --check-prefix PACDYN %s
+# RUN: llvm-readelf --dynamic-table %t-ba.so |  FileCheck --check-prefix PACDYN %s
+
+# PACPROP: Properties: aarch64 feature: PAC
+
+# PACSO: Disassembly of section .text:
+# PACSO: 0000000000010348 <func2>:
+# PACSO-NEXT:   10348:      	bl	0x10380 <func3 at plt>
+# PACSO-NEXT:   1034c:      	ret
+# PACSO: 0000000000010350 <func3>:
+# PACSO-NEXT:   10350:      	ret
+# PACSO: Disassembly of section .plt:
+# PACSO: 0000000000010360 <.plt>:
+# PACSO-NEXT:   10360:      	stp	x16, x30, [sp, #-16]!
+# PACSO-NEXT:   10364:      	adrp	x16, 0x30000
+# PACSO-NEXT:   10368:      	ldr	x17, [x16, #1120]
+# PACSO-NEXT:   1036c:      	add	x16, x16, #1120
+# PACSO-NEXT:   10370:      	br	x17
+# PACSO-NEXT:   10374:      	nop
+# PACSO-NEXT:   10378:      	nop
+# PACSO-NEXT:   1037c:      	nop
+# PACSO: 0000000000010380 <func3 at plt>:
+# PACSO-NEXT:   10380:      	adrp	x16, 0x30000
+# PACSO-NEXT:   10384:      	ldr	x17, [x16, #1128]
+# PACSO-NEXT:   10388:      	add	x16, x16, #1128
+# PACSO-NEXT:   1038c:      	br	x17
+
+# SOGOTPLT2: Hex dump of section '.got.plt':
+# SOGOTPLT2-NEXT: 0x00030450 00000000 00000000 00000000 00000000
+# SOGOTPLT2-NEXT: 0x00030460 00000000 00000000 60030100 00000000
+
+# PACDYN-NOT:      0x0000000070000001 (AARCH64_BTI_PLT)
+# PACDYN-NOT:      0x0000000070000003 (AARCH64_PAC_PLT)
+
+
+# RUN: ld.lld %t.o %t2.o -z pac-plt %t.so -o %tpacplt.exe 2>&1 | FileCheck -DFILE=%t2.o --check-prefix WARN %s
+# RUN: ld.lld %t.o %t2.o -z pac-plt %t-ba.so -o %tpacplt-ba.exe 2>&1 | FileCheck -DFILE=%t2.o --check-prefix WARN %s
+
+# WARN: warning: [[FILE]]: -z pac-plt: file does not have GNU_PROPERTY_AARCH64_FEATURE_1_PAC property and no valid PAuth core info present for this link job
+
+
+# RUN: llvm-readelf -n %tpacplt.exe | FileCheck --check-prefix=PACPROP %s
+# RUN: llvm-readelf -n %tpacplt-ba.exe | FileCheck --check-prefix=PACPROP %s
+# RUN: llvm-readelf --dynamic-table %tpacplt.exe | FileCheck --check-prefix PACDYN2 %s
+# RUN: llvm-readelf --dynamic-table %tpacplt-ba.exe | FileCheck --check-prefix PACDYN2 %s
+# RUN: llvm-objdump --no-print-imm-hex -d --mattr=+v8.3a --no-show-raw-insn %tpacplt.exe | FileCheck --check-prefix PACPLT %s
+# RUN: llvm-objdump --no-print-imm-hex -d --mattr=+v8.3a --no-show-raw-insn %tpacplt-ba.exe | FileCheck --check-prefix PACPLT %s
+
+# PACDYN2-NOT:      0x0000000070000001 (AARCH64_BTI_PLT)
+# PACDYN2:      0x0000000070000003 (AARCH64_PAC_PLT)
+
+# PACPLT: Disassembly of section .text:
+# PACPLT: 0000000000210370 <func1>:
+# PACPLT-NEXT:   210370:        bl      0x2103a0 <func2 at plt>
+# PACPLT-NEXT:                  ret
+# PACPLT: 0000000000210378 <func3>:
+# PACPLT-NEXT:   210378:        ret
+# PACPLT: Disassembly of section .plt:
+# PACPLT: 0000000000210380 <.plt>:
+# PACPLT-NEXT:   210380:        stp     x16, x30, [sp, #-16]!
+# PACPLT-NEXT:                  adrp    x16, 0x230000
+# PACPLT-NEXT:                  ldr     x17, [x16, #1192]
+# PACPLT-NEXT:                  add     x16, x16, #1192
+# PACPLT-NEXT:                  br      x17
+# PACPLT-NEXT:                  nop
+# PACPLT-NEXT:                  nop
+# PACPLT-NEXT:                  nop
+# PACPLT: 00000000002103a0 <func2 at plt>:
+# PACPLT-NEXT:   2103a0:        adrp    x16, 0x230000
+# PACPLT-NEXT:                  ldr     x17, [x16, #1200]
+# PACPLT-NEXT:                  add     x16, x16, #1200
+# PACPLT-NEXT:                  autia1716
+# PACPLT-NEXT:                  br      x17
+# PACPLT-NEXT:                  nop
+
+
+.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+.aeabi_attribute Tag_Feature_BTI, 0
+.aeabi_attribute Tag_Feature_PAC, 1
+.aeabi_attribute Tag_Feature_GCS, 0
+
+.text
+.globl _start
+.type func1,%function
+func1:
+  bl func2
+  ret
diff --git a/llvm/include/llvm/Support/AArch64AttributeParser.h b/llvm/include/llvm/Support/AArch64AttributeParser.h
index aa82ca13668d5..796dbfd6f4162 100644
--- a/llvm/include/llvm/Support/AArch64AttributeParser.h
+++ b/llvm/include/llvm/Support/AArch64AttributeParser.h
@@ -25,6 +25,17 @@ class AArch64AttributeParser : public ELFExtendedAttrParser {
       : ELFExtendedAttrParser(nullptr, returnTagsNamesMap()) {}
 };
 
+// Used for extracting AArch64 Build Attributes
+struct AArch64BuildAttrSubsections {
+  struct PauthSubSection {
+    uint64_t TagPlatform = 0;
+    uint64_t TagSchema = 0;
+  } Pauth;
+  uint32_t AndFeatures = 0;
+};
+
+AArch64BuildAttrSubsections
+extractBuildAttributesSubsections(const llvm::AArch64AttributeParser &);
 } // namespace llvm
 
 #endif // LLVM_SUPPORT_AARCH64ATTRIBUTEPARSER_H
diff --git a/llvm/lib/Support/AArch64AttributeParser.cpp b/llvm/lib/Support/AArch64AttributeParser.cpp
index c675ef2a3b3df..eed8dba5d250a 100644
--- a/llvm/lib/Support/AArch64AttributeParser.cpp
+++ b/llvm/lib/Support/AArch64AttributeParser.cpp
@@ -8,6 +8,7 @@
 //===---------------------------------------------------------------------===//
 
 #include "llvm/Support/AArch64AttributeParser.h"
+#include "llvm/Support/AArch64BuildAttributes.h"
 
 std::vector<llvm::SubsectionAndTagToTagName> &
 llvm::AArch64AttributeParser::returnTagsNamesMap() {
@@ -19,3 +20,29 @@ llvm::AArch64AttributeParser::returnTagsNamesMap() {
       {"aeabi_feature_and_bits", 2, "Tag_Feature_GCS"}};
   return TagsNamesMap;
 }
+
+llvm::AArch64BuildAttrSubsections llvm::extractBuildAttributesSubsections(
+    const llvm::AArch64AttributeParser &Attributes) {
+
+  llvm::AArch64BuildAttrSubsections SubSections;
+  auto GetPauthValue = [&Attributes](unsigned Tag) {
+    return Attributes.getAttributeValue("aeabi_pauthabi", Tag).value_or(0);
+  };
+  SubSections.Pauth.TagPlatform =
+      GetPauthValue(llvm::AArch64BuildAttributes::TAG_PAUTH_PLATFORM);
+  SubSections.Pauth.TagSchema =
+      GetPauthValue(llvm::AArch64BuildAttributes::TAG_PAUTH_SCHEMA);
+
+  auto GetFeatureValue = [&Attributes](unsigned Tag) {
+    return Attributes.getAttributeValue("aeabi_feature_and_bits", Tag)
+        .value_or(0);
+  };
+  SubSections.AndFeatures |=
+      GetFeatureValue(llvm::AArch64BuildAttributes::TAG_FEATURE_BTI);
+  SubSections.AndFeatures |=
+      GetFeatureValue(llvm::AArch64BuildAttributes::TAG_FEATURE_PAC) << 1;
+  SubSections.AndFeatures |=
+      GetFeatureValue(llvm::AArch64BuildAttributes::TAG_FEATURE_GCS) << 2;
+
+  return SubSections;
+}



More information about the llvm-commits mailing list