[lld] [llvm] [readobj][Arm][AArch64] Refactor Build Attributes parsing under ELFAtributeParser and add support for AArch64 Build Attributes (PR #128727)

via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 26 02:44:31 PST 2025


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

>From f3a80563c9a66050cf6fd9f49441bb8a8b252bb6 Mon Sep 17 00:00:00 2001
From: Sivan Shani <sivan.shani at arm.com>
Date: Thu, 23 Jan 2025 18:00:32 +0000
Subject: [PATCH 1/5] [readobj][Arm][AArch64] Refactor build attribute parsing
 under ELFAttributeParser and add support for AArch64 Build Attributes

Refactor readobj to integrate AArch64 build attributes under ELFAttributeParser.
ELFAttributeParser now serves as a base class for:
- ELFCompactAttrParser, handling Arm-style attributes with a single build attribute subsection.
- ELFExtendedAttrParser, handling AArch64-style attributes with multiple build attribute subsections.
This improves code organization and better aligns with the attribute parsing model.

Add support for parsing AArch64 Build Attributes.
---
 lld/ELF/Arch/RISCV.cpp                        |  12 +-
 lld/ELF/InputFiles.cpp                        |  10 +-
 llvm/include/llvm/Object/ELFObjectFile.h      |   3 +
 .../llvm/Support/AArch64AttributeParser.h     |  29 +++
 .../llvm/Support/AArch64BuildAttributes.h     |   4 +-
 .../include/llvm/Support/ARMAttributeParser.h |   9 +-
 .../llvm/Support/CSKYAttributeParser.h        |   8 +-
 .../llvm/Support/ELFAttrParserCompact.h       |  82 ++++++++
 .../llvm/Support/ELFAttrParserExtended.h      |  51 +++++
 .../include/llvm/Support/ELFAttributeParser.h |  63 +------
 llvm/include/llvm/Support/ELFAttributes.h     |  29 +++
 .../llvm/Support/HexagonAttributeParser.h     |  12 +-
 .../llvm/Support/MSP430AttributeParser.h      |  10 +-
 .../llvm/Support/RISCVAttributeParser.h       |   9 +-
 llvm/lib/Object/ELFObjectFile.cpp             |  34 ++--
 llvm/lib/Support/AArch64AttributeParser.cpp   |  19 ++
 llvm/lib/Support/AArch64BuildAttributes.cpp   |  26 +--
 llvm/lib/Support/CMakeLists.txt               |   4 +-
 llvm/lib/Support/CSKYAttributeParser.cpp      |  10 +-
 ...uteParser.cpp => ELFAttrParserCompact.cpp} |  36 ++--
 llvm/lib/Support/ELFAttrParserExtended.cpp    | 176 ++++++++++++++++++
 llvm/lib/Support/HexagonAttributeParser.cpp   |  14 +-
 llvm/lib/Support/RISCVAttributeParser.cpp     |   8 +-
 llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp |  67 ++++---
 .../AArch64/AsmParser/AArch64AsmParser.cpp    |  86 ++++-----
 .../MCTargetDesc/AArch64ELFStreamer.cpp       |  51 ++---
 .../MCTargetDesc/AArch64TargetStreamer.cpp    |   4 +-
 .../MCTargetDesc/AArch64TargetStreamer.h      |   9 +-
 .../AArch64/build-attributes-comprehensive.s  |  81 ++++++++
 llvm/tools/llvm-readobj/ELFDumper.cpp         |   7 +
 llvm/unittests/Support/ARMAttributeParser.cpp |   2 +-
 .../Support/CSKYAttributeParserTest.cpp       |   4 +-
 .../Support/ELFAttributeParserTest.cpp        |   8 +-
 .../Support/RISCVAttributeParserTest.cpp      |   2 +-
 34 files changed, 713 insertions(+), 266 deletions(-)
 create mode 100644 llvm/include/llvm/Support/AArch64AttributeParser.h
 create mode 100644 llvm/include/llvm/Support/ELFAttrParserCompact.h
 create mode 100644 llvm/include/llvm/Support/ELFAttrParserExtended.h
 create mode 100644 llvm/lib/Support/AArch64AttributeParser.cpp
 rename llvm/lib/Support/{ELFAttributeParser.cpp => ELFAttrParserCompact.cpp} (85%)
 create mode 100644 llvm/lib/Support/ELFAttrParserExtended.cpp
 create mode 100644 llvm/test/tools/llvm-readobj/ELF/AArch64/build-attributes-comprehensive.s

diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 4d8989a21b501..0f9788640950f 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -1175,7 +1175,7 @@ mergeAttributesSection(Ctx &ctx,
       switch (RISCVAttrs::AttrType(tag.attr)) {
         // Integer attributes.
       case RISCVAttrs::STACK_ALIGN:
-        if (auto i = parser.getAttributeValue(tag.attr)) {
+        if (auto i = parser.getAttributeValue("", tag.attr)) {
           auto r = merged.intAttr.try_emplace(tag.attr, *i);
           if (r.second) {
             firstStackAlign = sec;
@@ -1188,13 +1188,13 @@ mergeAttributesSection(Ctx &ctx,
         }
         continue;
       case RISCVAttrs::UNALIGNED_ACCESS:
-        if (auto i = parser.getAttributeValue(tag.attr))
+        if (auto i = parser.getAttributeValue("", tag.attr))
           merged.intAttr[tag.attr] |= *i;
         continue;
 
         // String attributes.
       case RISCVAttrs::ARCH:
-        if (auto s = parser.getAttributeString(tag.attr)) {
+        if (auto s = parser.getAttributeString("", tag.attr)) {
           hasArch = true;
           mergeArch(ctx, exts, xlen, sec, *s);
         }
@@ -1207,7 +1207,7 @@ mergeAttributesSection(Ctx &ctx,
         break;
 
       case RISCVAttrs::AttrType::ATOMIC_ABI:
-        if (auto i = parser.getAttributeValue(tag.attr)) {
+        if (auto i = parser.getAttributeValue("", tag.attr)) {
           auto r = merged.intAttr.try_emplace(tag.attr, *i);
           if (r.second)
             firstAtomicAbi = sec;
@@ -1225,12 +1225,12 @@ mergeAttributesSection(Ctx &ctx,
       // TODO Adjust after resolution to
       // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/issues/352
       if (tag.attr % 2 == 0) {
-        if (auto i = parser.getAttributeValue(tag.attr)) {
+        if (auto i = parser.getAttributeValue("", tag.attr)) {
           auto r = merged.intAttr.try_emplace(tag.attr, *i);
           if (!r.second && r.first->second != *i)
             r.first->second = 0;
         }
-      } else if (auto s = parser.getAttributeString(tag.attr)) {
+      } else if (auto s = parser.getAttributeString("", tag.attr)) {
         auto r = merged.strAttr.try_emplace(tag.attr, *s);
         if (!r.second && r.first->second != *s)
           r.first->second = {};
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index d43de8ce6dfef..fa94f02819298 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -107,7 +107,7 @@ static ELFKind getELFKind(Ctx &ctx, MemoryBufferRef mb, StringRef archiveName) {
 static void updateARMVFPArgs(Ctx &ctx, const ARMAttributeParser &attributes,
                              const InputFile *f) {
   std::optional<unsigned> attr =
-      attributes.getAttributeValue(ARMBuildAttrs::ABI_VFP_args);
+      attributes.getAttributeValue("", ARMBuildAttrs::ABI_VFP_args);
   if (!attr)
     // If an ABI tag isn't present then it is implicitly given the value of 0
     // which maps to ARMBuildAttrs::BaseAAPCS. However many assembler files,
@@ -155,7 +155,7 @@ static void updateARMVFPArgs(Ctx &ctx, const ARMAttributeParser &attributes,
 static void updateSupportedARMFeatures(Ctx &ctx,
                                        const ARMAttributeParser &attributes) {
   std::optional<unsigned> attr =
-      attributes.getAttributeValue(ARMBuildAttrs::CPU_arch);
+      attributes.getAttributeValue("", ARMBuildAttrs::CPU_arch);
   if (!attr)
     return;
   auto arch = *attr;
@@ -189,7 +189,7 @@ static void updateSupportedARMFeatures(Ctx &ctx,
 
   // Only ARMv8-M or later architectures have CMSE support.
   std::optional<unsigned> profile =
-      attributes.getAttributeValue(ARMBuildAttrs::CPU_arch_profile);
+      attributes.getAttributeValue("", ARMBuildAttrs::CPU_arch_profile);
   if (!profile)
     return;
   if (arch >= ARMBuildAttrs::CPUArch::v8_M_Base &&
@@ -200,9 +200,9 @@ static void updateSupportedARMFeatures(Ctx &ctx,
   // For now, let's limit it to ones where ARM isn't available and we know have
   // Thumb2.
   std::optional<unsigned> armISA =
-      attributes.getAttributeValue(ARMBuildAttrs::ARM_ISA_use);
+      attributes.getAttributeValue("", ARMBuildAttrs::ARM_ISA_use);
   std::optional<unsigned> thumb =
-      attributes.getAttributeValue(ARMBuildAttrs::THUMB_ISA_use);
+      attributes.getAttributeValue("", ARMBuildAttrs::THUMB_ISA_use);
   ctx.arg.armHasArmISA |= armISA && *armISA >= ARMBuildAttrs::Allowed;
   ctx.arg.armHasThumb2ISA |= thumb && *thumb >= ARMBuildAttrs::AllowThumb32;
 }
diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h
index 60c72062a3f6a..bafc92cafe539 100644
--- a/llvm/include/llvm/Object/ELFObjectFile.h
+++ b/llvm/include/llvm/Object/ELFObjectFile.h
@@ -410,6 +410,9 @@ template <class ELFT> class ELFObjectFile : public ELFObjectFileBase {
     case ELF::EM_ARM:
       Type = ELF::SHT_ARM_ATTRIBUTES;
       break;
+    case ELF::EM_AARCH64:
+      Type = ELF::SHT_AARCH64_ATTRIBUTES;
+      break;
     case ELF::EM_RISCV:
       Type = ELF::SHT_RISCV_ATTRIBUTES;
       break;
diff --git a/llvm/include/llvm/Support/AArch64AttributeParser.h b/llvm/include/llvm/Support/AArch64AttributeParser.h
new file mode 100644
index 0000000000000..add18fa3349fe
--- /dev/null
+++ b/llvm/include/llvm/Support/AArch64AttributeParser.h
@@ -0,0 +1,29 @@
+//=== - AArch64AttributeParser.h-AArch64 Attribute Information Printer - ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_AARCH64ATTRIBUTEPARSER_H
+#define LLVM_SUPPORT_AARCH64ATTRIBUTEPARSER_H
+
+#include "llvm/Support/ELFAttrParserExtended.h"
+#include "llvm/Support/ELFAttributes.h"
+
+namespace llvm {
+
+class AArch64AttributeParser : public ELFExtendedAttrParser {
+  static const std::vector<SubsectionAndTagToTagName> returnTagsNamesMap();
+
+public:
+  AArch64AttributeParser(ScopedPrinter *Sw)
+      : ELFExtendedAttrParser(Sw, returnTagsNamesMap()) {}
+  AArch64AttributeParser()
+      : ELFExtendedAttrParser(nullptr, returnTagsNamesMap()) {}
+};
+
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_AARCH64ATTRIBUTEPARSER_H
diff --git a/llvm/include/llvm/Support/AArch64BuildAttributes.h b/llvm/include/llvm/Support/AArch64BuildAttributes.h
index 2479992cf8e79..ea293b72f9bb1 100644
--- a/llvm/include/llvm/Support/AArch64BuildAttributes.h
+++ b/llvm/include/llvm/Support/AArch64BuildAttributes.h
@@ -22,7 +22,7 @@
 
 namespace llvm {
 
-namespace AArch64BuildAttrs {
+namespace AArch64BuildAttributes {
 
 /// AArch64 build attributes vendors IDs (a.k.a subsection name)
 enum VendorID : unsigned {
@@ -69,7 +69,7 @@ enum FeatureAndBitsFlag : unsigned {
   Feature_PAC_Flag = 1 << 1,
   Feature_GCS_Flag = 1 << 2
 };
-} // namespace AArch64BuildAttrs
+} // namespace AArch64BuildAttributes
 } // namespace llvm
 
 #endif // LLVM_SUPPORT_AARCH64BUILDATTRIBUTES_H
\ No newline at end of file
diff --git a/llvm/include/llvm/Support/ARMAttributeParser.h b/llvm/include/llvm/Support/ARMAttributeParser.h
index d1d953120ae7e..749f9cd2213d7 100644
--- a/llvm/include/llvm/Support/ARMAttributeParser.h
+++ b/llvm/include/llvm/Support/ARMAttributeParser.h
@@ -10,15 +10,15 @@
 #define LLVM_SUPPORT_ARMATTRIBUTEPARSER_H
 
 #include "ARMBuildAttributes.h"
-#include "ELFAttributeParser.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ELFAttrParserCompact.h"
 #include "llvm/Support/Error.h"
 
 namespace llvm {
 
 class ScopedPrinter;
 
-class ARMAttributeParser : public ELFAttributeParser {
+class ARMAttributeParser : public ELFCompactAttrParser {
   struct DisplayHandler {
     ARMBuildAttrs::AttrType attribute;
     Error (ARMAttributeParser::*routine)(ARMBuildAttrs::AttrType);
@@ -74,9 +74,10 @@ class ARMAttributeParser : public ELFAttributeParser {
 
 public:
   ARMAttributeParser(ScopedPrinter *sw)
-      : ELFAttributeParser(sw, ARMBuildAttrs::getARMAttributeTags(), "aeabi") {}
+      : ELFCompactAttrParser(sw, ARMBuildAttrs::getARMAttributeTags(),
+                             "aeabi") {}
   ARMAttributeParser()
-      : ELFAttributeParser(ARMBuildAttrs::getARMAttributeTags(), "aeabi") {}
+      : ELFCompactAttrParser(ARMBuildAttrs::getARMAttributeTags(), "aeabi") {}
 };
 }
 
diff --git a/llvm/include/llvm/Support/CSKYAttributeParser.h b/llvm/include/llvm/Support/CSKYAttributeParser.h
index e926ebe5e306e..08257a744a959 100644
--- a/llvm/include/llvm/Support/CSKYAttributeParser.h
+++ b/llvm/include/llvm/Support/CSKYAttributeParser.h
@@ -10,10 +10,10 @@
 #define LLVM_SUPPORT_CSKYATTRIBUTEPARSER_H
 
 #include "llvm/Support/CSKYAttributes.h"
-#include "llvm/Support/ELFAttributeParser.h"
+#include "llvm/Support/ELFAttrParserCompact.h"
 
 namespace llvm {
-class CSKYAttributeParser : public ELFAttributeParser {
+class CSKYAttributeParser : public ELFCompactAttrParser {
   struct DisplayHandler {
     CSKYAttrs::AttrType attribute;
     Error (CSKYAttributeParser::*routine)(unsigned);
@@ -33,9 +33,9 @@ class CSKYAttributeParser : public ELFAttributeParser {
 
 public:
   CSKYAttributeParser(ScopedPrinter *sw)
-      : ELFAttributeParser(sw, CSKYAttrs::getCSKYAttributeTags(), "csky") {}
+      : ELFCompactAttrParser(sw, CSKYAttrs::getCSKYAttributeTags(), "csky") {}
   CSKYAttributeParser()
-      : ELFAttributeParser(CSKYAttrs::getCSKYAttributeTags(), "csky") {}
+      : ELFCompactAttrParser(CSKYAttrs::getCSKYAttributeTags(), "csky") {}
 };
 
 } // namespace llvm
diff --git a/llvm/include/llvm/Support/ELFAttrParserCompact.h b/llvm/include/llvm/Support/ELFAttrParserCompact.h
new file mode 100644
index 0000000000000..cb2710ec631af
--- /dev/null
+++ b/llvm/include/llvm/Support/ELFAttrParserCompact.h
@@ -0,0 +1,82 @@
+//===- ELF AttributeParser.h - ELF Attribute Parser -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ELFCOMPACTATTRPARSER_H
+#define LLVM_SUPPORT_ELFCOMPACTATTRPARSER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/ELFAttributeParser.h"
+#include "llvm/Support/ELFAttributes.h"
+#include "llvm/Support/Error.h"
+
+#include <optional>
+#include <unordered_map>
+
+namespace llvm {
+class StringRef;
+class ScopedPrinter;
+
+class ELFCompactAttrParser : public ELFAttributeParser {
+  StringRef vendor;
+  std::unordered_map<unsigned, unsigned> attributes;
+  std::unordered_map<unsigned, StringRef> attributesStr;
+
+  virtual Error handler(uint64_t tag, bool &handled) = 0;
+
+protected:
+  ScopedPrinter *sw;
+  TagNameMap tagToStringMap;
+  DataExtractor de{ArrayRef<uint8_t>{}, true, 0};
+  DataExtractor::Cursor cursor{0};
+
+  void printAttribute(unsigned tag, unsigned value, StringRef valueDesc);
+
+  Error parseStringAttribute(const char *name, unsigned tag,
+                             ArrayRef<const char *> strings);
+  Error parseAttributeList(uint32_t length);
+  void parseIndexList(SmallVectorImpl<uint8_t> &indexList);
+  Error parseSubsection(uint32_t length);
+
+  void setAttributeString(unsigned tag, StringRef value) {
+    attributesStr.emplace(tag, value);
+  }
+
+public:
+  virtual ~ELFCompactAttrParser() { static_cast<void>(!cursor.takeError()); }
+  Error integerAttribute(unsigned tag);
+  Error stringAttribute(unsigned tag);
+
+  ELFCompactAttrParser(ScopedPrinter *sw, TagNameMap tagNameMap,
+                       StringRef vendor)
+      : vendor(vendor), sw(sw), tagToStringMap(tagNameMap) {}
+  ELFCompactAttrParser(TagNameMap tagNameMap, StringRef vendor)
+      : vendor(vendor), sw(nullptr), tagToStringMap(tagNameMap) {}
+
+  Error parse(ArrayRef<uint8_t> section, llvm::endianness endian) override;
+
+  std::optional<unsigned>
+  getAttributeValue(StringRef buildAttributeSubsectionName,
+                    unsigned tag) const override {
+    auto I = attributes.find(tag);
+    if (I == attributes.end())
+      return std::nullopt;
+    return I->second;
+  }
+  std::optional<StringRef>
+  getAttributeString(StringRef buildAttributeSubsectionName,
+                     unsigned tag) const override {
+    auto I = attributesStr.find(tag);
+    if (I == attributesStr.end())
+      return std::nullopt;
+    return I->second;
+  }
+};
+
+} // namespace llvm
+#endif // LLVM_SUPPORT_ELFCOMPACTATTRPARSER_H
diff --git a/llvm/include/llvm/Support/ELFAttrParserExtended.h b/llvm/include/llvm/Support/ELFAttrParserExtended.h
new file mode 100644
index 0000000000000..5fc1371173313
--- /dev/null
+++ b/llvm/include/llvm/Support/ELFAttrParserExtended.h
@@ -0,0 +1,51 @@
+//===- ELF AttributeParser.h - ELF Attribute Parser -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ELFEXTENDEDATTRPARSER_H
+#define LLVM_SUPPORT_ELFEXTENDEDATTRPARSER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/ELFAttributeParser.h"
+#include "llvm/Support/ELFAttributes.h"
+#include "llvm/Support/Error.h"
+#include <optional>
+#include <vector>
+
+namespace llvm {
+class StringRef;
+class ScopedPrinter;
+
+class ELFExtendedAttrParser : public ELFAttributeParser {
+protected:
+  ScopedPrinter *Sw;
+  DataExtractor De{ArrayRef<uint8_t>{}, true, 0};
+  DataExtractor::Cursor Cursor{0};
+
+  // Data structure for holding Extended ELF Build Attribute subsection
+  SmallVector<BuildAttributeSubSection, 64> SubSectionVec;
+  // Maps SubsectionName + Tag to tags names. Required for printing comments.
+  const std::vector<SubsectionAndTagToTagName> TagsNamesMap;
+  StringRef getTagName(const StringRef &s, const unsigned i);
+
+public:
+  Error parse(ArrayRef<uint8_t> Section, llvm::endianness Endian) override;
+
+  std::optional<unsigned> getAttributeValue(StringRef BuildAttrSubsectionName,
+                                            unsigned Tag) const override;
+  std::optional<StringRef> getAttributeString(StringRef BuildAttrSubsectionName,
+                                              unsigned Tag) const override;
+
+  ELFExtendedAttrParser(ScopedPrinter *Sw,
+                        std::vector<SubsectionAndTagToTagName> TagsNamesMap)
+      : Sw(Sw), TagsNamesMap(TagsNamesMap) {}
+  ELFExtendedAttrParser(std::vector<SubsectionAndTagToTagName> TagsNamesMap)
+      : Sw(nullptr), TagsNamesMap(TagsNamesMap) {}
+};
+} // namespace llvm
+#endif // LLVM_SUPPORT_ELFEXTENDEDATTRPARSER_H
diff --git a/llvm/include/llvm/Support/ELFAttributeParser.h b/llvm/include/llvm/Support/ELFAttributeParser.h
index ffb92468fb37e..1eeaaea3bf356 100644
--- a/llvm/include/llvm/Support/ELFAttributeParser.h
+++ b/llvm/include/llvm/Support/ELFAttributeParser.h
@@ -9,69 +9,22 @@
 #ifndef LLVM_SUPPORT_ELFATTRIBUTEPARSER_H
 #define LLVM_SUPPORT_ELFATTRIBUTEPARSER_H
 
-#include "ELFAttributes.h"
 #include "llvm/ADT/ArrayRef.h"
-#include "llvm/Support/DataExtractor.h"
+#include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Error.h"
 
-#include <optional>
-#include <unordered_map>
-
 namespace llvm {
-class StringRef;
-class ScopedPrinter;
 
 class ELFAttributeParser {
-  StringRef vendor;
-  std::unordered_map<unsigned, unsigned> attributes;
-  std::unordered_map<unsigned, StringRef> attributesStr;
-
-  virtual Error handler(uint64_t tag, bool &handled) = 0;
-
-protected:
-  ScopedPrinter *sw;
-  TagNameMap tagToStringMap;
-  DataExtractor de{ArrayRef<uint8_t>{}, true, 0};
-  DataExtractor::Cursor cursor{0};
-
-  void printAttribute(unsigned tag, unsigned value, StringRef valueDesc);
-
-  Error parseStringAttribute(const char *name, unsigned tag,
-                             ArrayRef<const char *> strings);
-  Error parseAttributeList(uint32_t length);
-  void parseIndexList(SmallVectorImpl<uint8_t> &indexList);
-  Error parseSubsection(uint32_t length);
-
-  void setAttributeString(unsigned tag, StringRef value) {
-    attributesStr.emplace(tag, value);
-  }
-
 public:
-  virtual ~ELFAttributeParser() { static_cast<void>(!cursor.takeError()); }
-  Error integerAttribute(unsigned tag);
-  Error stringAttribute(unsigned tag);
-
-  ELFAttributeParser(ScopedPrinter *sw, TagNameMap tagNameMap, StringRef vendor)
-      : vendor(vendor), sw(sw), tagToStringMap(tagNameMap) {}
-
-  ELFAttributeParser(TagNameMap tagNameMap, StringRef vendor)
-      : vendor(vendor), sw(nullptr), tagToStringMap(tagNameMap) {}
-
-  Error parse(ArrayRef<uint8_t> section, llvm::endianness endian);
+  virtual ~ELFAttributeParser() {}
 
-  std::optional<unsigned> getAttributeValue(unsigned tag) const {
-    auto I = attributes.find(tag);
-    if (I == attributes.end())
-      return std::nullopt;
-    return I->second;
-  }
-  std::optional<StringRef> getAttributeString(unsigned tag) const {
-    auto I = attributesStr.find(tag);
-    if (I == attributesStr.end())
-      return std::nullopt;
-    return I->second;
-  }
+  virtual Error parse(ArrayRef<uint8_t> Section, llvm::endianness Endian);
+  virtual std::optional<unsigned>
+  getAttributeValue(StringRef BuildAttrSubsectionName, unsigned Tag) const;
+  virtual std::optional<StringRef>
+  getAttributeString(StringRef BuildAttrSubsectionName, unsigned Tag) const;
 };
 
 } // namespace llvm
-#endif
+#endif // LLVM_SUPPORT_ELFATTRIBUTEPARSER_H
diff --git a/llvm/include/llvm/Support/ELFAttributes.h b/llvm/include/llvm/Support/ELFAttributes.h
index 295d0f4669812..6782aec6050ad 100644
--- a/llvm/include/llvm/Support/ELFAttributes.h
+++ b/llvm/include/llvm/Support/ELFAttributes.h
@@ -15,6 +15,7 @@
 
 namespace llvm {
 
+// Tag to string: ELF compact build attribute section
 struct TagNameItem {
   unsigned attr;
   StringRef tagName;
@@ -22,6 +23,34 @@ struct TagNameItem {
 
 using TagNameMap = ArrayRef<TagNameItem>;
 
+// Build Attribute storage for ELF extended attribute section
+struct BuildAttributeItem {
+  enum Types : uint8_t {
+    NumericAttribute = 0,
+    TextAttribute,
+  } Type;
+  unsigned Tag;
+  unsigned IntValue;
+  std::string StringValue;
+  BuildAttributeItem(Types Ty, unsigned Tg, unsigned IV, std::string SV)
+      : Type(Ty), Tag(Tg), IntValue(IV), StringValue(std::move(SV)) {}
+};
+struct BuildAttributeSubSection {
+  StringRef Name;
+  unsigned IsOptional;
+  unsigned ParameterType;
+  SmallVector<BuildAttributeItem, 64> Content;
+};
+
+// Tag to string: ELF extended build attribute section
+struct SubsectionAndTagToTagName {
+  StringRef SubsectionName;
+  unsigned Tag;
+  StringRef TagName;
+  SubsectionAndTagToTagName(StringRef SN, unsigned Tg, StringRef TN)
+      : SubsectionName(SN), Tag(Tg), TagName(TN) {}
+};
+
 namespace ELFAttrs {
 
 enum AttrType : unsigned { File = 1, Section = 2, Symbol = 3 };
diff --git a/llvm/include/llvm/Support/HexagonAttributeParser.h b/llvm/include/llvm/Support/HexagonAttributeParser.h
index 1116dd42b1ad0..462bfc4e2df1e 100644
--- a/llvm/include/llvm/Support/HexagonAttributeParser.h
+++ b/llvm/include/llvm/Support/HexagonAttributeParser.h
@@ -9,11 +9,11 @@
 #ifndef LLVM_SUPPORT_HEXAGONATTRIBUTEPARSER_H
 #define LLVM_SUPPORT_HEXAGONATTRIBUTEPARSER_H
 
-#include "llvm/Support/ELFAttributeParser.h"
+#include "llvm/Support/ELFAttrParserCompact.h"
 #include "llvm/Support/HexagonAttributes.h"
 
 namespace llvm {
-class HexagonAttributeParser : public ELFAttributeParser {
+class HexagonAttributeParser : public ELFCompactAttrParser {
   struct DisplayHandler {
     HexagonAttrs::AttrType Attribute;
     Error (HexagonAttributeParser::*Routine)(unsigned);
@@ -25,11 +25,11 @@ class HexagonAttributeParser : public ELFAttributeParser {
 
 public:
   HexagonAttributeParser(ScopedPrinter *SP)
-      : ELFAttributeParser(SP, HexagonAttrs::getHexagonAttributeTags(),
-                           "hexagon") {}
+      : ELFCompactAttrParser(SP, HexagonAttrs::getHexagonAttributeTags(),
+                             "hexagon") {}
   HexagonAttributeParser()
-      : ELFAttributeParser(HexagonAttrs::getHexagonAttributeTags(), "hexagon") {
-  }
+      : ELFCompactAttrParser(HexagonAttrs::getHexagonAttributeTags(),
+                             "hexagon") {}
 };
 
 } // namespace llvm
diff --git a/llvm/include/llvm/Support/MSP430AttributeParser.h b/llvm/include/llvm/Support/MSP430AttributeParser.h
index bc9b214944708..3a4f1b43d9d18 100644
--- a/llvm/include/llvm/Support/MSP430AttributeParser.h
+++ b/llvm/include/llvm/Support/MSP430AttributeParser.h
@@ -14,11 +14,11 @@
 #ifndef LLVM_SUPPORT_MSP430ATTRIBUTEPARSER_H
 #define LLVM_SUPPORT_MSP430ATTRIBUTEPARSER_H
 
-#include "llvm/Support/ELFAttributeParser.h"
+#include "llvm/Support/ELFAttrParserCompact.h"
 #include "llvm/Support/MSP430Attributes.h"
 
 namespace llvm {
-class MSP430AttributeParser : public ELFAttributeParser {
+class MSP430AttributeParser : public ELFCompactAttrParser {
   struct DisplayHandler {
     MSP430Attrs::AttrType Attribute;
     Error (MSP430AttributeParser::*Routine)(MSP430Attrs::AttrType);
@@ -34,10 +34,10 @@ class MSP430AttributeParser : public ELFAttributeParser {
 
 public:
   MSP430AttributeParser(ScopedPrinter *SW)
-      : ELFAttributeParser(SW, MSP430Attrs::getMSP430AttributeTags(),
-                           "mspabi") {}
+      : ELFCompactAttrParser(SW, MSP430Attrs::getMSP430AttributeTags(),
+                             "mspabi") {}
   MSP430AttributeParser()
-      : ELFAttributeParser(MSP430Attrs::getMSP430AttributeTags(), "mspabi") {}
+      : ELFCompactAttrParser(MSP430Attrs::getMSP430AttributeTags(), "mspabi") {}
 };
 } // namespace llvm
 
diff --git a/llvm/include/llvm/Support/RISCVAttributeParser.h b/llvm/include/llvm/Support/RISCVAttributeParser.h
index 9f295504de959..4a74ed321d7a2 100644
--- a/llvm/include/llvm/Support/RISCVAttributeParser.h
+++ b/llvm/include/llvm/Support/RISCVAttributeParser.h
@@ -9,11 +9,11 @@
 #ifndef LLVM_SUPPORT_RISCVATTRIBUTEPARSER_H
 #define LLVM_SUPPORT_RISCVATTRIBUTEPARSER_H
 
-#include "llvm/Support/ELFAttributeParser.h"
+#include "llvm/Support/ELFAttrParserCompact.h"
 #include "llvm/Support/RISCVAttributes.h"
 
 namespace llvm {
-class RISCVAttributeParser : public ELFAttributeParser {
+class RISCVAttributeParser : public ELFCompactAttrParser {
   struct DisplayHandler {
     RISCVAttrs::AttrType attribute;
     Error (RISCVAttributeParser::*routine)(unsigned);
@@ -28,9 +28,10 @@ class RISCVAttributeParser : public ELFAttributeParser {
 
 public:
   RISCVAttributeParser(ScopedPrinter *sw)
-      : ELFAttributeParser(sw, RISCVAttrs::getRISCVAttributeTags(), "riscv") {}
+      : ELFCompactAttrParser(sw, RISCVAttrs::getRISCVAttributeTags(), "riscv") {
+  }
   RISCVAttributeParser()
-      : ELFAttributeParser(RISCVAttrs::getRISCVAttributeTags(), "riscv") {}
+      : ELFCompactAttrParser(RISCVAttrs::getRISCVAttributeTags(), "riscv") {}
 };
 
 } // namespace llvm
diff --git a/llvm/lib/Object/ELFObjectFile.cpp b/llvm/lib/Object/ELFObjectFile.cpp
index ac25d76709726..a0f381274f4f9 100644
--- a/llvm/lib/Object/ELFObjectFile.cpp
+++ b/llvm/lib/Object/ELFObjectFile.cpp
@@ -168,11 +168,11 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const {
   // both ARMv7-M and R have to support thumb hardware div
   bool isV7 = false;
   std::optional<unsigned> Attr =
-      Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch);
+      Attributes.getAttributeValue("", ARMBuildAttrs::CPU_arch);
   if (Attr)
     isV7 = *Attr == ARMBuildAttrs::v7;
 
-  Attr = Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch_profile);
+  Attr = Attributes.getAttributeValue("", ARMBuildAttrs::CPU_arch_profile);
   if (Attr) {
     switch (*Attr) {
     case ARMBuildAttrs::ApplicationProfile:
@@ -191,7 +191,7 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const {
     }
   }
 
-  Attr = Attributes.getAttributeValue(ARMBuildAttrs::THUMB_ISA_use);
+  Attr = Attributes.getAttributeValue("", ARMBuildAttrs::THUMB_ISA_use);
   if (Attr) {
     switch (*Attr) {
     default:
@@ -206,7 +206,7 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const {
     }
   }
 
-  Attr = Attributes.getAttributeValue(ARMBuildAttrs::FP_arch);
+  Attr = Attributes.getAttributeValue("", ARMBuildAttrs::FP_arch);
   if (Attr) {
     switch (*Attr) {
     default:
@@ -230,7 +230,7 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const {
     }
   }
 
-  Attr = Attributes.getAttributeValue(ARMBuildAttrs::Advanced_SIMD_arch);
+  Attr = Attributes.getAttributeValue("", ARMBuildAttrs::Advanced_SIMD_arch);
   if (Attr) {
     switch (*Attr) {
     default:
@@ -249,7 +249,7 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const {
     }
   }
 
-  Attr = Attributes.getAttributeValue(ARMBuildAttrs::MVE_arch);
+  Attr = Attributes.getAttributeValue("", ARMBuildAttrs::MVE_arch);
   if (Attr) {
     switch (*Attr) {
     default:
@@ -268,7 +268,7 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const {
     }
   }
 
-  Attr = Attributes.getAttributeValue(ARMBuildAttrs::DIV_use);
+  Attr = Attributes.getAttributeValue("", ARMBuildAttrs::DIV_use);
   if (Attr) {
     switch (*Attr) {
     default:
@@ -327,13 +327,13 @@ SubtargetFeatures ELFObjectFileBase::getHexagonFeatures() const {
   }
   std::optional<unsigned> Attr;
 
-  if ((Attr = Parser.getAttributeValue(HexagonAttrs::ARCH))) {
+  if ((Attr = Parser.getAttributeValue("", HexagonAttrs::ARCH))) {
     if (std::optional<std::string> FeatureString =
             hexagonAttrToFeatureString(*Attr))
       Features.AddFeature(*FeatureString);
   }
 
-  if ((Attr = Parser.getAttributeValue(HexagonAttrs::HVXARCH))) {
+  if ((Attr = Parser.getAttributeValue("", HexagonAttrs::HVXARCH))) {
     std::optional<std::string> FeatureString =
         hexagonAttrToFeatureString(*Attr);
     // There is no corresponding hvx arch for v5 and v55.
@@ -341,23 +341,23 @@ SubtargetFeatures ELFObjectFileBase::getHexagonFeatures() const {
       Features.AddFeature("hvx" + *FeatureString);
   }
 
-  if ((Attr = Parser.getAttributeValue(HexagonAttrs::HVXIEEEFP)))
+  if ((Attr = Parser.getAttributeValue("", HexagonAttrs::HVXIEEEFP)))
     if (*Attr)
       Features.AddFeature("hvx-ieee-fp");
 
-  if ((Attr = Parser.getAttributeValue(HexagonAttrs::HVXQFLOAT)))
+  if ((Attr = Parser.getAttributeValue("", HexagonAttrs::HVXQFLOAT)))
     if (*Attr)
       Features.AddFeature("hvx-qfloat");
 
-  if ((Attr = Parser.getAttributeValue(HexagonAttrs::ZREG)))
+  if ((Attr = Parser.getAttributeValue("", HexagonAttrs::ZREG)))
     if (*Attr)
       Features.AddFeature("zreg");
 
-  if ((Attr = Parser.getAttributeValue(HexagonAttrs::AUDIO)))
+  if ((Attr = Parser.getAttributeValue("", HexagonAttrs::AUDIO)))
     if (*Attr)
       Features.AddFeature("audio");
 
-  if ((Attr = Parser.getAttributeValue(HexagonAttrs::CABAC)))
+  if ((Attr = Parser.getAttributeValue("", HexagonAttrs::CABAC)))
     if (*Attr)
       Features.AddFeature("cabac");
 
@@ -378,7 +378,7 @@ Expected<SubtargetFeatures> ELFObjectFileBase::getRISCVFeatures() const {
   }
 
   std::optional<StringRef> Attr =
-      Attributes.getAttributeString(RISCVAttrs::ARCH);
+      Attributes.getAttributeString("", RISCVAttrs::ARCH);
   if (Attr) {
     auto ParseResult = RISCVISAInfo::parseNormalizedArchString(*Attr);
     if (!ParseResult)
@@ -703,7 +703,7 @@ void ELFObjectFileBase::setARMSubArch(Triple &TheTriple) const {
     Triple = "arm";
 
   std::optional<unsigned> Attr =
-      Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch);
+      Attributes.getAttributeValue("", ARMBuildAttrs::CPU_arch);
   if (Attr) {
     switch (*Attr) {
     case ARMBuildAttrs::v4:
@@ -735,7 +735,7 @@ void ELFObjectFileBase::setARMSubArch(Triple &TheTriple) const {
       break;
     case ARMBuildAttrs::v7: {
       std::optional<unsigned> ArchProfileAttr =
-          Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch_profile);
+          Attributes.getAttributeValue("", ARMBuildAttrs::CPU_arch_profile);
       if (ArchProfileAttr &&
           *ArchProfileAttr == ARMBuildAttrs::MicroControllerProfile)
         Triple += "v7m";
diff --git a/llvm/lib/Support/AArch64AttributeParser.cpp b/llvm/lib/Support/AArch64AttributeParser.cpp
new file mode 100644
index 0000000000000..031d871e3a2e7
--- /dev/null
+++ b/llvm/lib/Support/AArch64AttributeParser.cpp
@@ -0,0 +1,19 @@
+//===-- AArch64AttributeParser.cpp - AArch64 Build Attributes PArser------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with
+// LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#include "llvm/Support/AArch64AttributeParser.h"
+
+const std::vector<llvm::SubsectionAndTagToTagName>
+llvm::AArch64AttributeParser::returnTagsNamesMap() {
+  return {{"aeabi_pauthabi", 1, "Tag_PAuth_Platform"},
+          {"aeabi_pauthabi", 2, "Tag_PAuth_Schema"},
+          {"aeabi_feature_and_bits", 0, "Tag_Feature_BTI"},
+          {"aeabi_feature_and_bits", 1, "Tag_Feature_PAC"},
+          {"aeabi_feature_and_bits", 2, "Tag_Feature_GCS"}};
+}
diff --git a/llvm/lib/Support/AArch64BuildAttributes.cpp b/llvm/lib/Support/AArch64BuildAttributes.cpp
index e36667ca711e0..4a6b2fd538803 100644
--- a/llvm/lib/Support/AArch64BuildAttributes.cpp
+++ b/llvm/lib/Support/AArch64BuildAttributes.cpp
@@ -10,9 +10,9 @@
 #include "llvm/ADT/StringSwitch.h"
 
 using namespace llvm;
-using namespace llvm::AArch64BuildAttrs;
+using namespace llvm::AArch64BuildAttributes;
 
-StringRef AArch64BuildAttrs::getVendorName(unsigned Vendor) {
+StringRef AArch64BuildAttributes::getVendorName(unsigned Vendor) {
   switch (Vendor) {
   case AEABI_FEATURE_AND_BITS:
     return "aeabi_feature_and_bits";
@@ -25,14 +25,14 @@ StringRef AArch64BuildAttrs::getVendorName(unsigned Vendor) {
     return "";
   }
 }
-VendorID AArch64BuildAttrs::getVendorID(StringRef Vendor) {
+VendorID AArch64BuildAttributes::getVendorID(StringRef Vendor) {
   return StringSwitch<VendorID>(Vendor)
       .Case("aeabi_feature_and_bits", AEABI_FEATURE_AND_BITS)
       .Case("aeabi_pauthabi", AEABI_PAUTHABI)
       .Default(VENDOR_UNKNOWN);
 }
 
-StringRef AArch64BuildAttrs::getOptionalStr(unsigned Optional) {
+StringRef AArch64BuildAttributes::getOptionalStr(unsigned Optional) {
   switch (Optional) {
   case REQUIRED:
     return "required";
@@ -43,18 +43,18 @@ StringRef AArch64BuildAttrs::getOptionalStr(unsigned Optional) {
     return "";
   }
 }
-SubsectionOptional AArch64BuildAttrs::getOptionalID(StringRef Optional) {
+SubsectionOptional AArch64BuildAttributes::getOptionalID(StringRef Optional) {
   return StringSwitch<SubsectionOptional>(Optional)
       .Case("required", REQUIRED)
       .Case("optional", OPTIONAL)
       .Default(OPTIONAL_NOT_FOUND);
 }
-StringRef AArch64BuildAttrs::getSubsectionOptionalUnknownError() {
+StringRef AArch64BuildAttributes::getSubsectionOptionalUnknownError() {
   return "unknown AArch64 build attributes optionality, expected "
          "required|optional";
 }
 
-StringRef AArch64BuildAttrs::getTypeStr(unsigned Type) {
+StringRef AArch64BuildAttributes::getTypeStr(unsigned Type) {
   switch (Type) {
   case ULEB128:
     return "uleb128";
@@ -65,17 +65,17 @@ StringRef AArch64BuildAttrs::getTypeStr(unsigned Type) {
     return "";
   }
 }
-SubsectionType AArch64BuildAttrs::getTypeID(StringRef Type) {
+SubsectionType AArch64BuildAttributes::getTypeID(StringRef Type) {
   return StringSwitch<SubsectionType>(Type)
       .Cases("uleb128", "ULEB128", ULEB128)
       .Cases("ntbs", "NTBS", NTBS)
       .Default(TYPE_NOT_FOUND);
 }
-StringRef AArch64BuildAttrs::getSubsectionTypeUnknownError() {
+StringRef AArch64BuildAttributes::getSubsectionTypeUnknownError() {
   return "unknown AArch64 build attributes type, expected uleb128|ntbs";
 }
 
-StringRef AArch64BuildAttrs::getPauthABITagsStr(unsigned PauthABITag) {
+StringRef AArch64BuildAttributes::getPauthABITagsStr(unsigned PauthABITag) {
   switch (PauthABITag) {
   case TAG_PAUTH_PLATFORM:
     return "Tag_PAuth_Platform";
@@ -87,7 +87,7 @@ StringRef AArch64BuildAttrs::getPauthABITagsStr(unsigned PauthABITag) {
   }
 }
 
-PauthABITags AArch64BuildAttrs::getPauthABITagsID(StringRef PauthABITag) {
+PauthABITags AArch64BuildAttributes::getPauthABITagsID(StringRef PauthABITag) {
   return StringSwitch<PauthABITags>(PauthABITag)
       .Case("Tag_PAuth_Platform", TAG_PAUTH_PLATFORM)
       .Case("Tag_PAuth_Schema", TAG_PAUTH_SCHEMA)
@@ -95,7 +95,7 @@ PauthABITags AArch64BuildAttrs::getPauthABITagsID(StringRef PauthABITag) {
 }
 
 StringRef
-AArch64BuildAttrs::getFeatureAndBitsTagsStr(unsigned FeatureAndBitsTag) {
+AArch64BuildAttributes::getFeatureAndBitsTagsStr(unsigned FeatureAndBitsTag) {
   switch (FeatureAndBitsTag) {
   case TAG_FEATURE_BTI:
     return "Tag_Feature_BTI";
@@ -110,7 +110,7 @@ AArch64BuildAttrs::getFeatureAndBitsTagsStr(unsigned FeatureAndBitsTag) {
 }
 
 FeatureAndBitsTags
-AArch64BuildAttrs::getFeatureAndBitsTagsID(StringRef FeatureAndBitsTag) {
+AArch64BuildAttributes::getFeatureAndBitsTagsID(StringRef FeatureAndBitsTag) {
   return StringSwitch<FeatureAndBitsTags>(FeatureAndBitsTag)
       .Case("Tag_Feature_BTI", TAG_FEATURE_BTI)
       .Case("Tag_Feature_PAC", TAG_FEATURE_PAC)
diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt
index a6d8a25818866..49a26a618de83 100644
--- a/llvm/lib/Support/CMakeLists.txt
+++ b/llvm/lib/Support/CMakeLists.txt
@@ -144,6 +144,7 @@ add_llvm_component_library(LLVMSupport
   APInt.cpp
   APSInt.cpp
   ARMBuildAttributes.cpp
+  AArch64AttributeParser.cpp
   AArch64BuildAttributes.cpp
   ARMAttributeParser.cpp
   ARMWinEH.cpp
@@ -182,8 +183,9 @@ add_llvm_component_library(LLVMSupport
   DAGDeltaAlgorithm.cpp
   DJB.cpp
   DynamicAPInt.cpp
-  ELFAttributeParser.cpp
   ELFAttributes.cpp
+  ELFAttrParserCompact.cpp
+  ELFAttrParserExtended.cpp
   Error.cpp
   ErrorHandling.cpp
   ExponentialBackoff.cpp
diff --git a/llvm/lib/Support/CSKYAttributeParser.cpp b/llvm/lib/Support/CSKYAttributeParser.cpp
index 40ee617b981b2..1e46bf8127df6 100644
--- a/llvm/lib/Support/CSKYAttributeParser.cpp
+++ b/llvm/lib/Support/CSKYAttributeParser.cpp
@@ -16,19 +16,19 @@ const CSKYAttributeParser::DisplayHandler
     CSKYAttributeParser::displayRoutines[] = {
         {
             CSKYAttrs::CSKY_ARCH_NAME,
-            &ELFAttributeParser::stringAttribute,
+            &ELFCompactAttrParser::stringAttribute,
         },
         {
             CSKYAttrs::CSKY_CPU_NAME,
-            &ELFAttributeParser::stringAttribute,
+            &ELFCompactAttrParser::stringAttribute,
         },
         {
             CSKYAttrs::CSKY_ISA_FLAGS,
-            &ELFAttributeParser::integerAttribute,
+            &ELFCompactAttrParser::integerAttribute,
         },
         {
             CSKYAttrs::CSKY_ISA_EXT_FLAGS,
-            &ELFAttributeParser::integerAttribute,
+            &ELFCompactAttrParser::integerAttribute,
         },
         {
             CSKYAttrs::CSKY_DSP_VERSION,
@@ -60,7 +60,7 @@ const CSKYAttributeParser::DisplayHandler
         },
         {
             CSKYAttrs::CSKY_FPU_NUMBER_MODULE,
-            &ELFAttributeParser::stringAttribute,
+            &ELFCompactAttrParser::stringAttribute,
         },
         {
             CSKYAttrs::CSKY_FPU_HARDFP,
diff --git a/llvm/lib/Support/ELFAttributeParser.cpp b/llvm/lib/Support/ELFAttrParserCompact.cpp
similarity index 85%
rename from llvm/lib/Support/ELFAttributeParser.cpp
rename to llvm/lib/Support/ELFAttrParserCompact.cpp
index 26c3d54e17ade..4880083177cb8 100644
--- a/llvm/lib/Support/ELFAttributeParser.cpp
+++ b/llvm/lib/Support/ELFAttrParserCompact.cpp
@@ -1,12 +1,15 @@
-//===--- ELFAttributeParser.cpp - ELF Attribute Parser --------------------===//
+//===--- ELFCompactAttrParser.cpp - ELF Compact Attribute Parser ------  ===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
-//===----------------------------------------------------------------------===//
+// ELF Compact Attribute Parser parse ELF build atrributes that are held
+// in a single Build Attributes Subsection.
+//
+//===--------------------------------------------------------------------===//
 
-#include "llvm/Support/ELFAttributeParser.h"
+#include "llvm/Support/ELFAttrParserCompact.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/Errc.h"
 #include "llvm/Support/ScopedPrinter.h"
@@ -20,8 +23,8 @@ static constexpr EnumEntry<unsigned> tagNames[] = {
     {"Tag_Symbol", ELFAttrs::Symbol},
 };
 
-Error ELFAttributeParser::parseStringAttribute(const char *name, unsigned tag,
-                                               ArrayRef<const char *> strings) {
+Error ELFCompactAttrParser::parseStringAttribute(
+    const char *name, unsigned tag, ArrayRef<const char *> strings) {
   uint64_t value = de.getULEB128(cursor);
   if (value >= strings.size()) {
     printAttribute(tag, value, "");
@@ -33,7 +36,7 @@ Error ELFAttributeParser::parseStringAttribute(const char *name, unsigned tag,
   return Error::success();
 }
 
-Error ELFAttributeParser::integerAttribute(unsigned tag) {
+Error ELFCompactAttrParser::integerAttribute(unsigned tag) {
   StringRef tagName =
       ELFAttrs::attrTypeAsString(tag, tagToStringMap, /*hasTagPrefix=*/false);
   uint64_t value = de.getULEB128(cursor);
@@ -49,7 +52,7 @@ Error ELFAttributeParser::integerAttribute(unsigned tag) {
   return Error::success();
 }
 
-Error ELFAttributeParser::stringAttribute(unsigned tag) {
+Error ELFCompactAttrParser::stringAttribute(unsigned tag) {
   StringRef tagName =
       ELFAttrs::attrTypeAsString(tag, tagToStringMap, /*hasTagPrefix=*/false);
   StringRef desc = de.getCStrRef(cursor);
@@ -65,8 +68,8 @@ Error ELFAttributeParser::stringAttribute(unsigned tag) {
   return Error::success();
 }
 
-void ELFAttributeParser::printAttribute(unsigned tag, unsigned value,
-                                        StringRef valueDesc) {
+void ELFCompactAttrParser::printAttribute(unsigned tag, unsigned value,
+                                          StringRef valueDesc) {
   attributes.insert(std::make_pair(tag, value));
 
   if (sw) {
@@ -82,7 +85,7 @@ void ELFAttributeParser::printAttribute(unsigned tag, unsigned value,
   }
 }
 
-void ELFAttributeParser::parseIndexList(SmallVectorImpl<uint8_t> &indexList) {
+void ELFCompactAttrParser::parseIndexList(SmallVectorImpl<uint8_t> &indexList) {
   for (;;) {
     uint64_t value = de.getULEB128(cursor);
     if (!cursor || !value)
@@ -91,7 +94,7 @@ void ELFAttributeParser::parseIndexList(SmallVectorImpl<uint8_t> &indexList) {
   }
 }
 
-Error ELFAttributeParser::parseAttributeList(uint32_t length) {
+Error ELFCompactAttrParser::parseAttributeList(uint32_t length) {
   uint64_t pos;
   uint64_t end = cursor.tell() + length;
   while ((pos = cursor.tell()) < end) {
@@ -119,7 +122,7 @@ Error ELFAttributeParser::parseAttributeList(uint32_t length) {
   return Error::success();
 }
 
-Error ELFAttributeParser::parseSubsection(uint32_t length) {
+Error ELFCompactAttrParser::parseSubsection(uint32_t length) {
   uint64_t end = cursor.tell() - sizeof(length) + length;
   StringRef vendorName = de.getCStrRef(cursor);
   if (sw) {
@@ -128,9 +131,8 @@ Error ELFAttributeParser::parseSubsection(uint32_t length) {
   }
 
   // Handle a subsection with an unrecognized vendor-name by skipping
-  // over it to the next subsection. ADDENDA32 in the Arm ABI defines
-  // that vendor attribute sections must not affect compatibility, so
-  // this should always be safe.
+  // over it to the next subsection. vendor attribute sections must not
+  // affect compatibility, so this should always be safe.
   if (vendorName.lower() != vendor) {
     cursor.seek(end);
     return Error::success();
@@ -188,8 +190,8 @@ Error ELFAttributeParser::parseSubsection(uint32_t length) {
   return Error::success();
 }
 
-Error ELFAttributeParser::parse(ArrayRef<uint8_t> section,
-                                llvm::endianness endian) {
+Error ELFCompactAttrParser::parse(ArrayRef<uint8_t> section,
+                                  llvm::endianness endian) {
   unsigned sectionNumber = 0;
   de = DataExtractor(section, endian == llvm::endianness::little, 0);
 
diff --git a/llvm/lib/Support/ELFAttrParserExtended.cpp b/llvm/lib/Support/ELFAttrParserExtended.cpp
new file mode 100644
index 0000000000000..138bc99aa69ff
--- /dev/null
+++ b/llvm/lib/Support/ELFAttrParserExtended.cpp
@@ -0,0 +1,176 @@
+//===-ELFAttrParserExtended.cpp-ELF Extended Attribute Information Printer-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM
+// Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===------------------------------------------------------------------===//
+
+#include "llvm/Support/ELFAttrParserExtended.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/AArch64BuildAttributes.h"
+#include "llvm/Support/ELFAttributes.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdint>
+
+using namespace llvm;
+using namespace ELFAttrs;
+
+std::optional<unsigned>
+ELFExtendedAttrParser::getAttributeValue(StringRef BuildAttrSubsectionName,
+                                         unsigned Tag) const {
+  for (auto SubSection : SubSectionVec) {
+    if (BuildAttrSubsectionName == SubSection.Name)
+      for (auto BAItem : SubSection.Content) {
+        if (Tag == BAItem.Tag)
+          return std::optional<unsigned>(BAItem.IntValue);
+      }
+  }
+  return std::nullopt;
+}
+
+std::optional<StringRef>
+ELFExtendedAttrParser::getAttributeString(StringRef BuildAttrSubsectionName,
+                                          unsigned Tag) const {
+  for (auto SubSection : SubSectionVec) {
+    if (BuildAttrSubsectionName == SubSection.Name)
+      for (auto BAItem : SubSection.Content) {
+        if (Tag == BAItem.Tag)
+          return std::optional<StringRef>(BAItem.StringValue);
+      }
+  }
+  return std::nullopt;
+}
+
+StringRef ELFExtendedAttrParser::getTagName(const StringRef &s,
+                                            const unsigned i) {
+  for (const auto &entry : TagsNamesMap) {
+    if (s == entry.SubsectionName) {
+      if (i == entry.Tag) {
+        return entry.TagName;
+      }
+    }
+  }
+  return "";
+}
+
+Error ELFExtendedAttrParser::parse(ArrayRef<uint8_t> Section,
+                                   llvm::endianness Endian) {
+
+  unsigned SectionNumber = 0;
+  De = DataExtractor(Section, Endian == llvm::endianness::little, 0);
+
+  // Early returns have specific errors. Consume the Error in Cursor.
+  struct ClearCursorError {
+    DataExtractor::Cursor &Cursor;
+    ~ClearCursorError() { consumeError(Cursor.takeError()); }
+  } Clear{Cursor};
+
+  /*
+      ELF Extended Build Attributes Layout:
+      <format-version: ‘A’> --> Currently, there is only one version: 'A' (0x41)
+      [ <uint32: subsection-length> <NTBS: vendor-name> <bytes: vendor-data> ]
+        --> subsection-length: Offset from the start of this subsection to the
+     start of the next one.
+        --> vendor-name: Null-terminated byte string.
+        --> vendor-data expands to:
+          [ <uint8: optional> <uint8: parameter type> <attribute>* ]
+            --> optional: 0 = required, 1 = optional.
+            --> parameter type: 0 = ULEB128, 1 = NTBS.
+            --> attribute: <tag, value>* pair. Tag is ULEB128, value is of
+     <parameter type>.
+  */
+
+  // Get format-version
+  uint8_t FormatVersion = De.getU8(Cursor);
+  if (ELFAttrs::Format_Version != FormatVersion)
+    return createStringError(errc::invalid_argument,
+                             "unrecognized format-version: 0x" +
+                                 utohexstr(FormatVersion));
+
+  while (!De.eof(Cursor)) {
+    uint32_t ExtBASubsectionLength = De.getU32(Cursor);
+    // Minimal valid Extended Build Attributes subsection header size is at
+    // least 8: length(4) name(at least a single char + null) optionality(1) and
+    // type(1)
+    if (ExtBASubsectionLength < 8)
+      return createStringError(
+          errc::invalid_argument,
+          "invalid Extended Build Attributes subsection size at offset: " +
+              utohexstr(Cursor.tell() - 4));
+
+    StringRef VendorName = De.getCStrRef(Cursor);
+    uint8_t IsOptional = De.getU8(Cursor);
+    StringRef IsOptionalStr = IsOptional ? "optional" : "required";
+    uint8_t Type = De.getU8(Cursor);
+    StringRef TypeStr = Type ? "ntbs" : "uleb128";
+
+    BuildAttributeSubSection BASubSection;
+    BASubSection.Name = VendorName;
+    BASubSection.IsOptional = IsOptional;
+    BASubSection.ParameterType = Type;
+
+    if (Sw) {
+      Sw->startLine() << "Section " << ++SectionNumber << " {\n";
+      Sw->indent();
+      Sw->printNumber("SectionLength", ExtBASubsectionLength);
+      Sw->startLine() << "VendorName" << ": " << VendorName
+                      << " Optionality: " << IsOptionalStr
+                      << " Type: " << TypeStr << "\n";
+      Sw->startLine() << "Attributes {\n";
+      Sw->indent();
+    }
+
+    // Offset in Section
+    uint64_t OffsetInSection = Cursor.tell();
+    // Size: 4 bytes, Vendor Name: VendorName.size() + 1 (null termination),
+    // optionality: 1, size: 1
+    uint32_t BytesAllButAttributes = 4 + (VendorName.size() + 1) + 1 + 1;
+    while (Cursor.tell() <
+           (OffsetInSection + ExtBASubsectionLength - BytesAllButAttributes)) {
+
+      uint64_t Tag = De.getULEB128(Cursor);
+      std::string Str = utostr(Tag);
+      StringRef TagStr(Str);
+
+      StringRef TagAsString = getTagName(VendorName, Tag);
+      if ("" != TagAsString)
+        TagStr = TagAsString;
+
+      uint64_t ValueInt = 0;
+      std::string ValueStr = "";
+      if (Type) { // type==1 --> ntbs
+        StringRef Value = De.getCStrRef(Cursor);
+        if (Sw)
+          Sw->printString(TagStr, Value);
+      } else { // type==0 --> uleb128
+        uint64_t Value = De.getULEB128(Cursor);
+        if (Sw)
+          Sw->printNumber(TagStr, Value);
+      }
+
+      // populate data structure
+      BuildAttributeItem BAItem(static_cast<BuildAttributeItem::Types>(Type),
+                                Tag, ValueInt, ValueStr);
+      BASubSection.Content.push_back(BAItem);
+    }
+    if (Sw) {
+      // Close 'Attributes'
+      Sw->unindent();
+      Sw->startLine() << "}\n";
+      // Close 'Section'
+      Sw->unindent();
+      Sw->startLine() << "}\n";
+    }
+
+    // populate data structure
+    SubSectionVec.push_back(BASubSection);
+  }
+
+  return Cursor.takeError();
+}
diff --git a/llvm/lib/Support/HexagonAttributeParser.cpp b/llvm/lib/Support/HexagonAttributeParser.cpp
index 2143162d11c79..3baa976574930 100644
--- a/llvm/lib/Support/HexagonAttributeParser.cpp
+++ b/llvm/lib/Support/HexagonAttributeParser.cpp
@@ -14,31 +14,31 @@ const HexagonAttributeParser::DisplayHandler
     HexagonAttributeParser::DisplayRoutines[] = {
         {
             HexagonAttrs::ARCH,
-            &ELFAttributeParser::integerAttribute,
+            &ELFCompactAttrParser::integerAttribute,
         },
         {
             HexagonAttrs::HVXARCH,
-            &ELFAttributeParser::integerAttribute,
+            &ELFCompactAttrParser::integerAttribute,
         },
         {
             HexagonAttrs::HVXIEEEFP,
-            &ELFAttributeParser::integerAttribute,
+            &ELFCompactAttrParser::integerAttribute,
         },
         {
             HexagonAttrs::HVXQFLOAT,
-            &ELFAttributeParser::integerAttribute,
+            &ELFCompactAttrParser::integerAttribute,
         },
         {
             HexagonAttrs::ZREG,
-            &ELFAttributeParser::integerAttribute,
+            &ELFCompactAttrParser::integerAttribute,
         },
         {
             HexagonAttrs::AUDIO,
-            &ELFAttributeParser::integerAttribute,
+            &ELFCompactAttrParser::integerAttribute,
         },
         {
             HexagonAttrs::CABAC,
-            &ELFAttributeParser::integerAttribute,
+            &ELFCompactAttrParser::integerAttribute,
         }};
 
 Error HexagonAttributeParser::handler(uint64_t Tag, bool &Handled) {
diff --git a/llvm/lib/Support/RISCVAttributeParser.cpp b/llvm/lib/Support/RISCVAttributeParser.cpp
index 20392e4bae19f..41c48859566e4 100644
--- a/llvm/lib/Support/RISCVAttributeParser.cpp
+++ b/llvm/lib/Support/RISCVAttributeParser.cpp
@@ -15,19 +15,19 @@ const RISCVAttributeParser::DisplayHandler
     RISCVAttributeParser::displayRoutines[] = {
         {
             RISCVAttrs::ARCH,
-            &ELFAttributeParser::stringAttribute,
+            &ELFCompactAttrParser::stringAttribute,
         },
         {
             RISCVAttrs::PRIV_SPEC,
-            &ELFAttributeParser::integerAttribute,
+            &ELFCompactAttrParser::integerAttribute,
         },
         {
             RISCVAttrs::PRIV_SPEC_MINOR,
-            &ELFAttributeParser::integerAttribute,
+            &ELFCompactAttrParser::integerAttribute,
         },
         {
             RISCVAttrs::PRIV_SPEC_REVISION,
-            &ELFAttributeParser::integerAttribute,
+            &ELFCompactAttrParser::integerAttribute,
         },
         {
             RISCVAttrs::STACK_ALIGN,
diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index fc38bfe93c1e0..6216315766fc8 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -361,7 +361,7 @@ void AArch64AsmPrinter::emitStartOfAsmFile(Module &M) {
   if (const auto *BTE = mdconst::extract_or_null<ConstantInt>(
           M.getModuleFlag("branch-target-enforcement"))) {
     if (!BTE->isZero()) {
-      BAFlags |= AArch64BuildAttrs::FeatureAndBitsFlag::Feature_BTI_Flag;
+      BAFlags |= AArch64BuildAttributes::FeatureAndBitsFlag::Feature_BTI_Flag;
       GNUFlags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
     }
   }
@@ -369,7 +369,7 @@ void AArch64AsmPrinter::emitStartOfAsmFile(Module &M) {
   if (const auto *GCS = mdconst::extract_or_null<ConstantInt>(
           M.getModuleFlag("guarded-control-stack"))) {
     if (!GCS->isZero()) {
-      BAFlags |= AArch64BuildAttrs::FeatureAndBitsFlag::Feature_GCS_Flag;
+      BAFlags |= AArch64BuildAttributes::FeatureAndBitsFlag::Feature_GCS_Flag;
       GNUFlags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
     }
   }
@@ -377,7 +377,7 @@ void AArch64AsmPrinter::emitStartOfAsmFile(Module &M) {
   if (const auto *Sign = mdconst::extract_or_null<ConstantInt>(
           M.getModuleFlag("sign-return-address"))) {
     if (!Sign->isZero()) {
-      BAFlags |= AArch64BuildAttrs::FeatureAndBitsFlag::Feature_PAC_Flag;
+      BAFlags |= AArch64BuildAttributes::FeatureAndBitsFlag::Feature_PAC_Flag;
       GNUFlags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_PAC;
     }
   }
@@ -480,35 +480,42 @@ void AArch64AsmPrinter::emitAttributes(unsigned Flags,
 
   if (PAuthABIPlatform || PAuthABIVersion) {
     TS->emitAtributesSubsection(
-        AArch64BuildAttrs::getVendorName(AArch64BuildAttrs::AEABI_PAUTHABI),
-        AArch64BuildAttrs::SubsectionOptional::REQUIRED,
-        AArch64BuildAttrs::SubsectionType::ULEB128);
-    TS->emitAttribute(
-        AArch64BuildAttrs::getVendorName(AArch64BuildAttrs::AEABI_PAUTHABI),
-        AArch64BuildAttrs::TAG_PAUTH_PLATFORM, PAuthABIPlatform, "");
-    TS->emitAttribute(
-        AArch64BuildAttrs::getVendorName(AArch64BuildAttrs::AEABI_PAUTHABI),
-        AArch64BuildAttrs::TAG_PAUTH_SCHEMA, PAuthABIVersion, "");
-  }
-
-  unsigned BTIValue = (Flags & AArch64BuildAttrs::Feature_BTI_Flag) ? 1 : 0;
-  unsigned PACValue = (Flags & AArch64BuildAttrs::Feature_PAC_Flag) ? 1 : 0;
-  unsigned GCSValue = (Flags & AArch64BuildAttrs::Feature_GCS_Flag) ? 1 : 0;
+        AArch64BuildAttributes::getVendorName(
+            AArch64BuildAttributes::AEABI_PAUTHABI),
+        AArch64BuildAttributes::SubsectionOptional::REQUIRED,
+        AArch64BuildAttributes::SubsectionType::ULEB128);
+    TS->emitAttribute(AArch64BuildAttributes::getVendorName(
+                          AArch64BuildAttributes::AEABI_PAUTHABI),
+                      AArch64BuildAttributes::TAG_PAUTH_PLATFORM,
+                      PAuthABIPlatform, "");
+    TS->emitAttribute(AArch64BuildAttributes::getVendorName(
+                          AArch64BuildAttributes::AEABI_PAUTHABI),
+                      AArch64BuildAttributes::TAG_PAUTH_SCHEMA, PAuthABIVersion,
+                      "");
+  }
+
+  unsigned BTIValue =
+      (Flags & AArch64BuildAttributes::Feature_BTI_Flag) ? 1 : 0;
+  unsigned PACValue =
+      (Flags & AArch64BuildAttributes::Feature_PAC_Flag) ? 1 : 0;
+  unsigned GCSValue =
+      (Flags & AArch64BuildAttributes::Feature_GCS_Flag) ? 1 : 0;
 
   if (BTIValue || PACValue || GCSValue) {
-    TS->emitAtributesSubsection(AArch64BuildAttrs::getVendorName(
-                                    AArch64BuildAttrs::AEABI_FEATURE_AND_BITS),
-                                AArch64BuildAttrs::SubsectionOptional::OPTIONAL,
-                                AArch64BuildAttrs::SubsectionType::ULEB128);
-    TS->emitAttribute(AArch64BuildAttrs::getVendorName(
-                          AArch64BuildAttrs::AEABI_FEATURE_AND_BITS),
-                      AArch64BuildAttrs::TAG_FEATURE_BTI, BTIValue, "");
-    TS->emitAttribute(AArch64BuildAttrs::getVendorName(
-                          AArch64BuildAttrs::AEABI_FEATURE_AND_BITS),
-                      AArch64BuildAttrs::TAG_FEATURE_PAC, PACValue, "");
-    TS->emitAttribute(AArch64BuildAttrs::getVendorName(
-                          AArch64BuildAttrs::AEABI_FEATURE_AND_BITS),
-                      AArch64BuildAttrs::TAG_FEATURE_GCS, GCSValue, "");
+    TS->emitAtributesSubsection(
+        AArch64BuildAttributes::getVendorName(
+            AArch64BuildAttributes::AEABI_FEATURE_AND_BITS),
+        AArch64BuildAttributes::SubsectionOptional::OPTIONAL,
+        AArch64BuildAttributes::SubsectionType::ULEB128);
+    TS->emitAttribute(AArch64BuildAttributes::getVendorName(
+                          AArch64BuildAttributes::AEABI_FEATURE_AND_BITS),
+                      AArch64BuildAttributes::TAG_FEATURE_BTI, BTIValue, "");
+    TS->emitAttribute(AArch64BuildAttributes::getVendorName(
+                          AArch64BuildAttributes::AEABI_FEATURE_AND_BITS),
+                      AArch64BuildAttributes::TAG_FEATURE_PAC, PACValue, "");
+    TS->emitAttribute(AArch64BuildAttributes::getVendorName(
+                          AArch64BuildAttributes::AEABI_FEATURE_AND_BITS),
+                      AArch64BuildAttributes::TAG_FEATURE_GCS, GCSValue, "");
   }
 }
 
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 6a973b0160e23..1e7296fa23486 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -7847,10 +7847,10 @@ bool AArch64AsmParser::parseDirectiveAeabiSubSectionHeader(SMLoc L) {
 
   // Consume the name (subsection name)
   StringRef SubsectionName;
-  AArch64BuildAttrs::VendorID SubsectionNameID;
+  AArch64BuildAttributes::VendorID SubsectionNameID;
   if (Parser.getTok().is(AsmToken::Identifier)) {
     SubsectionName = Parser.getTok().getIdentifier();
-    SubsectionNameID = AArch64BuildAttrs::getVendorID(SubsectionName);
+    SubsectionNameID = AArch64BuildAttributes::getVendorID(SubsectionName);
   } else {
     Error(Parser.getTok().getLoc(), "subsection name not found");
     return true;
@@ -7867,14 +7867,14 @@ bool AArch64AsmParser::parseDirectiveAeabiSubSectionHeader(SMLoc L) {
       getTargetStreamer().getAtributesSubsectionByName(SubsectionName);
 
   // Consume the first parameter (optionality parameter)
-  AArch64BuildAttrs::SubsectionOptional IsOptional;
+  AArch64BuildAttributes::SubsectionOptional IsOptional;
   // options: optional/required
   if (Parser.getTok().is(AsmToken::Identifier)) {
     StringRef Optionality = Parser.getTok().getIdentifier();
-    IsOptional = AArch64BuildAttrs::getOptionalID(Optionality);
-    if (AArch64BuildAttrs::OPTIONAL_NOT_FOUND == IsOptional) {
+    IsOptional = AArch64BuildAttributes::getOptionalID(Optionality);
+    if (AArch64BuildAttributes::OPTIONAL_NOT_FOUND == IsOptional) {
       Error(Parser.getTok().getLoc(),
-            AArch64BuildAttrs::getSubsectionOptionalUnknownError());
+            AArch64BuildAttributes::getSubsectionOptionalUnknownError());
       return true;
     }
     if (SubsectionExists) {
@@ -7882,10 +7882,10 @@ bool AArch64AsmParser::parseDirectiveAeabiSubSectionHeader(SMLoc L) {
         Error(Parser.getTok().getLoc(),
               "optionality mismatch! subsection '" + SubsectionName +
                   "' already exists with optionality defined as '" +
-                  AArch64BuildAttrs::getOptionalStr(
+                  AArch64BuildAttributes::getOptionalStr(
                       SubsectionExists->IsOptional) +
                   "' and not '" +
-                  AArch64BuildAttrs::getOptionalStr(IsOptional) + "'");
+                  AArch64BuildAttributes::getOptionalStr(IsOptional) + "'");
         return true;
       }
     }
@@ -7895,15 +7895,15 @@ bool AArch64AsmParser::parseDirectiveAeabiSubSectionHeader(SMLoc L) {
     return true;
   }
   // Check for possible IsOptional unaccepted values for known subsections
-  if (AArch64BuildAttrs::AEABI_FEATURE_AND_BITS == SubsectionNameID) {
-    if (AArch64BuildAttrs::REQUIRED == IsOptional) {
+  if (AArch64BuildAttributes::AEABI_FEATURE_AND_BITS == SubsectionNameID) {
+    if (AArch64BuildAttributes::REQUIRED == IsOptional) {
       Error(Parser.getTok().getLoc(),
             "aeabi_feature_and_bits must be marked as optional");
       return true;
     }
   }
-  if (AArch64BuildAttrs::AEABI_PAUTHABI == SubsectionNameID) {
-    if (AArch64BuildAttrs::OPTIONAL == IsOptional) {
+  if (AArch64BuildAttributes::AEABI_PAUTHABI == SubsectionNameID) {
+    if (AArch64BuildAttributes::OPTIONAL == IsOptional) {
       Error(Parser.getTok().getLoc(),
             "aeabi_pauthabi must be marked as required");
       return true;
@@ -7916,23 +7916,24 @@ bool AArch64AsmParser::parseDirectiveAeabiSubSectionHeader(SMLoc L) {
   }
 
   // Consume the second parameter (type parameter)
-  AArch64BuildAttrs::SubsectionType Type;
+  AArch64BuildAttributes::SubsectionType Type;
   if (Parser.getTok().is(AsmToken::Identifier)) {
     StringRef Name = Parser.getTok().getIdentifier();
-    Type = AArch64BuildAttrs::getTypeID(Name);
-    if (AArch64BuildAttrs::TYPE_NOT_FOUND == Type) {
+    Type = AArch64BuildAttributes::getTypeID(Name);
+    if (AArch64BuildAttributes::TYPE_NOT_FOUND == Type) {
       Error(Parser.getTok().getLoc(),
-            AArch64BuildAttrs::getSubsectionTypeUnknownError());
+            AArch64BuildAttributes::getSubsectionTypeUnknownError());
       return true;
     }
     if (SubsectionExists) {
       if (Type != SubsectionExists->ParameterType) {
-        Error(
-            Parser.getTok().getLoc(),
-            "type mismatch! subsection '" + SubsectionName +
-                "' already exists with type defined as '" +
-                AArch64BuildAttrs::getTypeStr(SubsectionExists->ParameterType) +
-                "' and not '" + AArch64BuildAttrs::getTypeStr(Type) + "'");
+        Error(Parser.getTok().getLoc(),
+              "type mismatch! subsection '" + SubsectionName +
+                  "' already exists with type defined as '" +
+                  AArch64BuildAttributes::getTypeStr(
+                      SubsectionExists->ParameterType) +
+                  "' and not '" + AArch64BuildAttributes::getTypeStr(Type) +
+                  "'");
         return true;
       }
     }
@@ -7942,9 +7943,9 @@ bool AArch64AsmParser::parseDirectiveAeabiSubSectionHeader(SMLoc L) {
     return true;
   }
   // Check for possible unaccepted 'type' values for known subsections
-  if (AArch64BuildAttrs::AEABI_FEATURE_AND_BITS == SubsectionNameID ||
-      AArch64BuildAttrs::AEABI_PAUTHABI == SubsectionNameID) {
-    if (AArch64BuildAttrs::NTBS == Type) {
+  if (AArch64BuildAttributes::AEABI_FEATURE_AND_BITS == SubsectionNameID ||
+      AArch64BuildAttributes::AEABI_PAUTHABI == SubsectionNameID) {
+    if (AArch64BuildAttributes::NTBS == Type) {
       Error(Parser.getTok().getLoc(),
             SubsectionName + " must be marked as ULEB128");
       return true;
@@ -7980,13 +7981,14 @@ bool AArch64AsmParser::parseDirectiveAeabiAArch64Attr(SMLoc L) {
   StringRef ActiveSubsectionName = ActiveSubsection->VendorName;
   unsigned ActiveSubsectionType = ActiveSubsection->ParameterType;
 
-  unsigned ActiveSubsectionID = AArch64BuildAttrs::VENDOR_UNKNOWN;
-  if (AArch64BuildAttrs::getVendorName(AArch64BuildAttrs::AEABI_PAUTHABI) ==
+  unsigned ActiveSubsectionID = AArch64BuildAttributes::VENDOR_UNKNOWN;
+  if (AArch64BuildAttributes::getVendorName(
+          AArch64BuildAttributes::AEABI_PAUTHABI) == ActiveSubsectionName)
+    ActiveSubsectionID = AArch64BuildAttributes::AEABI_PAUTHABI;
+  if (AArch64BuildAttributes::getVendorName(
+          AArch64BuildAttributes::AEABI_FEATURE_AND_BITS) ==
       ActiveSubsectionName)
-    ActiveSubsectionID = AArch64BuildAttrs::AEABI_PAUTHABI;
-  if (AArch64BuildAttrs::getVendorName(
-          AArch64BuildAttrs::AEABI_FEATURE_AND_BITS) == ActiveSubsectionName)
-    ActiveSubsectionID = AArch64BuildAttrs::AEABI_FEATURE_AND_BITS;
+    ActiveSubsectionID = AArch64BuildAttributes::AEABI_FEATURE_AND_BITS;
 
   StringRef TagStr = "";
   unsigned Tag;
@@ -7995,7 +7997,7 @@ bool AArch64AsmParser::parseDirectiveAeabiAArch64Attr(SMLoc L) {
   } else if (Parser.getTok().is(AsmToken::Identifier)) {
     TagStr = Parser.getTok().getIdentifier();
     switch (ActiveSubsectionID) {
-    case AArch64BuildAttrs::VENDOR_UNKNOWN:
+    case AArch64BuildAttributes::VENDOR_UNKNOWN:
       // Tag was provided as an unrecognized string instead of an unsigned
       // integer
       Error(Parser.getTok().getLoc(), "unrecognized Tag: '" + TagStr +
@@ -8003,18 +8005,18 @@ bool AArch64AsmParser::parseDirectiveAeabiAArch64Attr(SMLoc L) {
                                           "tags have to be an unsigned int.");
       return true;
       break;
-    case AArch64BuildAttrs::AEABI_PAUTHABI:
-      Tag = AArch64BuildAttrs::getPauthABITagsID(TagStr);
-      if (AArch64BuildAttrs::PAUTHABI_TAG_NOT_FOUND == Tag) {
+    case AArch64BuildAttributes::AEABI_PAUTHABI:
+      Tag = AArch64BuildAttributes::getPauthABITagsID(TagStr);
+      if (AArch64BuildAttributes::PAUTHABI_TAG_NOT_FOUND == Tag) {
         Error(Parser.getTok().getLoc(), "unknown AArch64 build attribute '" +
                                             TagStr + "' for subsection '" +
                                             ActiveSubsectionName + "'");
         return true;
       }
       break;
-    case AArch64BuildAttrs::AEABI_FEATURE_AND_BITS:
-      Tag = AArch64BuildAttrs::getFeatureAndBitsTagsID(TagStr);
-      if (AArch64BuildAttrs::FEATURE_AND_BITS_TAG_NOT_FOUND == Tag) {
+    case AArch64BuildAttributes::AEABI_FEATURE_AND_BITS:
+      Tag = AArch64BuildAttributes::getFeatureAndBitsTagsID(TagStr);
+      if (AArch64BuildAttributes::FEATURE_AND_BITS_TAG_NOT_FOUND == Tag) {
         Error(Parser.getTok().getLoc(), "unknown AArch64 build attribute '" +
                                             TagStr + "' for subsection '" +
                                             ActiveSubsectionName + "'");
@@ -8038,7 +8040,7 @@ bool AArch64AsmParser::parseDirectiveAeabiAArch64Attr(SMLoc L) {
   unsigned ValueInt = unsigned(-1);
   std::string ValueStr = "";
   if (Parser.getTok().is(AsmToken::Integer)) {
-    if (AArch64BuildAttrs::NTBS == ActiveSubsectionType) {
+    if (AArch64BuildAttributes::NTBS == ActiveSubsectionType) {
       Error(
           Parser.getTok().getLoc(),
           "active subsection type is NTBS (string), found ULEB128 (unsigned)");
@@ -8046,7 +8048,7 @@ bool AArch64AsmParser::parseDirectiveAeabiAArch64Attr(SMLoc L) {
     }
     ValueInt = getTok().getIntVal();
   } else if (Parser.getTok().is(AsmToken::Identifier)) {
-    if (AArch64BuildAttrs::ULEB128 == ActiveSubsectionType) {
+    if (AArch64BuildAttributes::ULEB128 == ActiveSubsectionType) {
       Error(
           Parser.getTok().getLoc(),
           "active subsection type is ULEB128 (unsigned), found NTBS (string)");
@@ -8054,7 +8056,7 @@ bool AArch64AsmParser::parseDirectiveAeabiAArch64Attr(SMLoc L) {
     }
     ValueStr = Parser.getTok().getIdentifier();
   } else if (Parser.getTok().is(AsmToken::String)) {
-    if (AArch64BuildAttrs::ULEB128 == ActiveSubsectionType) {
+    if (AArch64BuildAttributes::ULEB128 == ActiveSubsectionType) {
       Error(
           Parser.getTok().getLoc(),
           "active subsection type is ULEB128 (unsigned), found NTBS (string)");
@@ -8067,7 +8069,7 @@ bool AArch64AsmParser::parseDirectiveAeabiAArch64Attr(SMLoc L) {
   }
   // Check for possible unaccepted values for known tags
   // (AEABI_FEATURE_AND_BITS)
-  if (ActiveSubsectionID == AArch64BuildAttrs::AEABI_FEATURE_AND_BITS) {
+  if (ActiveSubsectionID == AArch64BuildAttributes::AEABI_FEATURE_AND_BITS) {
     if (0 != ValueInt && 1 != ValueInt) {
       Error(Parser.getTok().getLoc(),
             "unknown AArch64 build attributes Value for Tag '" + TagStr +
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
index 08cff5a0fefac..fbd0d1f96f6ba 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
@@ -161,10 +161,10 @@ class AArch64TargetAsmStreamer : public AArch64TargetStreamer {
       return;
     }
 
-    unsigned VendorID = AArch64BuildAttrs::getVendorID(VendorName);
+    unsigned VendorID = AArch64BuildAttributes::getVendorID(VendorName);
 
     switch (VendorID) {
-    case AArch64BuildAttrs::VENDOR_UNKNOWN:
+    case AArch64BuildAttributes::VENDOR_UNKNOWN:
       if (unsigned(-1) != Value) {
         OS << "\t.aeabi_attribute" << "\t" << Tag << ", " << Value;
         AArch64TargetStreamer::emitAttribute(VendorName, Tag, Value, "");
@@ -176,7 +176,7 @@ class AArch64TargetAsmStreamer : public AArch64TargetStreamer {
       }
       break;
     // Note: AEABI_FEATURE_AND_BITS takes only unsigned values
-    case AArch64BuildAttrs::AEABI_FEATURE_AND_BITS:
+    case AArch64BuildAttributes::AEABI_FEATURE_AND_BITS:
       switch (Tag) {
       default: // allow emitting any attribute by number
         OS << "\t.aeabi_attribute" << "\t" << Tag << ", " << Value;
@@ -184,17 +184,17 @@ class AArch64TargetAsmStreamer : public AArch64TargetStreamer {
         // (important for llvm-mc asm parsing)
         AArch64TargetStreamer::emitAttribute(VendorName, Tag, Value, "");
         break;
-      case AArch64BuildAttrs::TAG_FEATURE_BTI:
-      case AArch64BuildAttrs::TAG_FEATURE_GCS:
-      case AArch64BuildAttrs::TAG_FEATURE_PAC:
+      case AArch64BuildAttributes::TAG_FEATURE_BTI:
+      case AArch64BuildAttributes::TAG_FEATURE_GCS:
+      case AArch64BuildAttributes::TAG_FEATURE_PAC:
         OS << "\t.aeabi_attribute" << "\t" << Tag << ", " << Value << "\t// "
-           << AArch64BuildAttrs::getFeatureAndBitsTagsStr(Tag);
+           << AArch64BuildAttributes::getFeatureAndBitsTagsStr(Tag);
         AArch64TargetStreamer::emitAttribute(VendorName, Tag, Value, "");
         break;
       }
       break;
     // Note: AEABI_PAUTHABI takes only unsigned values
-    case AArch64BuildAttrs::AEABI_PAUTHABI:
+    case AArch64BuildAttributes::AEABI_PAUTHABI:
       switch (Tag) {
       default: // allow emitting any attribute by number
         OS << "\t.aeabi_attribute" << "\t" << Tag << ", " << Value;
@@ -202,10 +202,10 @@ class AArch64TargetAsmStreamer : public AArch64TargetStreamer {
         // (important for llvm-mc asm parsing)
         AArch64TargetStreamer::emitAttribute(VendorName, Tag, Value, "");
         break;
-      case AArch64BuildAttrs::TAG_PAUTH_PLATFORM:
-      case AArch64BuildAttrs::TAG_PAUTH_SCHEMA:
+      case AArch64BuildAttributes::TAG_PAUTH_PLATFORM:
+      case AArch64BuildAttributes::TAG_PAUTH_SCHEMA:
         OS << "\t.aeabi_attribute" << "\t" << Tag << ", " << Value << "\t// "
-           << AArch64BuildAttrs::getPauthABITagsStr(Tag);
+           << AArch64BuildAttributes::getPauthABITagsStr(Tag);
         AArch64TargetStreamer::emitAttribute(VendorName, Tag, Value, "");
         break;
       }
@@ -215,42 +215,43 @@ class AArch64TargetAsmStreamer : public AArch64TargetStreamer {
   }
 
   void emitAtributesSubsection(
-      StringRef SubsectionName, AArch64BuildAttrs::SubsectionOptional Optional,
-      AArch64BuildAttrs::SubsectionType ParameterType) override {
+      StringRef SubsectionName,
+      AArch64BuildAttributes::SubsectionOptional Optional,
+      AArch64BuildAttributes::SubsectionType ParameterType) override {
     // The AArch64 build attributes assembly subsection header format:
     // ".aeabi_subsection name, optional, parameter type"
     // optional: required (0) optional (1)
     // parameter type: uleb128 or ULEB128 (0) ntbs or NTBS (1)
-    unsigned SubsectionID = AArch64BuildAttrs::getVendorID(SubsectionName);
+    unsigned SubsectionID = AArch64BuildAttributes::getVendorID(SubsectionName);
 
     assert((0 == Optional || 1 == Optional) &&
-           AArch64BuildAttrs::getSubsectionOptionalUnknownError().data());
+           AArch64BuildAttributes::getSubsectionOptionalUnknownError().data());
     assert((0 == ParameterType || 1 == ParameterType) &&
-           AArch64BuildAttrs::getSubsectionTypeUnknownError().data());
+           AArch64BuildAttributes::getSubsectionTypeUnknownError().data());
 
     std::string SubsectionTag = ".aeabi_subsection";
     StringRef OptionalStr = getOptionalStr(Optional);
     StringRef ParameterStr = getTypeStr(ParameterType);
 
     switch (SubsectionID) {
-    case AArch64BuildAttrs::VENDOR_UNKNOWN: {
+    case AArch64BuildAttributes::VENDOR_UNKNOWN: {
       // Private subsection
       break;
     }
-    case AArch64BuildAttrs::AEABI_PAUTHABI: {
-      assert(AArch64BuildAttrs::REQUIRED == Optional &&
+    case AArch64BuildAttributes::AEABI_PAUTHABI: {
+      assert(AArch64BuildAttributes::REQUIRED == Optional &&
              "subsection .aeabi-pauthabi should be marked as "
              "required and not as optional");
-      assert(AArch64BuildAttrs::ULEB128 == ParameterType &&
+      assert(AArch64BuildAttributes::ULEB128 == ParameterType &&
              "subsection .aeabi-pauthabi should be "
              "marked as uleb128 and not as ntbs");
       break;
     }
-    case AArch64BuildAttrs::AEABI_FEATURE_AND_BITS: {
-      assert(AArch64BuildAttrs::OPTIONAL == Optional &&
+    case AArch64BuildAttributes::AEABI_FEATURE_AND_BITS: {
+      assert(AArch64BuildAttributes::OPTIONAL == Optional &&
              "subsection .aeabi_feature_and_bits should be "
              "marked as optional and not as required");
-      assert(AArch64BuildAttrs::ULEB128 == ParameterType &&
+      assert(AArch64BuildAttributes::ULEB128 == ParameterType &&
              "subsection .aeabi_feature_and_bits should "
              "be marked as uleb128 and not as ntbs");
       break;
@@ -416,8 +417,8 @@ AArch64ELFStreamer &AArch64TargetELFStreamer::getStreamer() {
 }
 
 void AArch64TargetELFStreamer::emitAtributesSubsection(
-    StringRef VendorName, AArch64BuildAttrs::SubsectionOptional IsOptional,
-    AArch64BuildAttrs::SubsectionType ParameterType) {
+    StringRef VendorName, AArch64BuildAttributes::SubsectionOptional IsOptional,
+    AArch64BuildAttributes::SubsectionType ParameterType) {
   AArch64TargetStreamer::emitAtributesSubsection(VendorName, IsOptional,
                                                  ParameterType);
 }
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp
index 028d9196613cb..04defbc977462 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp
@@ -154,8 +154,8 @@ MCTargetStreamer *llvm::createAArch64NullTargetStreamer(MCStreamer &S) {
 }
 
 void AArch64TargetStreamer::emitAtributesSubsection(
-    StringRef VendorName, AArch64BuildAttrs::SubsectionOptional IsOptional,
-    AArch64BuildAttrs::SubsectionType ParameterType) {
+    StringRef VendorName, AArch64BuildAttributes::SubsectionOptional IsOptional,
+    AArch64BuildAttributes::SubsectionType ParameterType) {
 
   // If exists, return.
   for (MCELFStreamer::AttributeSubSection &SubSection : AttributeSubSections) {
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h
index 9cbb104c0eb9e..43e099f919999 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h
@@ -97,8 +97,8 @@ class AArch64TargetStreamer : public MCTargetStreamer {
   /// Build attributes implementation
   virtual void
   emitAtributesSubsection(StringRef VendorName,
-                          AArch64BuildAttrs::SubsectionOptional IsOptional,
-                          AArch64BuildAttrs::SubsectionType ParameterType);
+                          AArch64BuildAttributes::SubsectionOptional IsOptional,
+                          AArch64BuildAttributes::SubsectionType ParameterType);
   virtual void emitAttribute(StringRef VendorName, unsigned Tag, unsigned Value,
                              std::string String);
   void activateAtributesSubsection(StringRef VendorName);
@@ -124,8 +124,9 @@ class AArch64TargetELFStreamer : public AArch64TargetStreamer {
 
   /// Build attributes implementation
   void emitAtributesSubsection(
-      StringRef VendorName, AArch64BuildAttrs::SubsectionOptional IsOptional,
-      AArch64BuildAttrs::SubsectionType ParameterType) override;
+      StringRef VendorName,
+      AArch64BuildAttributes::SubsectionOptional IsOptional,
+      AArch64BuildAttributes::SubsectionType ParameterType) override;
   void emitAttribute(StringRef VendorName, unsigned Tag, unsigned Value,
                      std::string String) override;
   void emitInst(uint32_t Inst) override;
diff --git a/llvm/test/tools/llvm-readobj/ELF/AArch64/build-attributes-comprehensive.s b/llvm/test/tools/llvm-readobj/ELF/AArch64/build-attributes-comprehensive.s
new file mode 100644
index 0000000000000..aadbbcd507664
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/ELF/AArch64/build-attributes-comprehensive.s
@@ -0,0 +1,81 @@
+# RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o - | llvm-readelf --arch-specific - | FileCheck %s --check-prefix=ATTR
+
+# ATTR: BuildAttributes {
+# ATTR-NEXT:   FormatVersion: 0x41
+# ATTR-NEXT:   Section 1 {
+# ATTR-NEXT:     SectionLength: 29
+# ATTR-NEXT:     VendorName: private_subsection_1 Optionality: optional Type: uleb128
+# ATTR-NEXT:     Attributes {
+# ATTR-NEXT:       1: 1
+# ATTR-NEXT:     }
+# ATTR-NEXT:   }
+# ATTR-NEXT:   Section 2 {
+# ATTR-NEXT:     SectionLength: 37
+# ATTR-NEXT:     VendorName: aeabi_feature_and_bits Optionality: optional Type: uleb128
+# ATTR-NEXT:     Attributes {
+# ATTR-NEXT:       Tag_Feature_BTI: 1
+# ATTR-NEXT:       Tag_Feature_PAC: 1
+# ATTR-NEXT:       Tag_Feature_GCS: 1
+# ATTR-NEXT:       3: 1
+# ATTR-NEXT:     }
+# ATTR-NEXT:   }
+# ATTR-NEXT:   Section 3 {
+# ATTR-NEXT:     SectionLength: 32
+# ATTR-NEXT:     VendorName: private_subsection_3 Optionality: optional Type: ntbs
+# ATTR-NEXT:     Attributes {
+# ATTR-NEXT:       1: "1"
+# ATTR-NEXT:     }
+# ATTR-NEXT:   }
+# ATTR-NEXT:   Section 4 {
+# ATTR-NEXT:     SectionLength: 35
+# ATTR-NEXT:     VendorName: aeabi_pauthabi Optionality: required Type: uleb128
+# ATTR-NEXT:     Attributes {
+# ATTR-NEXT:       Tag_PAuth_Schema: 1
+# ATTR-NEXT:       Tag_PAuth_Platform: 1
+# ATTR-NEXT:       5: 1
+# ATTR-NEXT:       6: 1
+# ATTR-NEXT:       7: 1
+# ATTR-NEXT:       8: 1
+# ATTR-NEXT:       9: 1
+# ATTR-NEXT:     }
+# ATTR-NEXT:   }
+# ATTR-NEXT:   Section 5 {
+# ATTR-NEXT:     SectionLength: 32
+# ATTR-NEXT:     VendorName: private_subsection_4 Optionality: required Type: ntbs
+# ATTR-NEXT:     Attributes {
+# ATTR-NEXT:       1: "1"
+# ATTR-NEXT:     }
+# ATTR-NEXT:   }
+# ATTR-NEXT:   Section 6 {
+# ATTR-NEXT:     SectionLength: 31
+# ATTR-NEXT:     VendorName: private_subsection_2 Optionality: required Type: uleb128
+# ATTR-NEXT:     Attributes {
+# ATTR-NEXT:       1: 1
+# ATTR-NEXT:       2: 1
+# ATTR-NEXT:     }
+# ATTR-NEXT:   }
+# ATTR-NEXT: }
+
+
+.aeabi_subsection private_subsection_1, optional, uleb128
+.aeabi_attribute 1, 1
+.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+.aeabi_attribute Tag_Feature_BTI, 1
+.aeabi_attribute 1, 1
+.aeabi_attribute 2, 1
+.aeabi_attribute 3, 1
+.aeabi_subsection private_subsection_3, optional, ntbs
+.aeabi_attribute 1, "1"
+.aeabi_subsection aeabi_pauthabi, required, uleb128
+.aeabi_attribute Tag_PAuth_Schema, 1
+.aeabi_attribute Tag_PAuth_Platform, 1
+.aeabi_attribute 5, 1
+.aeabi_attribute 6, 1
+.aeabi_attribute 7, 1
+.aeabi_attribute 8, 1
+.aeabi_attribute 9, 1
+.aeabi_subsection private_subsection_4, required, ntbs
+.aeabi_attribute 1, "1"
+.aeabi_subsection private_subsection_2, required, uleb128
+.aeabi_attribute 1, 1
+.aeabi_attribute 2, 1
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index fdae09ac767e6..91f211bbe4156 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -39,6 +39,7 @@
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Object/RelocationResolver.h"
 #include "llvm/Object/StackMapParser.h"
+#include "llvm/Support/AArch64AttributeParser.h"
 #include "llvm/Support/AMDGPUMetadata.h"
 #include "llvm/Support/ARMAttributeParser.h"
 #include "llvm/Support/ARMBuildAttributes.h"
@@ -2878,6 +2879,12 @@ template <class ELFT> void ELFDumper<ELFT>::printArchSpecificInfo() {
         ELF::SHT_ARM_ATTRIBUTES, std::make_unique<ARMAttributeParser>(&W),
         Obj.isLE() ? llvm::endianness::little : llvm::endianness::big);
     break;
+  case EM_AARCH64:
+    printAttributes(ELF::SHT_AARCH64_ATTRIBUTES,
+                    std::make_unique<AArch64AttributeParser>(&W),
+                    Obj.isLE() ? llvm::endianness::little
+                               : llvm::endianness::big);
+    break;
   case EM_RISCV:
     if (Obj.isLE())
       printAttributes(ELF::SHT_RISCV_ATTRIBUTES,
diff --git a/llvm/unittests/Support/ARMAttributeParser.cpp b/llvm/unittests/Support/ARMAttributeParser.cpp
index a0568262b4da9..e06f7fab85fa7 100644
--- a/llvm/unittests/Support/ARMAttributeParser.cpp
+++ b/llvm/unittests/Support/ARMAttributeParser.cpp
@@ -37,7 +37,7 @@ bool testBuildAttr(unsigned Tag, unsigned Value,
   ARMAttributeParser Parser;
   cantFail(Parser.parse(Bytes, llvm::endianness::little));
 
-  std::optional<unsigned> Attr = Parser.getAttributeValue(ExpectedTag);
+  std::optional<unsigned> Attr = Parser.getAttributeValue("", ExpectedTag);
   return Attr && *Attr == ExpectedValue;
 }
 
diff --git a/llvm/unittests/Support/CSKYAttributeParserTest.cpp b/llvm/unittests/Support/CSKYAttributeParserTest.cpp
index 2c5d93b0b7565..25b151fe5c1c1 100644
--- a/llvm/unittests/Support/CSKYAttributeParserTest.cpp
+++ b/llvm/unittests/Support/CSKYAttributeParserTest.cpp
@@ -83,7 +83,7 @@ static bool testAttributeInt(unsigned Tag, unsigned Value, unsigned ExpectedTag,
   CSKYAttributeParser Parser;
   cantFail(Parser.parse(Bytes, llvm::endianness::little));
 
-  std::optional<unsigned> Attr = Parser.getAttributeValue(ExpectedTag);
+  std::optional<unsigned> Attr = Parser.getAttributeValue("", ExpectedTag);
   return Attr && *Attr == ExpectedValue;
 }
 
@@ -100,7 +100,7 @@ static bool testAttributeString(unsigned Tag, const char *Value,
   CSKYAttributeParser Parser;
   cantFail(Parser.parse(Bytes, llvm::endianness::little));
 
-  std::optional<StringRef> Attr = Parser.getAttributeString(ExpectedTag);
+  std::optional<StringRef> Attr = Parser.getAttributeString("", ExpectedTag);
   return Attr && *Attr == ExpectedValue;
 }
 
diff --git a/llvm/unittests/Support/ELFAttributeParserTest.cpp b/llvm/unittests/Support/ELFAttributeParserTest.cpp
index 38e7b09cc3c7d..31cc594188e33 100644
--- a/llvm/unittests/Support/ELFAttributeParserTest.cpp
+++ b/llvm/unittests/Support/ELFAttributeParserTest.cpp
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/Support/ELFAttributeParser.h"
+#include "llvm/Support/ELFAttrParserCompact.h"
 #include "llvm/Support/ELFAttributes.h"
 #include "gtest/gtest.h"
 #include <string>
@@ -16,7 +16,7 @@ using namespace llvm;
 static const TagNameMap emptyTagNameMap;
 
 // This class is used to test the common part of the ELF attribute section.
-class AttributeHeaderParser : public ELFAttributeParser {
+class AttributeHeaderParser : public ELFCompactAttrParser {
   Error handler(uint64_t tag, bool &handled) override {
     // Treat all attributes as handled.
     handled = true;
@@ -25,8 +25,8 @@ class AttributeHeaderParser : public ELFAttributeParser {
 
 public:
   AttributeHeaderParser(ScopedPrinter *printer)
-      : ELFAttributeParser(printer, emptyTagNameMap, "test") {}
-  AttributeHeaderParser() : ELFAttributeParser(emptyTagNameMap, "test") {}
+      : ELFCompactAttrParser(printer, emptyTagNameMap, "test") {}
+  AttributeHeaderParser() : ELFCompactAttrParser(emptyTagNameMap, "test") {}
 };
 
 static void testParseError(ArrayRef<uint8_t> bytes, const char *msg) {
diff --git a/llvm/unittests/Support/RISCVAttributeParserTest.cpp b/llvm/unittests/Support/RISCVAttributeParserTest.cpp
index aa73bb92d6e3e..777dc4d0f4d42 100644
--- a/llvm/unittests/Support/RISCVAttributeParserTest.cpp
+++ b/llvm/unittests/Support/RISCVAttributeParserTest.cpp
@@ -44,7 +44,7 @@ static bool testAttribute(unsigned Tag, unsigned Value, unsigned ExpectedTag,
   RISCVAttributeParser Parser;
   cantFail(Parser.parse(Bytes, llvm::endianness::little));
 
-  std::optional<unsigned> Attr = Parser.getAttributeValue(ExpectedTag);
+  std::optional<unsigned> Attr = Parser.getAttributeValue("", ExpectedTag);
   return Attr && *Attr == ExpectedValue;
 }
 

>From 16feaafe0ea47a125102ca3deb926d44fc2c00b0 Mon Sep 17 00:00:00 2001
From: Sivan Shani <sivan.shani at arm.com>
Date: Wed, 26 Feb 2025 10:13:02 +0000
Subject: [PATCH 2/5] Remove '-o -' from llvm-mc arguments since it is the
 default.

---
 .../llvm-readobj/ELF/AArch64/build-attributes-comprehensive.s   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/test/tools/llvm-readobj/ELF/AArch64/build-attributes-comprehensive.s b/llvm/test/tools/llvm-readobj/ELF/AArch64/build-attributes-comprehensive.s
index aadbbcd507664..d202bcbedf446 100644
--- a/llvm/test/tools/llvm-readobj/ELF/AArch64/build-attributes-comprehensive.s
+++ b/llvm/test/tools/llvm-readobj/ELF/AArch64/build-attributes-comprehensive.s
@@ -1,4 +1,4 @@
-# RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o - | llvm-readelf --arch-specific - | FileCheck %s --check-prefix=ATTR
+# RUN: llvm-mc -triple=aarch64 -filetype=obj %s | llvm-readelf --arch-specific - | FileCheck %s --check-prefix=ATTR
 
 # ATTR: BuildAttributes {
 # ATTR-NEXT:   FormatVersion: 0x41

>From 17ed192587154f34ae2d88f937020e714445b95f Mon Sep 17 00:00:00 2001
From: Sivan Shani <sivan.shani at arm.com>
Date: Wed, 26 Feb 2025 10:23:00 +0000
Subject: [PATCH 3/5] Provide default implementations for ELFAttributeParser
 virtual functions to prevent compilation errors when no derived class is
 initialized, such as on non-ELF platforms.

---
 llvm/include/llvm/Support/ELFAttributeParser.h | 12 +++++++++---
 tests.sh                                       | 11 +++++++++++
 tests_ra.sh                                    | 11 +++++++++++
 3 files changed, 31 insertions(+), 3 deletions(-)
 create mode 100755 tests.sh
 create mode 100755 tests_ra.sh

diff --git a/llvm/include/llvm/Support/ELFAttributeParser.h b/llvm/include/llvm/Support/ELFAttributeParser.h
index 1eeaaea3bf356..a033e580c8859 100644
--- a/llvm/include/llvm/Support/ELFAttributeParser.h
+++ b/llvm/include/llvm/Support/ELFAttributeParser.h
@@ -19,11 +19,17 @@ class ELFAttributeParser {
 public:
   virtual ~ELFAttributeParser() {}
 
-  virtual Error parse(ArrayRef<uint8_t> Section, llvm::endianness Endian);
+  virtual Error parse(ArrayRef<uint8_t> Section, llvm::endianness Endian) {
+    return llvm::Error::success();
+  }
   virtual std::optional<unsigned>
-  getAttributeValue(StringRef BuildAttrSubsectionName, unsigned Tag) const;
+  getAttributeValue(StringRef BuildAttrSubsectionName, unsigned Tag) const {
+    return std::nullopt;
+  }
   virtual std::optional<StringRef>
-  getAttributeString(StringRef BuildAttrSubsectionName, unsigned Tag) const;
+  getAttributeString(StringRef BuildAttrSubsectionName, unsigned Tag) const {
+    return std::nullopt;
+  }
 };
 
 } // namespace llvm
diff --git a/tests.sh b/tests.sh
new file mode 100755
index 0000000000000..f505af1700eee
--- /dev/null
+++ b/tests.sh
@@ -0,0 +1,11 @@
+${binrl}/llvm-lit -v llvm/test/MC/AArch64/build-attributes-asm-*
+${binral}/llvm-lit -v llvm/test/MC/AArch64/build-attributes-asm-*
+${bindl}/llvm-lit -v llvm/test/MC/AArch64/build-attributes-asm-*
+
+${binrl}/llvm-lit -v  llvm/test/CodeGen/AArch64/build-attributes-*
+${binral}/llvm-lit -v  llvm/test/CodeGen/AArch64/build-attributes-*
+${bindl}/llvm-lit -v  llvm/test/CodeGen/AArch64/build-attributes-*
+
+${binrl}/llvm-lit -v  llvm/test/tools/llvm-readobj/ELF/AArch64/build-attributes-*
+${binral}/llvm-lit -v  llvm/test/tools/llvm-readobj/ELF/AArch64/build-attributes-*
+${bindl}/llvm-lit -v  llvm/test/tools/llvm-readobj/ELF/AArch64/build-attributes-*
diff --git a/tests_ra.sh b/tests_ra.sh
new file mode 100755
index 0000000000000..388a02cbc6a6c
--- /dev/null
+++ b/tests_ra.sh
@@ -0,0 +1,11 @@
+# ${binrl}/llvm-lit -v llvm/test/MC/AArch64/build-attributes-asm-*
+${binral}/llvm-lit -v llvm/test/MC/AArch64/build-attributes-asm-*
+# ${bindl}/llvm-lit -v llvm/test/MC/AArch64/build-attributes-asm-*
+
+# ${binrl}/llvm-lit -v  llvm/test/CodeGen/AArch64/build-attributes-*
+${binral}/llvm-lit -v  llvm/test/CodeGen/AArch64/build-attributes-*
+# ${bindl}/llvm-lit -v  llvm/test/CodeGen/AArch64/build-attributes-*
+
+# ${binrl}/llvm-lit -v  llvm/test/tools/llvm-readobj/ELF/AArch64/build-attributes-*
+${binral}/llvm-lit -v  llvm/test/tools/llvm-readobj/ELF/AArch64/build-attributes-*
+# ${bindl}/llvm-lit -v  llvm/test/tools/llvm-readobj/ELF/AArch64/build-attributes-*

>From e89d817d5540cc9820b354d72ba27538ef303f29 Mon Sep 17 00:00:00 2001
From: SivanShani-Arm <sivan.shani at arm.com>
Date: Wed, 26 Feb 2025 10:43:59 +0000
Subject: [PATCH 4/5] Delete tests_ra.sh

---
 tests_ra.sh | 11 -----------
 1 file changed, 11 deletions(-)
 delete mode 100755 tests_ra.sh

diff --git a/tests_ra.sh b/tests_ra.sh
deleted file mode 100755
index 388a02cbc6a6c..0000000000000
--- a/tests_ra.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-# ${binrl}/llvm-lit -v llvm/test/MC/AArch64/build-attributes-asm-*
-${binral}/llvm-lit -v llvm/test/MC/AArch64/build-attributes-asm-*
-# ${bindl}/llvm-lit -v llvm/test/MC/AArch64/build-attributes-asm-*
-
-# ${binrl}/llvm-lit -v  llvm/test/CodeGen/AArch64/build-attributes-*
-${binral}/llvm-lit -v  llvm/test/CodeGen/AArch64/build-attributes-*
-# ${bindl}/llvm-lit -v  llvm/test/CodeGen/AArch64/build-attributes-*
-
-# ${binrl}/llvm-lit -v  llvm/test/tools/llvm-readobj/ELF/AArch64/build-attributes-*
-${binral}/llvm-lit -v  llvm/test/tools/llvm-readobj/ELF/AArch64/build-attributes-*
-# ${bindl}/llvm-lit -v  llvm/test/tools/llvm-readobj/ELF/AArch64/build-attributes-*

>From ae9dd167327945d5ae887d1778b1b7dab3cd8c4f Mon Sep 17 00:00:00 2001
From: SivanShani-Arm <sivan.shani at arm.com>
Date: Wed, 26 Feb 2025 10:44:21 +0000
Subject: [PATCH 5/5] Delete tests.sh

---
 tests.sh | 11 -----------
 1 file changed, 11 deletions(-)
 delete mode 100755 tests.sh

diff --git a/tests.sh b/tests.sh
deleted file mode 100755
index f505af1700eee..0000000000000
--- a/tests.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-${binrl}/llvm-lit -v llvm/test/MC/AArch64/build-attributes-asm-*
-${binral}/llvm-lit -v llvm/test/MC/AArch64/build-attributes-asm-*
-${bindl}/llvm-lit -v llvm/test/MC/AArch64/build-attributes-asm-*
-
-${binrl}/llvm-lit -v  llvm/test/CodeGen/AArch64/build-attributes-*
-${binral}/llvm-lit -v  llvm/test/CodeGen/AArch64/build-attributes-*
-${bindl}/llvm-lit -v  llvm/test/CodeGen/AArch64/build-attributes-*
-
-${binrl}/llvm-lit -v  llvm/test/tools/llvm-readobj/ELF/AArch64/build-attributes-*
-${binral}/llvm-lit -v  llvm/test/tools/llvm-readobj/ELF/AArch64/build-attributes-*
-${bindl}/llvm-lit -v  llvm/test/tools/llvm-readobj/ELF/AArch64/build-attributes-*



More information about the llvm-commits mailing list