[llvm] d7fb4a2 - [LLVM][Clang][AArch64] Implement AArch64 build attributes (#118771)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 22 06:23:49 PST 2025


Author: SivanShani-Arm
Date: 2025-01-22T14:23:46Z
New Revision: d7fb4a275c98f4035d1083b5eb3edd2ffb2da00e

URL: https://github.com/llvm/llvm-project/commit/d7fb4a275c98f4035d1083b5eb3edd2ffb2da00e
DIFF: https://github.com/llvm/llvm-project/commit/d7fb4a275c98f4035d1083b5eb3edd2ffb2da00e.diff

LOG: [LLVM][Clang][AArch64] Implement AArch64 build attributes (#118771)

- Added support for AArch64-specific build attributes.
- Print AArch64 build attributes to assembly.
- Parse AArch64 build attributes from assembly.
- Emit AArch64 build attributes to ELF.

Specification:
 https://github.com/ARM-software/abi-aa/pull/230

Added: 
    llvm/include/llvm/Support/AArch64BuildAttributes.h
    llvm/lib/Support/AArch64BuildAttributes.cpp
    llvm/test/CodeGen/AArch64/aarch64-build-attributes-all.ll
    llvm/test/CodeGen/AArch64/aarch64-build-attributes-bti.ll
    llvm/test/CodeGen/AArch64/aarch64-build-attributes-gcs.ll
    llvm/test/CodeGen/AArch64/aarch64-build-attributes-pac.ll
    llvm/test/CodeGen/AArch64/aarch64-build-attributes-pauthabi.ll
    llvm/test/MC/AArch64/aarch64-build-attributes-asm-all.s
    llvm/test/MC/AArch64/aarch64-build-attributes-asm-bti.s
    llvm/test/MC/AArch64/aarch64-build-attributes-asm-err-attrs.s
    llvm/test/MC/AArch64/aarch64-build-attributes-asm-err-headers.s
    llvm/test/MC/AArch64/aarch64-build-attributes-asm-gcs.s
    llvm/test/MC/AArch64/aarch64-build-attributes-asm-none.s
    llvm/test/MC/AArch64/aarch64-build-attributes-asm-numerical-tags.s
    llvm/test/MC/AArch64/aarch64-build-attributes-asm-out-of-order.s
    llvm/test/MC/AArch64/aarch64-build-attributes-asm-pac.s
    llvm/test/MC/AArch64/aarch64-build-attributes-asm-private-subsections-err.s
    llvm/test/MC/AArch64/aarch64-build-attributes-asm-private-subsections.s

Modified: 
    llvm/include/llvm/BinaryFormat/ELF.h
    llvm/include/llvm/MC/MCELFStreamer.h
    llvm/lib/MC/MCELFStreamer.cpp
    llvm/lib/Support/CMakeLists.txt
    llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
    llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
    llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
    llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp
    llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h
    llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h
index 1bc69f791bd84c..48ae0db80f43ee 100644
--- a/llvm/include/llvm/BinaryFormat/ELF.h
+++ b/llvm/include/llvm/BinaryFormat/ELF.h
@@ -1158,6 +1158,8 @@ enum : unsigned {
   SHT_ARM_ATTRIBUTES = 0x70000003U,
   SHT_ARM_DEBUGOVERLAY = 0x70000004U,
   SHT_ARM_OVERLAYSECTION = 0x70000005U,
+  // Support for AArch64 build attributes
+  SHT_AARCH64_ATTRIBUTES = 0x70000003U,
   // Special aarch64-specific section for MTE support, as described in:
   // https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#section-types
   SHT_AARCH64_AUTH_RELR = 0x70000004U,

diff  --git a/llvm/include/llvm/MC/MCELFStreamer.h b/llvm/include/llvm/MC/MCELFStreamer.h
index 94d14088d0f5d2..5a1cdd9e96cad4 100644
--- a/llvm/include/llvm/MC/MCELFStreamer.h
+++ b/llvm/include/llvm/MC/MCELFStreamer.h
@@ -96,7 +96,7 @@ class MCELFStreamer : public MCObjectStreamer {
     // This structure holds all attributes, accounting for their string /
     // numeric value, so we can later emit them in declaration order, keeping
     // all in the same vector.
-    enum {
+    enum Types {
       HiddenAttribute = 0,
       NumericAttribute,
       TextAttribute,
@@ -105,6 +105,17 @@ class MCELFStreamer : public MCObjectStreamer {
     unsigned Tag;
     unsigned IntValue;
     std::string StringValue;
+    AttributeItem(Types Ty, unsigned Tg, unsigned IV, std::string SV)
+        : Type(Ty), Tag(Tg), IntValue(IV), StringValue(SV) {}
+  };
+
+  /// ELF object attributes subsection support
+  struct AttributeSubSection {
+    bool IsActive;
+    StringRef VendorName;
+    unsigned IsOptional;
+    unsigned ParameterType;
+    SmallVector<AttributeItem, 64> Content;
   };
 
   // Attributes that are added and managed entirely by target.
@@ -119,13 +130,23 @@ class MCELFStreamer : public MCObjectStreamer {
                              unsigned Type, MCSection *&AttributeSection) {
     createAttributesSection(Vendor, Section, Type, AttributeSection, Contents);
   }
+  void
+  emitAttributesSection(MCSection *&AttributeSection, const Twine &Section,
+                        unsigned Type,
+                        SmallVector<AttributeSubSection, 64> &SubSectionVec) {
+    createAttributesWithSubsection(AttributeSection, Section, Type,
+                                   SubSectionVec);
+  }
 
 private:
   AttributeItem *getAttributeItem(unsigned Attribute);
-  size_t calculateContentSize(SmallVector<AttributeItem, 64> &AttrsVec);
+  size_t calculateContentSize(SmallVector<AttributeItem, 64> &AttrsVec) const;
   void createAttributesSection(StringRef Vendor, const Twine &Section,
                                unsigned Type, MCSection *&AttributeSection,
                                SmallVector<AttributeItem, 64> &AttrsVec);
+  void createAttributesWithSubsection(
+      MCSection *&AttributeSection, const Twine &Section, unsigned Type,
+      SmallVector<AttributeSubSection, 64> &SubSectionVec);
 
   // GNU attributes that will get emitted at the end of the asm file.
   SmallVector<AttributeItem, 64> GNUAttributes;

diff  --git a/llvm/include/llvm/Support/AArch64BuildAttributes.h b/llvm/include/llvm/Support/AArch64BuildAttributes.h
new file mode 100644
index 00000000000000..ea293b72f9bb11
--- /dev/null
+++ b/llvm/include/llvm/Support/AArch64BuildAttributes.h
@@ -0,0 +1,75 @@
+//===-- AArch64BuildAttributes.h - AARch64 Build Attributes -----*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains enumerations and support routines for AArch64 build
+// attributes as defined in Build Attributes for the AArch64 document.
+//
+// Build Attributes for the ArmĀ® 64-bit Architecture (AArch64) 2024Q1
+//
+// https://github.com/ARM-software/abi-aa/pull/230
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_AARCH64BUILDATTRIBUTES_H
+#define LLVM_SUPPORT_AARCH64BUILDATTRIBUTES_H
+
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+
+namespace AArch64BuildAttributes {
+
+/// AArch64 build attributes vendors IDs (a.k.a subsection name)
+enum VendorID : unsigned {
+  AEABI_FEATURE_AND_BITS = 0,
+  AEABI_PAUTHABI = 1,
+  VENDOR_UNKNOWN = 404 // Treated as a private subsection name
+};
+StringRef getVendorName(unsigned const Vendor);
+VendorID getVendorID(StringRef const Vendor);
+
+enum SubsectionOptional : unsigned {
+  REQUIRED = 0,
+  OPTIONAL = 1,
+  OPTIONAL_NOT_FOUND = 404
+};
+StringRef getOptionalStr(unsigned Optional);
+SubsectionOptional getOptionalID(StringRef Optional);
+StringRef getSubsectionOptionalUnknownError();
+
+enum SubsectionType : unsigned { ULEB128 = 0, NTBS = 1, TYPE_NOT_FOUND = 404 };
+StringRef getTypeStr(unsigned Type);
+SubsectionType getTypeID(StringRef Type);
+StringRef getSubsectionTypeUnknownError();
+
+enum PauthABITags : unsigned {
+  TAG_PAUTH_PLATFORM = 1,
+  TAG_PAUTH_SCHEMA = 2,
+  PAUTHABI_TAG_NOT_FOUND = 404
+};
+StringRef getPauthABITagsStr(unsigned PauthABITag);
+PauthABITags getPauthABITagsID(StringRef PauthABITag);
+
+enum FeatureAndBitsTags : unsigned {
+  TAG_FEATURE_BTI = 0,
+  TAG_FEATURE_PAC = 1,
+  TAG_FEATURE_GCS = 2,
+  FEATURE_AND_BITS_TAG_NOT_FOUND = 404
+};
+StringRef getFeatureAndBitsTagsStr(unsigned FeatureAndBitsTag);
+FeatureAndBitsTags getFeatureAndBitsTagsID(StringRef FeatureAndBitsTag);
+
+enum FeatureAndBitsFlag : unsigned {
+  Feature_BTI_Flag = 1 << 0,
+  Feature_PAC_Flag = 1 << 1,
+  Feature_GCS_Flag = 1 << 2
+};
+} // namespace AArch64BuildAttributes
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_AARCH64BUILDATTRIBUTES_H
\ No newline at end of file

diff  --git a/llvm/lib/MC/MCELFStreamer.cpp b/llvm/lib/MC/MCELFStreamer.cpp
index 64ab2b2ab58f5b..282c82198507d7 100644
--- a/llvm/lib/MC/MCELFStreamer.cpp
+++ b/llvm/lib/MC/MCELFStreamer.cpp
@@ -696,8 +696,8 @@ MCELFStreamer::getAttributeItem(unsigned Attribute) {
   return nullptr;
 }
 
-size_t
-MCELFStreamer::calculateContentSize(SmallVector<AttributeItem, 64> &AttrsVec) {
+size_t MCELFStreamer::calculateContentSize(
+    SmallVector<AttributeItem, 64> &AttrsVec) const {
   size_t Result = 0;
   for (const AttributeItem &Item : AttrsVec) {
     switch (Item.Type) {
@@ -783,6 +783,67 @@ void MCELFStreamer::createAttributesSection(
   AttrsVec.clear();
 }
 
+void MCELFStreamer::createAttributesWithSubsection(
+    MCSection *&AttributeSection, const Twine &Section, unsigned Type,
+    SmallVector<AttributeSubSection, 64> &SubSectionVec) {
+  // <format-version: 'A'>
+  // [ <uint32: subsection-length> NTBS: vendor-name
+  //   <bytes: vendor-data>
+  // ]*
+  // vendor-data expends to:
+  // <uint8: optional> <uint8: parameter type> <attribute>*
+  if (0 == SubSectionVec.size()) {
+    return;
+  }
+
+  // Switch section to AttributeSection or get/create the section.
+  if (AttributeSection) {
+    switchSection(AttributeSection);
+  } else {
+    AttributeSection = getContext().getELFSection(Section, Type, 0);
+    switchSection(AttributeSection);
+
+    // Format version
+    emitInt8(0x41);
+  }
+
+  for (AttributeSubSection &SubSection : SubSectionVec) {
+    // subsection-length + vendor-name + '\0'
+    const size_t VendorHeaderSize = 4 + SubSection.VendorName.size() + 1;
+    // optional + parameter-type
+    const size_t VendorParameters = 1 + 1;
+    const size_t ContentsSize = calculateContentSize(SubSection.Content);
+
+    emitInt32(VendorHeaderSize + VendorParameters + ContentsSize);
+    emitBytes(SubSection.VendorName);
+    emitInt8(0); // '\0'
+    emitInt8(SubSection.IsOptional);
+    emitInt8(SubSection.ParameterType);
+
+    for (AttributeItem &Item : SubSection.Content) {
+      emitULEB128IntValue(Item.Tag);
+      switch (Item.Type) {
+      default:
+        assert(0 && "Invalid attribute type");
+        break;
+      case AttributeItem::NumericAttribute:
+        emitULEB128IntValue(Item.IntValue);
+        break;
+      case AttributeItem::TextAttribute:
+        emitBytes(Item.StringValue);
+        emitInt8(0); // '\0'
+        break;
+      case AttributeItem::NumericAndTextAttributes:
+        emitULEB128IntValue(Item.IntValue);
+        emitBytes(Item.StringValue);
+        emitInt8(0); // '\0'
+        break;
+      }
+    }
+  }
+  SubSectionVec.clear();
+}
+
 MCStreamer *llvm::createELFStreamer(MCContext &Context,
                                     std::unique_ptr<MCAsmBackend> &&MAB,
                                     std::unique_ptr<MCObjectWriter> &&OW,

diff  --git a/llvm/lib/Support/AArch64BuildAttributes.cpp b/llvm/lib/Support/AArch64BuildAttributes.cpp
new file mode 100644
index 00000000000000..ada34eb3f927d1
--- /dev/null
+++ b/llvm/lib/Support/AArch64BuildAttributes.cpp
@@ -0,0 +1,117 @@
+//===-- AArch64BuildAttributes.cpp - AArch64 Build Attributes -------------===//
+//
+// 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/AArch64BuildAttributes.h"
+#include "llvm/ADT/StringSwitch.h"
+
+namespace llvm {
+namespace AArch64BuildAttributes {
+
+StringRef getVendorName(unsigned Vendor) {
+  switch (Vendor) {
+  case AEABI_FEATURE_AND_BITS:
+    return "aeabi_feature_and_bits";
+  case AEABI_PAUTHABI:
+    return "aeabi_pauthabi";
+  case VENDOR_UNKNOWN:
+    return "";
+  default:
+    assert(0 && "Vendor name error");
+    return "";
+  }
+}
+VendorID 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 getOptionalStr(unsigned Optional) {
+  switch (Optional) {
+  case REQUIRED:
+    return "required";
+  case OPTIONAL:
+    return "optional";
+  case OPTIONAL_NOT_FOUND:
+  default:
+    return "";
+  }
+}
+SubsectionOptional getOptionalID(StringRef Optional) {
+  return StringSwitch<SubsectionOptional>(Optional)
+      .Case("required", REQUIRED)
+      .Case("optional", OPTIONAL)
+      .Default(OPTIONAL_NOT_FOUND);
+}
+StringRef getSubsectionOptionalUnknownError() {
+  return "unknown AArch64 build attributes optionality, expected "
+         "required|optional";
+}
+
+StringRef getTypeStr(unsigned Type) {
+  switch (Type) {
+  case ULEB128:
+    return "uleb128";
+  case NTBS:
+    return "ntbs";
+  case TYPE_NOT_FOUND:
+  default:
+    return "";
+  }
+}
+SubsectionType getTypeID(StringRef Type) {
+  return StringSwitch<SubsectionType>(Type)
+      .Cases("uleb128", "ULEB128", ULEB128)
+      .Cases("ntbs", "NTBS", NTBS)
+      .Default(TYPE_NOT_FOUND);
+}
+StringRef getSubsectionTypeUnknownError() {
+  return "unknown AArch64 build attributes type, expected uleb128|ntbs";
+}
+
+StringRef getPauthABITagsStr(unsigned PauthABITag) {
+  switch (PauthABITag) {
+  case TAG_PAUTH_PLATFORM:
+    return "Tag_PAuth_Platform";
+  case TAG_PAUTH_SCHEMA:
+    return "Tag_PAuth_Schema";
+  case PAUTHABI_TAG_NOT_FOUND:
+  default:
+    return "";
+  }
+}
+PauthABITags getPauthABITagsID(StringRef PauthABITag) {
+  return StringSwitch<PauthABITags>(PauthABITag)
+      .Case("Tag_PAuth_Platform", TAG_PAUTH_PLATFORM)
+      .Case("Tag_PAuth_Schema", TAG_PAUTH_SCHEMA)
+      .Default(PAUTHABI_TAG_NOT_FOUND);
+}
+
+StringRef getFeatureAndBitsTagsStr(unsigned FeatureAndBitsTag) {
+  switch (FeatureAndBitsTag) {
+  case TAG_FEATURE_BTI:
+    return "Tag_Feature_BTI";
+  case TAG_FEATURE_PAC:
+    return "Tag_Feature_PAC";
+  case TAG_FEATURE_GCS:
+    return "Tag_Feature_GCS";
+  case FEATURE_AND_BITS_TAG_NOT_FOUND:
+  default:
+    return "";
+  }
+}
+FeatureAndBitsTags getFeatureAndBitsTagsID(StringRef FeatureAndBitsTag) {
+  return StringSwitch<FeatureAndBitsTags>(FeatureAndBitsTag)
+      .Case("Tag_Feature_BTI", TAG_FEATURE_BTI)
+      .Case("Tag_Feature_PAC", TAG_FEATURE_PAC)
+      .Case("Tag_Feature_GCS", TAG_FEATURE_GCS)
+      .Default(FEATURE_AND_BITS_TAG_NOT_FOUND);
+}
+} // namespace AArch64BuildAttributes
+} // namespace llvm

diff  --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt
index 2ecaea4b02bf61..122240c27b1fcd 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
   ARMBuildAttrs.cpp
+  AArch64BuildAttributes.cpp
   ARMAttributeParser.cpp
   ARMWinEH.cpp
   Allocator.cpp

diff  --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index 27e65d60122fd7..8d8520c68232be 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -208,6 +208,10 @@ class AArch64AsmPrinter : public AsmPrinter {
   /// pseudo instructions.
   bool lowerPseudoInstExpansion(const MachineInstr *MI, MCInst &Inst);
 
+  // Emit Build Attributes
+  void emitAttributes(unsigned Flags, uint64_t PAuthABIPlatform,
+                      uint64_t PAuthABIVersion, AArch64TargetStreamer *TS);
+
   void EmitToStreamer(MCStreamer &S, const MCInst &Inst);
   void EmitToStreamer(const MCInst &Inst) {
     EmitToStreamer(*OutStreamer, Inst);
@@ -345,36 +349,53 @@ void AArch64AsmPrinter::emitStartOfAsmFile(Module &M) {
   if (!TT.isOSBinFormatELF())
     return;
 
-  // Assemble feature flags that may require creation of a note section.
-  unsigned Flags = 0;
+  // For emitting build attributes and .note.gnu.property section
+  auto *TS =
+      static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
+  // Assemble feature flags that may require creation of build attributes and a
+  // note section.
+  unsigned BAFlags = 0;
+  unsigned GNUFlags = 0;
   if (const auto *BTE = mdconst::extract_or_null<ConstantInt>(
-          M.getModuleFlag("branch-target-enforcement")))
-    if (!BTE->isZero())
-      Flags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
+          M.getModuleFlag("branch-target-enforcement"))) {
+    if (!BTE->isZero()) {
+      BAFlags |= AArch64BuildAttributes::FeatureAndBitsFlag::Feature_BTI_Flag;
+      GNUFlags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
+    }
+  }
 
   if (const auto *GCS = mdconst::extract_or_null<ConstantInt>(
-          M.getModuleFlag("guarded-control-stack")))
-    if (!GCS->isZero())
-      Flags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
+          M.getModuleFlag("guarded-control-stack"))) {
+    if (!GCS->isZero()) {
+      BAFlags |= AArch64BuildAttributes::FeatureAndBitsFlag::Feature_GCS_Flag;
+      GNUFlags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
+    }
+  }
 
   if (const auto *Sign = mdconst::extract_or_null<ConstantInt>(
-          M.getModuleFlag("sign-return-address")))
-    if (!Sign->isZero())
-      Flags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_PAC;
+          M.getModuleFlag("sign-return-address"))) {
+    if (!Sign->isZero()) {
+      BAFlags |= AArch64BuildAttributes::FeatureAndBitsFlag::Feature_PAC_Flag;
+      GNUFlags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_PAC;
+    }
+  }
 
   uint64_t PAuthABIPlatform = -1;
   if (const auto *PAP = mdconst::extract_or_null<ConstantInt>(
-          M.getModuleFlag("aarch64-elf-pauthabi-platform")))
+          M.getModuleFlag("aarch64-elf-pauthabi-platform"))) {
     PAuthABIPlatform = PAP->getZExtValue();
+  }
+
   uint64_t PAuthABIVersion = -1;
   if (const auto *PAV = mdconst::extract_or_null<ConstantInt>(
-          M.getModuleFlag("aarch64-elf-pauthabi-version")))
+          M.getModuleFlag("aarch64-elf-pauthabi-version"))) {
     PAuthABIVersion = PAV->getZExtValue();
+  }
 
+  // Emit AArch64 Build Attributes
+  emitAttributes(BAFlags, PAuthABIPlatform, PAuthABIVersion, TS);
   // Emit a .note.gnu.property section with the flags.
-  auto *TS =
-      static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
-  TS->emitNoteSection(Flags, PAuthABIPlatform, PAuthABIVersion);
+  TS->emitNoteSection(GNUFlags, PAuthABIPlatform, PAuthABIVersion);
 }
 
 void AArch64AsmPrinter::emitFunctionHeaderComment() {
@@ -447,6 +468,58 @@ void AArch64AsmPrinter::emitSled(const MachineInstr &MI, SledKind Kind) {
   recordSled(CurSled, MI, Kind, 2);
 }
 
+void AArch64AsmPrinter::emitAttributes(unsigned Flags,
+                                       uint64_t PAuthABIPlatform,
+                                       uint64_t PAuthABIVersion,
+                                       AArch64TargetStreamer *TS) {
+
+  PAuthABIPlatform = (uint64_t(-1) == PAuthABIPlatform) ? 0 : PAuthABIPlatform;
+  PAuthABIVersion = (uint64_t(-1) == PAuthABIVersion) ? 0 : PAuthABIVersion;
+
+  if (PAuthABIPlatform || PAuthABIVersion) {
+    TS->emitAtributesSubsection(
+        AArch64BuildAttributes::getVendorName(
+            AArch64BuildAttributes::AEABI_PAUTHABI),
+        AArch64BuildAttributes::SubsectionOptional::REQUIRED,
+        AArch64BuildAttributes::SubsectionType::ULEB128);
+    TS->emitAttribute(AArch64BuildAttributes::getVendorName(
+                          AArch64BuildAttributes::AEABI_PAUTHABI),
+                      AArch64BuildAttributes::TAG_PAUTH_PLATFORM,
+                      PAuthABIPlatform, "", false);
+    TS->emitAttribute(AArch64BuildAttributes::getVendorName(
+                          AArch64BuildAttributes::AEABI_PAUTHABI),
+                      AArch64BuildAttributes::TAG_PAUTH_SCHEMA, PAuthABIVersion,
+                      "", false);
+  }
+
+  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(
+        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, "",
+                      false);
+    TS->emitAttribute(AArch64BuildAttributes::getVendorName(
+                          AArch64BuildAttributes::AEABI_FEATURE_AND_BITS),
+                      AArch64BuildAttributes::TAG_FEATURE_PAC, PACValue, "",
+                      false);
+    TS->emitAttribute(AArch64BuildAttributes::getVendorName(
+                          AArch64BuildAttributes::AEABI_FEATURE_AND_BITS),
+                      AArch64BuildAttributes::TAG_FEATURE_GCS, GCSValue, "",
+                      false);
+  }
+}
+
 // Emit the following code for Intrinsic::{xray_customevent,xray_typedevent}
 // (built-in functions __xray_customevent/__xray_typedevent).
 //

diff  --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 92f9f7309f8ec0..d3eda48f3276e9 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -42,7 +42,7 @@
 #include "llvm/MC/MCTargetOptions.h"
 #include "llvm/MC/MCValue.h"
 #include "llvm/MC/TargetRegistry.h"
-#include "llvm/Support/Casting.h"
+#include "llvm/Support/AArch64BuildAttributes.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/MathExtras.h"
@@ -228,6 +228,8 @@ class AArch64AsmParser : public MCTargetAsmParser {
   bool parseDirectiveSEHClearUnwoundToCall(SMLoc L);
   bool parseDirectiveSEHPACSignLR(SMLoc L);
   bool parseDirectiveSEHSaveAnyReg(SMLoc L, bool Paired, bool Writeback);
+  bool parseDirectiveAeabiSubSectionHeader(SMLoc L);
+  bool parseDirectiveAeabiAArch64Attr(SMLoc L);
 
   bool validateInstruction(MCInst &Inst, SMLoc &IDLoc,
                            SmallVectorImpl<SMLoc> &Loc);
@@ -6992,6 +6994,7 @@ bool AArch64AsmParser::ParseDirective(AsmToken DirectiveID) {
   const MCContext::Environment Format = getContext().getObjectFileType();
   bool IsMachO = Format == MCContext::IsMachO;
   bool IsCOFF = Format == MCContext::IsCOFF;
+  bool IsELF = Format == MCContext::IsELF;
 
   auto IDVal = DirectiveID.getIdentifier().lower();
   SMLoc Loc = DirectiveID.getLoc();
@@ -7087,6 +7090,13 @@ bool AArch64AsmParser::ParseDirective(AsmToken DirectiveID) {
       parseDirectiveSEHSaveAnyReg(Loc, true, true);
     else
       return true;
+  } else if (IsELF) {
+    if (IDVal == ".aeabi_subsection")
+      parseDirectiveAeabiSubSectionHeader(Loc);
+    else if (IDVal == ".aeabi_attribute")
+      parseDirectiveAeabiAArch64Attr(Loc);
+    else
+      return true;
   } else
     return true;
   return false;
@@ -7823,6 +7833,265 @@ bool AArch64AsmParser::parseDirectiveSEHSaveAnyReg(SMLoc L, bool Paired,
   return false;
 }
 
+bool AArch64AsmParser::parseDirectiveAeabiSubSectionHeader(SMLoc L) {
+  // Expecting 3 AsmToken::Identifier after '.aeabi_subsection', a name and 2
+  // parameters, e.g.: .aeabi_subsection (1)aeabi_feature_and_bits, (2)optional,
+  // (3)uleb128 separated by 2 commas.
+  MCAsmParser &Parser = getParser();
+
+  // Consume the name (subsection name)
+  StringRef SubsectionName;
+  AArch64BuildAttributes::VendorID SubsectionNameID;
+  if (Parser.getTok().is(AsmToken::Identifier)) {
+    SubsectionName = Parser.getTok().getIdentifier();
+    SubsectionNameID = AArch64BuildAttributes::getVendorID(SubsectionName);
+  } else {
+    Error(Parser.getTok().getLoc(), "subsection name not found");
+    return true;
+  }
+  Parser.Lex();
+  // consume a comma
+  // parseComma() return *false* on success, and call Lex(), no need to call
+  // Lex() again.
+  if (Parser.parseComma()) {
+    return true;
+  }
+
+  std::unique_ptr<MCELFStreamer::AttributeSubSection> SubsectionExists =
+      getTargetStreamer().getAtributesSubsectionByName(SubsectionName);
+
+  // Consume the first parameter (optionality parameter)
+  AArch64BuildAttributes::SubsectionOptional IsOptional;
+  // options: optional/required
+  if (Parser.getTok().is(AsmToken::Identifier)) {
+    StringRef Optionality = Parser.getTok().getIdentifier();
+    IsOptional = AArch64BuildAttributes::getOptionalID(Optionality);
+    if (AArch64BuildAttributes::OPTIONAL_NOT_FOUND == IsOptional) {
+      Error(Parser.getTok().getLoc(),
+            AArch64BuildAttributes::getSubsectionOptionalUnknownError() + ": " +
+                Optionality);
+      return true;
+    }
+    if (SubsectionExists) {
+      if (IsOptional != SubsectionExists->IsOptional) {
+        Error(Parser.getTok().getLoc(),
+              "optionality mismatch! subsection '" + SubsectionName +
+                  "' already exists with optionality defined as '" +
+                  AArch64BuildAttributes::getOptionalStr(
+                      SubsectionExists->IsOptional) +
+                  "' and not '" +
+                  AArch64BuildAttributes::getOptionalStr(IsOptional) + "'");
+        return true;
+      }
+    }
+  } else {
+    Error(Parser.getTok().getLoc(),
+          "optionality parameter not found, expected required|optional");
+    return true;
+  }
+  // Check for possible IsOptional unaccepted values for known subsections
+  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 (AArch64BuildAttributes::AEABI_PAUTHABI == SubsectionNameID) {
+    if (AArch64BuildAttributes::OPTIONAL == IsOptional) {
+      Error(Parser.getTok().getLoc(),
+            "aeabi_pauthabi must be marked as required");
+      return true;
+    }
+  }
+  Parser.Lex();
+  // consume a comma
+  if (Parser.parseComma()) {
+    return true;
+  }
+
+  // Consume the second parameter (type parameter)
+  AArch64BuildAttributes::SubsectionType Type;
+  if (Parser.getTok().is(AsmToken::Identifier)) {
+    StringRef Name = Parser.getTok().getIdentifier();
+    Type = AArch64BuildAttributes::getTypeID(Name);
+    if (AArch64BuildAttributes::TYPE_NOT_FOUND == Type) {
+      Error(Parser.getTok().getLoc(),
+            AArch64BuildAttributes::getSubsectionTypeUnknownError() + ": " +
+                Name);
+      return true;
+    }
+    if (SubsectionExists) {
+      if (Type != SubsectionExists->ParameterType) {
+        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;
+      }
+    }
+  } else {
+    Error(Parser.getTok().getLoc(),
+          "type parameter not found, expected uleb128|ntbs");
+    return true;
+  }
+  // Check for possible unaccepted 'type' values for known subsections
+  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;
+    }
+  }
+  Parser.Lex();
+  // Parsing finished, check for trailing tokens.
+  if (Parser.getTok().isNot(llvm::AsmToken::EndOfStatement)) {
+    Error(Parser.getTok().getLoc(), "unexpected token for AArch64 build "
+                                    "attributes subsection header directive");
+    return true;
+  }
+
+  getTargetStreamer().emitAtributesSubsection(SubsectionName, IsOptional, Type);
+
+  return false;
+}
+
+bool AArch64AsmParser::parseDirectiveAeabiAArch64Attr(SMLoc L) {
+  // Expecting 2 Tokens: after '.aeabi_attribute', e.g.:
+  // .aeabi_attribute	(1)Tag_Feature_BTI, (2)[uleb128|ntbs]
+  // separated by a comma.
+  MCAsmParser &Parser = getParser();
+
+  std::unique_ptr<MCELFStreamer::AttributeSubSection> ActiveSubsection =
+      getTargetStreamer().getActiveAtributesSubsection();
+  if (nullptr == ActiveSubsection) {
+    Error(Parser.getTok().getLoc(),
+          "no active subsection, build attribute can not be added");
+    return true;
+  }
+  StringRef ActiveSubsectionName = ActiveSubsection->VendorName;
+  unsigned ActiveSubsectionType = ActiveSubsection->ParameterType;
+
+  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 = AArch64BuildAttributes::AEABI_FEATURE_AND_BITS;
+
+  StringRef TagStr = "";
+  unsigned Tag;
+  if (Parser.getTok().is(AsmToken::Identifier)) {
+    TagStr = Parser.getTok().getIdentifier();
+    switch (ActiveSubsectionID) {
+    default:
+      assert(0 && "Subsection name error");
+      break;
+    case AArch64BuildAttributes::VENDOR_UNKNOWN:
+      // Private subsection, accept any tag.
+      break;
+    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 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 + "'");
+        return true;
+      }
+      break;
+    }
+  } else if (Parser.getTok().is(AsmToken::Integer)) {
+    Tag = getTok().getIntVal();
+  } else {
+    Error(Parser.getTok().getLoc(), "AArch64 build attributes tag not found");
+    return true;
+  }
+  Parser.Lex();
+  // consume a comma
+  // parseComma() return *false* on success, and call Lex(), no need to call
+  // Lex() again.
+  if (Parser.parseComma()) {
+    return true;
+  }
+
+  // Consume the second parameter (attribute value)
+  unsigned ValueInt = unsigned(-1);
+  std::string ValueStr = "";
+  if (Parser.getTok().is(AsmToken::Integer)) {
+    if (AArch64BuildAttributes::NTBS == ActiveSubsectionType) {
+      Error(
+          Parser.getTok().getLoc(),
+          "active subsection type is NTBS (string), found ULEB128 (unsigned)");
+      return true;
+    }
+    ValueInt = getTok().getIntVal();
+  } else if (Parser.getTok().is(AsmToken::Identifier)) {
+    if (AArch64BuildAttributes::ULEB128 == ActiveSubsectionType) {
+      Error(
+          Parser.getTok().getLoc(),
+          "active subsection type is ULEB128 (unsigned), found NTBS (string)");
+      return true;
+    }
+    ValueStr = Parser.getTok().getIdentifier();
+  } else if (Parser.getTok().is(AsmToken::String)) {
+    if (AArch64BuildAttributes::ULEB128 == ActiveSubsectionType) {
+      Error(
+          Parser.getTok().getLoc(),
+          "active subsection type is ULEB128 (unsigned), found NTBS (string)");
+      return true;
+    }
+    ValueStr = Parser.getTok().getString();
+  } else {
+    Error(Parser.getTok().getLoc(), "AArch64 build attributes value not found");
+    return true;
+  }
+  // Check for possible unaccepted values for known tags (AEABI_PAUTHABI,
+  // AEABI_FEATURE_AND_BITS)
+  if (!(ActiveSubsectionID == AArch64BuildAttributes::VENDOR_UNKNOWN) &&
+      TagStr != "") { // TagStr was a recognized string
+    if (0 != ValueInt && 1 != ValueInt) {
+      Error(Parser.getTok().getLoc(),
+            "unknown AArch64 build attributes Value for Tag '" + TagStr +
+                "' options are 0|1");
+      return true;
+    }
+  }
+  Parser.Lex();
+  // Parsing finished, check for trailing tokens.
+  if (Parser.getTok().isNot(llvm::AsmToken::EndOfStatement)) {
+    Error(Parser.getTok().getLoc(),
+          "unexpected token for AArch64 build attributes tag and value "
+          "attribute directive");
+    return true;
+  }
+
+  if (unsigned(-1) != ValueInt) {
+    getTargetStreamer().emitAttribute(ActiveSubsectionName, Tag, ValueInt, "",
+                                      false);
+  }
+
+  if ("" != ValueStr) {
+    getTargetStreamer().emitAttribute(ActiveSubsectionName, Tag, unsigned(-1),
+                                      ValueStr, false);
+  }
+  return false;
+}
+
 bool AArch64AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) {
   // Try @AUTH expressions: they're more complex than the usual symbol variants.
   if (!parseAuthExpr(Res, EndLoc))

diff  --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
index 5bae846824548b..9f7a60074daeb9 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
@@ -33,6 +33,7 @@
 #include "llvm/MC/MCSymbolELF.h"
 #include "llvm/MC/MCTargetOptions.h"
 #include "llvm/MC/MCWinCOFFStreamer.h"
+#include "llvm/Support/AArch64BuildAttributes.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/FormattedStream.h"
 #include "llvm/Support/raw_ostream.h"
@@ -45,6 +46,7 @@ class AArch64ELFStreamer;
 
 class AArch64TargetAsmStreamer : public AArch64TargetStreamer {
   formatted_raw_ostream &OS;
+  std::string VendorTag;
 
   void emitInst(uint32_t Inst) override;
 
@@ -148,13 +150,137 @@ class AArch64TargetAsmStreamer : public AArch64TargetStreamer {
     OS << "\t.seh_save_any_reg_px\tq" << Reg << ", " << Offset << "\n";
   }
 
+  void emitAttribute(StringRef VendorName, unsigned Tag, unsigned Value,
+                     std::string String, bool Override) override {
+
+    // AArch64 build attributes for assembly attribute form:
+    // .aeabi_attribute tag, value
+    if (unsigned(-1) == Value && "" == String) {
+      assert(0 && "Arguments error");
+      return;
+    }
+
+    unsigned VendorID = AArch64BuildAttributes::getVendorID(VendorName);
+
+    switch (VendorID) {
+    default:
+      assert(0 && "Subsection name error");
+      break;
+    case AArch64BuildAttributes::VENDOR_UNKNOWN:
+      if (unsigned(-1) != Value) {
+        OS << "\t.aeabi_attribute" << "\t" << Tag << ", " << Value;
+        AArch64TargetStreamer::emitAttribute(VendorName, Tag, Value, "",
+                                             Override);
+      }
+      if ("" != String) {
+        OS << "\t.aeabi_attribute" << "\t" << Tag << ", " << String;
+        AArch64TargetStreamer::emitAttribute(VendorName, Tag, unsigned(-1),
+                                             String, Override);
+      }
+      break;
+    // Note: AEABI_FEATURE_AND_BITS takes only unsigned values
+    case AArch64BuildAttributes::AEABI_FEATURE_AND_BITS:
+      switch (Tag) {
+      default: // allow emitting any attribute by number
+        OS << "\t.aeabi_attribute" << "\t" << Tag << ", " << Value;
+        // Keep the data structure consistent with the case of ELF emission
+        // (important for llvm-mc asm parsing)
+        AArch64TargetStreamer::emitAttribute(VendorName, Tag, Value, "",
+                                             Override);
+        break;
+      case AArch64BuildAttributes::TAG_FEATURE_BTI:
+      case AArch64BuildAttributes::TAG_FEATURE_GCS:
+      case AArch64BuildAttributes::TAG_FEATURE_PAC:
+        OS << "\t.aeabi_attribute" << "\t"
+           << AArch64BuildAttributes::getFeatureAndBitsTagsStr(Tag) << ", "
+           << Value;
+        AArch64TargetStreamer::emitAttribute(VendorName, Tag, Value, "",
+                                             Override);
+        break;
+      }
+      break;
+    // Note: AEABI_PAUTHABI takes only unsigned values
+    case AArch64BuildAttributes::AEABI_PAUTHABI:
+      switch (Tag) {
+      default: // allow emitting any attribute by number
+        OS << "\t.aeabi_attribute" << "\t" << Tag << ", " << Value;
+        // Keep the data structure consistent with the case of ELF emission
+        // (important for llvm-mc asm parsing)
+        AArch64TargetStreamer::emitAttribute(VendorName, Tag, Value, "",
+                                             Override);
+        break;
+      case AArch64BuildAttributes::TAG_PAUTH_PLATFORM:
+      case AArch64BuildAttributes::TAG_PAUTH_SCHEMA:
+        OS << "\t.aeabi_attribute" << "\t"
+           << AArch64BuildAttributes::getPauthABITagsStr(Tag) << ", " << Value;
+        AArch64TargetStreamer::emitAttribute(VendorName, Tag, Value, "",
+                                             Override);
+        break;
+      }
+      break;
+    }
+    OS << "\n";
+  }
+
+  void emitAtributesSubsection(
+      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 = AArch64BuildAttributes::getVendorID(SubsectionName);
+
+    assert((0 == Optional || 1 == Optional) &&
+           AArch64BuildAttributes::getSubsectionOptionalUnknownError().data());
+    assert((0 == ParameterType || 1 == ParameterType) &&
+           AArch64BuildAttributes::getSubsectionTypeUnknownError().data());
+
+    std::string SubsectionTag = ".aeabi_subsection";
+    StringRef OptionalStr = getOptionalStr(Optional);
+    StringRef ParameterStr = getTypeStr(ParameterType);
+
+    switch (SubsectionID) {
+    default: {
+      // Treated as a private subsection
+      break;
+    }
+    case AArch64BuildAttributes::AEABI_PAUTHABI: {
+      assert(AArch64BuildAttributes::REQUIRED == Optional &&
+             "subsection .aeabi-pauthabi should be marked as "
+             "required and not as optional");
+      assert(AArch64BuildAttributes::ULEB128 == ParameterType &&
+             "subsection .aeabi-pauthabi should be "
+             "marked as uleb128 and not as ntbs");
+      break;
+    }
+    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(AArch64BuildAttributes::ULEB128 == ParameterType &&
+             "subsection .aeabi_feature_and_bits should "
+             "be marked as uleb128 and not as ntbs");
+      break;
+    }
+    }
+    OS << "\t" << SubsectionTag << "\t" << SubsectionName << ", " << OptionalStr
+       << ", " << ParameterStr;
+    // Keep the data structure consistent with the case of ELF emission
+    // (important for llvm-mc asm parsing)
+    AArch64TargetStreamer::emitAtributesSubsection(SubsectionName, Optional,
+                                                   ParameterType);
+    OS << "\n";
+  }
+
 public:
   AArch64TargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS);
 };
 
 AArch64TargetAsmStreamer::AArch64TargetAsmStreamer(MCStreamer &S,
                                                    formatted_raw_ostream &OS)
-  : AArch64TargetStreamer(S), OS(OS) {}
+    : AArch64TargetStreamer(S), OS(OS) {}
 
 void AArch64TargetAsmStreamer::emitInst(uint32_t Inst) {
   OS << "\t.inst\t0x" << Twine::utohexstr(Inst) << "\n";
@@ -294,6 +420,23 @@ AArch64ELFStreamer &AArch64TargetELFStreamer::getStreamer() {
   return static_cast<AArch64ELFStreamer &>(Streamer);
 }
 
+void AArch64TargetELFStreamer::emitAtributesSubsection(
+    StringRef VendorName, AArch64BuildAttributes::SubsectionOptional IsOptional,
+    AArch64BuildAttributes::SubsectionType ParameterType) {
+  AArch64TargetStreamer::emitAtributesSubsection(VendorName, IsOptional,
+                                                 ParameterType);
+}
+
+void AArch64TargetELFStreamer::emitAttribute(StringRef VendorName, unsigned Tag,
+                                             unsigned Value, std::string String,
+                                             bool Override) {
+  if (unsigned(-1) != Value)
+    AArch64TargetStreamer::emitAttribute(VendorName, Tag, Value, "", Override);
+  if ("" != String)
+    AArch64TargetStreamer::emitAttribute(VendorName, Tag, unsigned(-1), String,
+                                         Override);
+}
+
 void AArch64TargetELFStreamer::emitInst(uint32_t Inst) {
   getStreamer().emitInst(Inst);
 }
@@ -309,6 +452,9 @@ void AArch64TargetELFStreamer::finish() {
   MCContext &Ctx = S.getContext();
   auto &Asm = S.getAssembler();
 
+  S.emitAttributesSection(AttributeSection, ".ARM.attributes",
+                          ELF::SHT_AARCH64_ATTRIBUTES, AttributeSubSections);
+
   // If ImplicitMapSyms is specified, ensure that text sections end with
   // the A64 state while non-text sections end with the data state. When
   // sections are combined by the linker, the subsequent section will start with

diff  --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp
index 7bd89c9e29a728..74ffe5f97f1b69 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp
@@ -151,3 +151,107 @@ llvm::createAArch64ObjectTargetStreamer(MCStreamer &S,
 MCTargetStreamer *llvm::createAArch64NullTargetStreamer(MCStreamer &S) {
   return new AArch64TargetStreamer(S);
 }
+
+void AArch64TargetStreamer::emitAtributesSubsection(
+    StringRef VendorName, AArch64BuildAttributes::SubsectionOptional IsOptional,
+    AArch64BuildAttributes::SubsectionType ParameterType) {
+
+  // If exists, return.
+  for (MCELFStreamer::AttributeSubSection &SubSection : AttributeSubSections) {
+    if (VendorName == SubSection.VendorName) {
+      activateAtributesSubsection(VendorName);
+      return;
+    }
+  }
+  // else, add the subsection
+  MCELFStreamer::AttributeSubSection AttSubSection;
+  AttSubSection.VendorName = VendorName;
+  AttSubSection.IsOptional = IsOptional;
+  AttSubSection.ParameterType = ParameterType;
+  AttributeSubSections.push_back(AttSubSection);
+  activateAtributesSubsection(VendorName);
+}
+
+std::unique_ptr<MCELFStreamer::AttributeSubSection>
+AArch64TargetStreamer::getActiveAtributesSubsection() {
+  for (MCELFStreamer::AttributeSubSection &SubSection : AttributeSubSections) {
+    if (SubSection.IsActive) {
+      return std::make_unique<MCELFStreamer::AttributeSubSection>(SubSection);
+    }
+  }
+  return nullptr;
+}
+
+std::unique_ptr<MCELFStreamer::AttributeSubSection>
+AArch64TargetStreamer::getAtributesSubsectionByName(StringRef Name) {
+  for (MCELFStreamer::AttributeSubSection &SubSection : AttributeSubSections) {
+    if (Name == SubSection.VendorName) {
+      return std::make_unique<MCELFStreamer::AttributeSubSection>(SubSection);
+    }
+  }
+  return nullptr;
+}
+
+void AArch64TargetStreamer::emitAttribute(StringRef VendorName, unsigned Tag,
+                                          unsigned Value, std::string String,
+                                          bool Override) {
+
+  if (unsigned(-1) == Value && "" == String) {
+    assert(0 && "Arguments error");
+    return;
+  }
+  if (AttributeSubSections.size() == 0) {
+    assert(0 &&
+           "Can not add AArch64 build attribute: no AArch64 subsection exists");
+    return;
+  }
+
+  for (MCELFStreamer::AttributeSubSection &SubSection : AttributeSubSections) {
+    if (VendorName == SubSection.VendorName) {
+      if (!SubSection.IsActive) {
+        assert(0 &&
+               "Can not add AArch64 build attribute: subsection is not active");
+        return;
+      }
+      for (MCELFStreamer::AttributeItem &Item : SubSection.Content) {
+        if (Item.Tag == Tag) {
+          if (!Override) {
+            if ((unsigned(-1) != Value && Item.IntValue != Value) ||
+                ("" != String && Item.StringValue != String)) {
+              assert(0 &&
+                     "Can not add AArch64 build attribute: An attribute with "
+                     "the same tag and a 
diff erent value already exists");
+              return;
+            } else {
+              // Case Item.IntValue == Value, no need to emit twice
+              assert(0 &&
+                     "AArch64 build attribute: An attribute with the same tag "
+                     "and a same value already exists");
+              return;
+            }
+          }
+        }
+      }
+      if (unsigned(-1) != Value)
+        SubSection.Content.push_back(MCELFStreamer::AttributeItem(
+            MCELFStreamer::AttributeItem::NumericAttribute, Tag, Value, ""));
+      if ("" != String)
+        SubSection.Content.push_back(MCELFStreamer::AttributeItem(
+            MCELFStreamer::AttributeItem::TextAttribute, Tag, unsigned(-1),
+            String));
+      return;
+    }
+  }
+  assert(0 && "Can not add AArch64 build attribute: required subsection does "
+              "not exist");
+}
+
+void AArch64TargetStreamer::activateAtributesSubsection(StringRef VendorName) {
+  for (MCELFStreamer::AttributeSubSection &SubSection : AttributeSubSections) {
+    if (VendorName == SubSection.VendorName) {
+      SubSection.IsActive = true;
+    } else {
+      SubSection.IsActive = false;
+    }
+  }
+}
\ No newline at end of file

diff  --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h
index 1c0f5d848c00c6..b2b9afe8670738 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h
@@ -10,7 +10,12 @@
 #define LLVM_LIB_TARGET_AARCH64_MCTARGETDESC_AARCH64TARGETSTREAMER_H
 
 #include "AArch64MCExpr.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/MC/MCELFStreamer.h"
 #include "llvm/MC/MCStreamer.h"
+#include "llvm/Support/AArch64BuildAttributes.h"
+#include <cstdint>
 
 namespace {
 class AArch64ELFStreamer;
@@ -89,6 +94,24 @@ class AArch64TargetStreamer : public MCTargetStreamer {
   virtual void emitARM64WinCFISaveAnyRegQX(unsigned Reg, int Offset) {}
   virtual void emitARM64WinCFISaveAnyRegQPX(unsigned Reg, int Offset) {}
 
+  /// Build attributes implementation
+  virtual void
+  emitAtributesSubsection(StringRef VendorName,
+                          AArch64BuildAttributes::SubsectionOptional IsOptional,
+                          AArch64BuildAttributes::SubsectionType ParameterType);
+  virtual void emitAttribute(StringRef VendorName, unsigned Tag, unsigned Value,
+                             std::string String, bool Override);
+  void activateAtributesSubsection(StringRef VendorName);
+  std::unique_ptr<MCELFStreamer::AttributeSubSection>
+  getActiveAtributesSubsection();
+  std::unique_ptr<MCELFStreamer::AttributeSubSection>
+  getAtributesSubsectionByName(StringRef Name);
+  void
+  insertAttributeInPlace(const MCELFStreamer::AttributeItem &Attr,
+                         MCELFStreamer::AttributeSubSection &AttSubSection);
+
+  SmallVector<MCELFStreamer::AttributeSubSection, 64> AttributeSubSections;
+
 private:
   std::unique_ptr<AssemblerConstantPools> ConstantPools;
 };
@@ -97,6 +120,15 @@ class AArch64TargetELFStreamer : public AArch64TargetStreamer {
 private:
   AArch64ELFStreamer &getStreamer();
 
+  MCSection *AttributeSection = nullptr;
+
+  /// Build attributes implementation
+  void emitAtributesSubsection(
+      StringRef VendorName,
+      AArch64BuildAttributes::SubsectionOptional IsOptional,
+      AArch64BuildAttributes::SubsectionType ParameterType) override;
+  void emitAttribute(StringRef VendorName, unsigned Tag, unsigned Value,
+                     std::string String, bool Override = false) override;
   void emitInst(uint32_t Inst) override;
   void emitDirectiveVariantPCS(MCSymbol *Symbol) override;
   void finish() override;

diff  --git a/llvm/test/CodeGen/AArch64/aarch64-build-attributes-all.ll b/llvm/test/CodeGen/AArch64/aarch64-build-attributes-all.ll
new file mode 100644
index 00000000000000..81ece7aec8793b
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/aarch64-build-attributes-all.ll
@@ -0,0 +1,22 @@
+; RUN: llc %s -o - | FileCheck %s --check-prefix=ASM
+; RUN: llc %s -filetype=obj -o - | llvm-readelf --hex-dump=.ARM.attributes - | FileCheck %s --check-prefix=ELF
+
+; ASM: .text
+; ASM-NEXT:      .aeabi_subsection	aeabi_feature_and_bits, optional, uleb128
+; ASM-NEXT: .aeabi_attribute	Tag_Feature_BTI, 1
+; ASM-NEXT: .aeabi_attribute	Tag_Feature_PAC, 1
+; ASM-NEXT: .aeabi_attribute	Tag_Feature_GCS, 1
+
+; ELF: Hex dump of section '.ARM.attributes':
+; ELF-NEXT: 0x00000000 41230000 00616561 62695f66 65617475 A#...aeabi_featu
+; ELF-NEXT: 0x00000010 72655f61 6e645f62 69747300 01000001 re_and_bits.....
+; ELF-NEXT: 0x00000020 01010201
+
+
+target triple = "aarch64-unknown-none-elf"
+
+!llvm.module.flags = !{!1, !2, !3}
+
+!1 = !{i32 8, !"branch-target-enforcement", i32 1}
+!2 = !{i32 8, !"guarded-control-stack", i32 1}
+!3 = !{i32 8, !"sign-return-address", i32 1}

diff  --git a/llvm/test/CodeGen/AArch64/aarch64-build-attributes-bti.ll b/llvm/test/CodeGen/AArch64/aarch64-build-attributes-bti.ll
new file mode 100644
index 00000000000000..e719e06553cc0f
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/aarch64-build-attributes-bti.ll
@@ -0,0 +1,20 @@
+; RUN: llc < %s | FileCheck %s --check-prefix=ASM
+; RUN: llc %s -filetype=obj -o - | llvm-readelf --hex-dump=.ARM.attributes - | FileCheck %s --check-prefix=ELF
+
+; ASM: .text
+; ASM-NEXT:      .aeabi_subsection	aeabi_feature_and_bits, optional, uleb128
+; ASM-NEXT: .aeabi_attribute	Tag_Feature_BTI, 1
+; ASM-NEXT: .aeabi_attribute	Tag_Feature_PAC, 0
+; ASM-NEXT: .aeabi_attribute	Tag_Feature_GCS, 0
+
+; ELF: Hex dump of section '.ARM.attributes':
+; ELF-NEXT: 0x00000000 41230000 00616561 62695f66 65617475 A#...aeabi_featu
+; ELF-NEXT: 0x00000010 72655f61 6e645f62 69747300 01000001 re_and_bits.....
+; ELF-NEXT: 0x00000020 01000200 
+
+
+target triple = "aarch64-unknown-none-elf"
+
+!llvm.module.flags = !{!1}
+
+!1 = !{i32 8, !"branch-target-enforcement", i32 1}

diff  --git a/llvm/test/CodeGen/AArch64/aarch64-build-attributes-gcs.ll b/llvm/test/CodeGen/AArch64/aarch64-build-attributes-gcs.ll
new file mode 100644
index 00000000000000..6f231025a11e33
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/aarch64-build-attributes-gcs.ll
@@ -0,0 +1,20 @@
+; RUN: llc < %s | FileCheck %s --check-prefix=ASM
+; RUN: llc %s -filetype=obj -o - | llvm-readelf --hex-dump=.ARM.attributes - | FileCheck %s --check-prefix=ELF
+
+; ASM: .text
+; ASM-NEXT:      .aeabi_subsection	aeabi_feature_and_bits, optional, uleb128
+; ASM-NEXT: .aeabi_attribute	Tag_Feature_BTI, 0
+; ASM-NEXT: .aeabi_attribute	Tag_Feature_PAC, 0
+; ASM-NEXT: .aeabi_attribute	Tag_Feature_GCS, 1
+
+; ELF: Hex dump of section '.ARM.attributes':
+; ELF-NEXT: 0x00000000 41230000 00616561 62695f66 65617475 A#...aeabi_featu
+; ELF-NEXT: 0x00000010 72655f61 6e645f62 69747300 01000000 re_and_bits.....
+; ELF-NEXT: 0x00000020 01000201
+
+
+target triple = "aarch64-unknown-none-elf"
+
+!llvm.module.flags = !{!1}
+
+!1 = !{i32 8, !"guarded-control-stack", i32 1}

diff  --git a/llvm/test/CodeGen/AArch64/aarch64-build-attributes-pac.ll b/llvm/test/CodeGen/AArch64/aarch64-build-attributes-pac.ll
new file mode 100644
index 00000000000000..54ff12655eb23f
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/aarch64-build-attributes-pac.ll
@@ -0,0 +1,20 @@
+; RUN: llc < %s | FileCheck %s --check-prefix=ASM
+; RUN: llc %s -filetype=obj -o - | llvm-readelf --hex-dump=.ARM.attributes - | FileCheck %s --check-prefix=ELF
+
+; ASM: .text
+; ASM-NEXT:      .aeabi_subsection	aeabi_feature_and_bits, optional, uleb128
+; ASM-NEXT: .aeabi_attribute	Tag_Feature_BTI, 0
+; ASM-NEXT: .aeabi_attribute	Tag_Feature_PAC, 1
+; ASM-NEXT: .aeabi_attribute	Tag_Feature_GCS, 0
+
+; ELF: Hex dump of section '.ARM.attributes':
+; ELF-NEXT: 0x00000000 41230000 00616561 62695f66 65617475 A#...aeabi_featu
+; ELF-NEXT: 0x00000010 72655f61 6e645f62 69747300 01000000 re_and_bits.....
+; ELF-NEXT: 0x00000020 01010200
+
+
+target triple = "aarch64-unknown-none-elf"
+
+!llvm.module.flags = !{!1}
+
+!1 = !{i32 8, !"sign-return-address", i32 1}

diff  --git a/llvm/test/CodeGen/AArch64/aarch64-build-attributes-pauthabi.ll b/llvm/test/CodeGen/AArch64/aarch64-build-attributes-pauthabi.ll
new file mode 100644
index 00000000000000..7e41167e8fff57
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/aarch64-build-attributes-pauthabi.ll
@@ -0,0 +1,19 @@
+; RUN: llc < %s | FileCheck %s --check-prefix=ASM
+; RUN: llc %s -filetype=obj -o - | llvm-readelf --hex-dump=.ARM.attributes - | FileCheck %s --check-prefix=ELF
+
+; ASM: .text
+; ASM-NEXT: .aeabi_subsection	aeabi_pauthabi, required, uleb128
+; ASM-NEXT: .aeabi_attribute	Tag_PAuth_Platform, 2
+; ASM-NEXT: .aeabi_attribute	Tag_PAuth_Schema, 31
+
+; ELF: Hex dump of section '.ARM.attributes':
+; ELF-NEXT: 0x00000000 41190000 00616561 62695f70 61757468 A....aeabi_pauth
+; ELF-NEXT: 0x00000010 61626900 00000102 021f
+
+
+target triple = "aarch64-unknown-none-elf"
+
+!llvm.module.flags = !{!1, !2}
+
+!1 = !{i32 1, !"aarch64-elf-pauthabi-platform", i32 2}
+!2 = !{i32 1, !"aarch64-elf-pauthabi-version", i32 31}

diff  --git a/llvm/test/MC/AArch64/aarch64-build-attributes-asm-all.s b/llvm/test/MC/AArch64/aarch64-build-attributes-asm-all.s
new file mode 100644
index 00000000000000..a895821f3b05d1
--- /dev/null
+++ b/llvm/test/MC/AArch64/aarch64-build-attributes-asm-all.s
@@ -0,0 +1,27 @@
+// RUN: llvm-mc -triple=aarch64 %s -o - | FileCheck %s --check-prefix=ASM
+// RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o - | llvm-readelf --hex-dump=.ARM.attributes - | FileCheck %s --check-prefix=ELF
+
+// ASM: .text
+// ASM: .aeabi_subsection aeabi_pauthabi, required, uleb128
+// ASM: .aeabi_attribute Tag_PAuth_Platform, 1
+// ASM: .aeabi_attribute Tag_PAuth_Schema, 1
+// ASM: .aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+// ASM: .aeabi_attribute Tag_Feature_BTI, 1
+// ASM: .aeabi_attribute Tag_Feature_PAC, 1
+// ASM: .aeabi_attribute Tag_Feature_GCS, 1
+
+// ELF: Hex dump of section '.ARM.attributes':
+// ELF-NEXT: 0x00000000 41190000 00616561 62695f70 61757468 A....aeabi_pauth
+// ELF-NEXT: 0x00000010 61626900 00000101 02012300 00006165 abi.......#...ae
+// ELF-NEXT: 0x00000020 6162695f 66656174 7572655f 616e645f abi_feature_and_
+// ELF-NEXT: 0x00000030 62697473 00010000 01010102 01
+
+
+.text
+.aeabi_subsection aeabi_pauthabi, required, uleb128
+.aeabi_attribute Tag_PAuth_Platform, 1
+.aeabi_attribute Tag_PAuth_Schema, 1
+.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+.aeabi_attribute Tag_Feature_BTI, 1
+.aeabi_attribute Tag_Feature_PAC, 1
+.aeabi_attribute Tag_Feature_GCS, 1

diff  --git a/llvm/test/MC/AArch64/aarch64-build-attributes-asm-bti.s b/llvm/test/MC/AArch64/aarch64-build-attributes-asm-bti.s
new file mode 100644
index 00000000000000..25573a0cabeca6
--- /dev/null
+++ b/llvm/test/MC/AArch64/aarch64-build-attributes-asm-bti.s
@@ -0,0 +1,19 @@
+// RUN: llvm-mc -triple=aarch64 %s -o - | FileCheck %s --check-prefix=ASM
+// RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o - | llvm-readelf --hex-dump=.ARM.attributes - | FileCheck %s --check-prefix=ELF
+
+// ASM: .aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+// ASM: .aeabi_attribute Tag_Feature_BTI, 1
+// ASM: .aeabi_attribute Tag_Feature_PAC, 0
+// ASM: .aeabi_attribute Tag_Feature_GCS, 0
+
+// ELF: Hex dump of section '.ARM.attributes':
+// ELF-NEXT: 0x00000000 41230000 00616561 62695f66 65617475 A#...aeabi_featu
+// ELF-NEXT: 0x00000010 72655f61 6e645f62 69747300 01000001 re_and_bits.....
+// ELF-NEXT: 0x00000020 01000200
+
+
+.text
+.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+.aeabi_attribute Tag_Feature_BTI, 1
+.aeabi_attribute Tag_Feature_PAC, 0
+.aeabi_attribute Tag_Feature_GCS, 0

diff  --git a/llvm/test/MC/AArch64/aarch64-build-attributes-asm-err-attrs.s b/llvm/test/MC/AArch64/aarch64-build-attributes-asm-err-attrs.s
new file mode 100644
index 00000000000000..e8daec0525591f
--- /dev/null
+++ b/llvm/test/MC/AArch64/aarch64-build-attributes-asm-err-attrs.s
@@ -0,0 +1,70 @@
+// RUN: not llvm-mc -triple=aarch64 %s 2>&1 | FileCheck --check-prefix=ERR %s
+
+.aeabi_attribute Tag_Feature_BTI, 1
+// ERR: error: no active subsection, build attribute can not be added
+// ERR-NEXT: .aeabi_attribute Tag_Feature_BTI, 1
+
+.aeabi_subsection aeabi_pauthabi, required, uleb128
+.aeabi_attribute Tag_Feature_BTI, 1
+// ERR: error: unknown AArch64 build attribute 'Tag_Feature_BTI' for subsection 'aeabi_pauthabi'
+// ERR-NEXT: .aeabi_attribute Tag_Feature_BTI, 1
+
+.aeabi_attribute Tag_PAuth_Platform, 4
+// ERR: error: unknown AArch64 build attributes Value for Tag 'Tag_PAuth_Platform' options are 0|1
+// ERR-NEXT: .aeabi_attribute Tag_PAuth_Platform, 4
+
+.aeabi_attribute a, 1
+// ERR: error: unknown AArch64 build attribute 'a' for subsection 'aeabi_pauthabi'
+// ERR-NEXT: .aeabi_attribute a, 1
+
+.aeabi_attribute Tag_PAuth_Platform, Tag_PAuth_Platform
+// ERR: error: active subsection type is ULEB128 (unsigned), found NTBS (string)
+// ERR-NEXT: .aeabi_attribute Tag_PAuth_Platform, Tag_PAuth_Platform
+
+.aeabi_attribute Tag_PAuth_Platform, a
+// ERR: error: active subsection type is ULEB128 (unsigned), found NTBS (string)
+// ERR-NEXT: .aeabi_attribute Tag_PAuth_Platform, a
+
+.aeabi_attribute Tag_PAuth_Platform,
+// ERR: error: AArch64 build attributes value not found
+// ERR-NEXT: .aeabi_attribute Tag_PAuth_Platform,
+
+.aeabi_attribute Tag_PAuth_Platform
+// ERR: error: expected comma
+// ERR-NEXT: .aeabi_attribute Tag_PAuth_Platform
+
+.aeabi_attribute
+// ERR: error: AArch64 build attributes tag not found
+// ERR-NEXT: .aeabi_attribute
+
+.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+.aeabi_attribute Tag_PAuth_Platform, 1
+// ERR: unknown AArch64 build attribute 'Tag_PAuth_Platform' for subsection 'aeabi_feature_and_bits'
+
+.aeabi_attribute a, 1
+// ERR: error: unknown AArch64 build attribute 'a' for subsection 'aeabi_feature_and_bits'
+
+.aeabi_attribute Tag_Feature_BTI, Tag_Feature_BTI
+// ERR: error: active subsection type is ULEB128 (unsigned), found NTBS (string)
+// ERR-NEXT: .aeabi_attribute Tag_Feature_BTI, Tag_Feature_BTI
+
+.aeabi_attribute Tag_Feature_BTI, a
+// ERR: error: active subsection type is ULEB128 (unsigned), found NTBS (string)
+// ERR-NEXT: .aeabi_attribute Tag_Feature_BTI, a
+
+.aeabi_attribute Tag_Feature_BTI,
+// ERR: error: AArch64 build attributes value not found
+// ERR-NEXT: .aeabi_attribute Tag_Feature_BTI,
+
+.aeabi_attribute Tag_Feature_BTI
+// ERR: error: expected comma
+// ERR-NEXT: .aeabi_attribute Tag_Feature_BTI
+
+.aeabi_attribute
+// ERR: error: AArch64 build attributes tag not found
+// ERR-NEXT: .aeabi_attribute
+
+.aeabi_subsection aeabi_pauthabi, required, uleb128
+.aeabi_attribute Tag_PAuth_Platform, 1 some_text
+// ERR: error: unexpected token for AArch64 build attributes tag and value attribute directive
+// ERR-NEXT: .aeabi_attribute Tag_PAuth_Platform, 1 some_text
\ No newline at end of file

diff  --git a/llvm/test/MC/AArch64/aarch64-build-attributes-asm-err-headers.s b/llvm/test/MC/AArch64/aarch64-build-attributes-asm-err-headers.s
new file mode 100644
index 00000000000000..9e6dca341e9f86
--- /dev/null
+++ b/llvm/test/MC/AArch64/aarch64-build-attributes-asm-err-headers.s
@@ -0,0 +1,61 @@
+// RUN: not llvm-mc -triple=aarch64 %s 2>&1 | FileCheck --check-prefix=ERR %s
+
+.aeabi_subsection aeabi_pauthabi, optional, uleb128
+// ERR: error: aeabi_pauthabi must be marked as required
+// ERR-NEXT: .aeabi_subsection aeabi_pauthabi, optional, uleb128
+
+.aeabi_subsection aeabi_pauthabi, required, ntbs
+// ERR: error: aeabi_pauthabi must be marked as ULEB128
+// ERR-NEXT: .aeabi_subsection aeabi_pauthabi, required, ntbs
+
+.aeabi_subsection aeabi_feature_and_bits, required, uleb128
+// ERR: error: aeabi_feature_and_bits must be marked as optional
+// ERR-NEXT: .aeabi_subsection aeabi_feature_and_bits, required, uleb128
+
+.aeabi_subsection aeabi_feature_and_bits, optional, ntbs
+// ERR: error: aeabi_feature_and_bits must be marked as ULEB128
+// ERR-NEXT: .aeabi_subsection aeabi_feature_and_bits, optional, ntbs
+
+.aeabi_subsection 1, required, uleb128
+// ERR: error: subsection name not found
+// ERR-NEXT: .aeabi_subsection 1, required, uleb128
+
+.aeabi_subsection , required, uleb128
+// ERR: error: subsection name not found
+// ERR-NEXT: .aeabi_subsection , required, uleb128
+
+.aeabi_subsection aeabi_pauthabi, a, uleb128
+// ERR: error: unknown AArch64 build attributes optionality, expected required|optional: a
+// ERR-NEXT: .aeabi_subsection aeabi_pauthabi, a, uleb128
+
+.aeabi_subsection aeabi_pauthabi, a, uleb128
+// ERR: error: unknown AArch64 build attributes optionality, expected required|optional: a
+// ERR-NEXT: .aeabi_subsection aeabi_pauthabi, a, uleb128
+
+.aeabi_subsection aeabi_pauthabi, 1, uleb128
+// ERR: error: optionality parameter not found, expected required|optional
+// ERR-NEXT: .aeabi_subsection aeabi_pauthabi, 1, uleb128
+
+.aeabi_subsection aeabi_pauthabi, ,uleb128
+// ERR: error: optionality parameter not found, expected required|optional
+// ERR-NEXT: .aeabi_subsection aeabi_pauthabi, ,uleb128
+
+.aeabi_subsection aeabi_pauthabi,uleb128
+// ERR: error: unknown AArch64 build attributes optionality, expected required|optional: uleb128
+// ERR-NEXT: .aeabi_subsection aeabi_pauthabi,uleb128
+
+.aeabi_subsection aeabi_pauthabi uleb128
+// ERR: expected comma
+// ERR-NEXT: .aeabi_subsection aeabi_pauthabi uleb128
+
+.aeabi_subsection aeabi_pauthabi, required
+// ERR: error: expected comma
+// ERR-NEXT: .aeabi_subsection aeabi_pauthabi, required
+
+.aeabi_subsection aeabi_pauthabi, required,
+// ERR: error: type parameter not found, expected uleb128|ntbs
+// ERR-NEXT: .aeabi_subsection aeabi_pauthabi, required,
+
+.aeabi_subsection aeabi_pauthabi, required, a
+// ERR: error: unknown AArch64 build attributes type, expected uleb128|ntbs: a
+// ERR-NEXT: .aeabi_subsection aeabi_pauthabi, required, a

diff  --git a/llvm/test/MC/AArch64/aarch64-build-attributes-asm-gcs.s b/llvm/test/MC/AArch64/aarch64-build-attributes-asm-gcs.s
new file mode 100644
index 00000000000000..62789c514dc332
--- /dev/null
+++ b/llvm/test/MC/AArch64/aarch64-build-attributes-asm-gcs.s
@@ -0,0 +1,19 @@
+// RUN: llvm-mc -triple=aarch64 %s -o - | FileCheck %s --check-prefix=ASM
+// RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o - | llvm-readelf --hex-dump=.ARM.attributes - | FileCheck %s --check-prefix=ELF
+
+// ASM: .aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+// ASM: .aeabi_attribute Tag_Feature_BTI, 0
+// ASM: .aeabi_attribute Tag_Feature_PAC, 0
+// ASM: .aeabi_attribute Tag_Feature_GCS, 1
+
+// ELF: Hex dump of section '.ARM.attributes':
+// ELF-NEXT: 0x00000000 41230000 00616561 62695f66 65617475 A#...aeabi_featu
+// ELF-NEXT: 0x00000010 72655f61 6e645f62 69747300 01000000 re_and_bits.....
+// ELF-NEXT: 0x00000020 01000201
+
+
+.text
+.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+.aeabi_attribute Tag_Feature_BTI, 0
+.aeabi_attribute Tag_Feature_PAC, 0
+.aeabi_attribute Tag_Feature_GCS, 1
\ No newline at end of file

diff  --git a/llvm/test/MC/AArch64/aarch64-build-attributes-asm-none.s b/llvm/test/MC/AArch64/aarch64-build-attributes-asm-none.s
new file mode 100644
index 00000000000000..07c89670373de8
--- /dev/null
+++ b/llvm/test/MC/AArch64/aarch64-build-attributes-asm-none.s
@@ -0,0 +1,27 @@
+// RUN: llvm-mc -triple=aarch64 %s -o - | FileCheck %s --check-prefix=ASM
+// RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o - | llvm-readelf --hex-dump=.ARM.attributes - | FileCheck %s --check-prefix=ELF
+
+// ASM: .text
+// ASM: .aeabi_subsection aeabi_pauthabi, required, uleb128
+// ASM: .aeabi_attribute Tag_PAuth_Platform, 0
+// ASM: .aeabi_attribute Tag_PAuth_Schema, 0
+// ASM: .aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+// ASM: .aeabi_attribute Tag_Feature_BTI, 0
+// ASM: .aeabi_attribute Tag_Feature_PAC, 0
+// ASM: .aeabi_attribute Tag_Feature_GCS, 0
+
+// ELF: Hex dump of section '.ARM.attributes':
+// ELF-NEXT: 0x00000000 41190000 00616561 62695f70 61757468 A....aeabi_pauth
+// ELF-NEXT: 0x00000010 61626900 00000100 02002300 00006165 abi.......#...ae
+// ELF-NEXT: 0x00000020 6162695f 66656174 7572655f 616e645f abi_feature_and_
+// ELF-NEXT: 0x00000030 62697473 00010000 00010002 00
+
+
+.text
+.aeabi_subsection aeabi_pauthabi, required, uleb128
+.aeabi_attribute Tag_PAuth_Platform, 0
+.aeabi_attribute Tag_PAuth_Schema, 0
+.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+.aeabi_attribute Tag_Feature_BTI, 0
+.aeabi_attribute Tag_Feature_PAC, 0
+.aeabi_attribute Tag_Feature_GCS, 0
\ No newline at end of file

diff  --git a/llvm/test/MC/AArch64/aarch64-build-attributes-asm-numerical-tags.s b/llvm/test/MC/AArch64/aarch64-build-attributes-asm-numerical-tags.s
new file mode 100644
index 00000000000000..2cdae778df5de5
--- /dev/null
+++ b/llvm/test/MC/AArch64/aarch64-build-attributes-asm-numerical-tags.s
@@ -0,0 +1,41 @@
+// RUN: llvm-mc -triple=aarch64 %s -o - | FileCheck %s --check-prefix=ASM
+
+// ASM: .text
+// ASM: .aeabi_subsection	aeabi_pauthabi, required, uleb128
+// ASM: .aeabi_attribute	0, 1
+// ASM: .aeabi_attribute	Tag_PAuth_Platform, 1
+// ASM: .aeabi_attribute	Tag_PAuth_Schema, 1
+// ASM: .aeabi_attribute	3, 1
+// ASM: .aeabi_attribute	4, 1
+// ASM: .aeabi_attribute	5, 1
+// ASM: .aeabi_subsection	aeabi_feature_and_bits, optional, uleb128
+// ASM: .aeabi_attribute	Tag_Feature_BTI, 1
+// ASM: .aeabi_attribute	Tag_Feature_PAC, 1
+// ASM: .aeabi_attribute	Tag_Feature_GCS, 1
+// ASM: .aeabi_attribute	3, 1
+// ASM: .aeabi_attribute	4, 1
+// ASM: .aeabi_attribute	5, 1
+
+// ELF: Hex dump of section '.ARM.attributes':
+// ELF-NEXT: 0x00000000 41210000 00616561 62695f70 61757468 A!...aeabi_pauth
+// ELF-NEXT: 0x00000010 61626900 00000001 01010201 03010401 abi.............
+// ELF-NEXT: 0x00000020 05012900 00006165 6162695f 66656174 ..)...aeabi_feat
+// ELF-NEXT: 0x00000030 7572655f 616e645f 62697473 00010000 ure_and_bits....
+// ELF-NEXT: 0x00000040 01010102 01030104 010501
+
+
+.text
+.aeabi_subsection aeabi_pauthabi, required, uleb128
+.aeabi_attribute	0, 1
+.aeabi_attribute	1, 1
+.aeabi_attribute	2, 1
+.aeabi_attribute	3, 1
+.aeabi_attribute	4, 1
+.aeabi_attribute	5, 1
+.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+.aeabi_attribute	0, 1
+.aeabi_attribute	1, 1
+.aeabi_attribute	2, 1
+.aeabi_attribute	3, 1
+.aeabi_attribute	4, 1
+.aeabi_attribute	5, 1
\ No newline at end of file

diff  --git a/llvm/test/MC/AArch64/aarch64-build-attributes-asm-out-of-order.s b/llvm/test/MC/AArch64/aarch64-build-attributes-asm-out-of-order.s
new file mode 100644
index 00000000000000..08ea2173ab86ce
--- /dev/null
+++ b/llvm/test/MC/AArch64/aarch64-build-attributes-asm-out-of-order.s
@@ -0,0 +1,50 @@
+// RUN: llvm-mc -triple=aarch64 %s -o - | FileCheck %s --check-prefix=ASM
+// RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o - | llvm-readelf --hex-dump=.ARM.attributes - | FileCheck %s --check-prefix=ELF
+
+// ASM: .text
+// ASM: .aeabi_subsection	aeabi_pauthabi, required, uleb128
+// ASM: .aeabi_subsection	aeabi_feature_and_bits, optional, uleb128
+// ASM: .aeabi_attribute	Tag_Feature_BTI, 1
+// ASM: .aeabi_subsection	aeabi_feature_and_bits, optional, uleb128
+// ASM: .aeabi_subsection	aeabi_pauthabi, required, uleb128
+// ASM: .aeabi_attribute	Tag_PAuth_Schema, 1
+// ASM: .aeabi_subsection	aeabi_pauthabi, required, uleb128
+// ASM: .aeabi_attribute	Tag_PAuth_Platform, 1
+// ASM: .aeabi_subsection	aeabi_pauthabi, required, uleb128
+// ASM: .aeabi_subsection	aeabi_feature_and_bits, optional, uleb128
+// ASM: .aeabi_attribute	Tag_Feature_GCS, 1
+// ASM: .aeabi_subsection	aeabi_pauthabi, required, uleb128
+// ASM: .aeabi_subsection	aeabi_feature_and_bits, optional, uleb128
+// ASM: .aeabi_attribute	Tag_Feature_PAC, 0
+// ASM: .aeabi_subsection	aeabi_feature_and_bits, optional, uleb128
+// ASM: .aeabi_attribute	7, 1
+// ASM: .aeabi_subsection	aeabi_pauthabi, required, uleb128
+// ASM: .aeabi_attribute	7, 0
+
+// ELF: Hex dump of section '.ARM.attributes':
+// ELF-NEXT: 0x00000000 411b0000 00616561 62695f70 61757468 A....aeabi_pauth
+// ELF-NEXT: 0x00000010 61626900 00000201 01010700 25000000 abi.........%...
+// ELF-NEXT: 0x00000020 61656162 695f6665 61747572 655f616e aeabi_feature_an
+// ELF-NEXT: 0x00000030 645f6269 74730001 00000102 01010007 d_bits..........
+// ELF-NEXT: 0x00000040 01
+
+
+.text
+.aeabi_subsection aeabi_pauthabi, required, uleb128
+.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+.aeabi_attribute Tag_Feature_BTI, 1
+.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+.aeabi_subsection aeabi_pauthabi, required, uleb128
+.aeabi_attribute Tag_PAuth_Schema, 1
+.aeabi_subsection aeabi_pauthabi, required, uleb128
+.aeabi_attribute Tag_PAuth_Platform, 1
+.aeabi_subsection aeabi_pauthabi, required, uleb128
+.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+.aeabi_attribute Tag_Feature_GCS, 1
+.aeabi_subsection aeabi_pauthabi, required, uleb128
+.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+.aeabi_attribute Tag_Feature_PAC, 0
+.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+.aeabi_attribute 7, 1
+.aeabi_subsection aeabi_pauthabi, required, uleb128
+.aeabi_attribute 7, 0
\ No newline at end of file

diff  --git a/llvm/test/MC/AArch64/aarch64-build-attributes-asm-pac.s b/llvm/test/MC/AArch64/aarch64-build-attributes-asm-pac.s
new file mode 100644
index 00000000000000..483cae0e09cc7c
--- /dev/null
+++ b/llvm/test/MC/AArch64/aarch64-build-attributes-asm-pac.s
@@ -0,0 +1,19 @@
+// RUN: llvm-mc -triple=aarch64 %s -o - | FileCheck %s --check-prefix=ASM
+// RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o - | llvm-readelf --hex-dump=.ARM.attributes - | FileCheck %s --check-prefix=ELF
+
+// ASM: .aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+// ASM: .aeabi_attribute Tag_Feature_BTI, 0
+// ASM: .aeabi_attribute Tag_Feature_PAC, 1
+// ASM: .aeabi_attribute Tag_Feature_GCS, 0
+
+// ELF: Hex dump of section '.ARM.attributes':
+// ELF-NEXT: 0x00000000 41230000 00616561 62695f66 65617475 A#...aeabi_featu
+// ELF-NEXT: 0x00000010 72655f61 6e645f62 69747300 01000000 re_and_bits.....
+// ELF-NEXT: 0x00000020 01010200
+
+
+.text
+.aeabi_subsection aeabi_feature_and_bits, optional, uleb128
+.aeabi_attribute Tag_Feature_BTI, 0
+.aeabi_attribute Tag_Feature_PAC, 1
+.aeabi_attribute Tag_Feature_GCS, 0

diff  --git a/llvm/test/MC/AArch64/aarch64-build-attributes-asm-private-subsections-err.s b/llvm/test/MC/AArch64/aarch64-build-attributes-asm-private-subsections-err.s
new file mode 100644
index 00000000000000..2b4cbcc721acd4
--- /dev/null
+++ b/llvm/test/MC/AArch64/aarch64-build-attributes-asm-private-subsections-err.s
@@ -0,0 +1,28 @@
+// RUN: not llvm-mc -triple=aarch64 %s 2>&1 | FileCheck --check-prefix=ERR %s
+
+.aeabi_subsection private_subsection, optional, uleb128
+
+.aeabi_subsection private_subsection, required, uleb128
+// ERR: error: optionality mismatch! subsection 'private_subsection' already exists with optionality defined as 'optional' and not 'required'
+// ERR-NEXT: .aeabi_subsection private_subsection, required, uleb128
+
+.aeabi_subsection private_subsection, optional, ntbs
+// ERR: error: type mismatch! subsection 'private_subsection' already exists with type defined as 'uleb128' and not 'ntbs'
+// ERR-NEXT: .aeabi_subsection private_subsection, optional, ntbs
+
+.aeabi_subsection private_subsection_1, optional, ntbs
+.aeabi_attribute 324, 1
+// ERR: error: active subsection type is NTBS (string), found ULEB128 (unsigned)
+// ERR-NEXT: .aeabi_attribute 324, 1
+
+.aeabi_subsection foo, optional, uleb128
+.aeabi_subsection bar, optional, uleb128
+.aeabi_subsection foo, required, uleb128
+// ERR: error: optionality mismatch! subsection 'foo' already exists with optionality defined as 'optional' and not 'required'
+// ERR-NEXT: .aeabi_subsection foo, required, uleb128
+
+.aeabi_subsection goo, optional, ntbs
+.aeabi_subsection zar, optional, ntbs
+.aeabi_subsection goo, optional, uleb128
+// ERR: error: type mismatch! subsection 'goo' already exists with type defined as 'ntbs' and not 'uleb128'
+// ERR-NEXT: .aeabi_subsection goo, optional, uleb128
\ No newline at end of file

diff  --git a/llvm/test/MC/AArch64/aarch64-build-attributes-asm-private-subsections.s b/llvm/test/MC/AArch64/aarch64-build-attributes-asm-private-subsections.s
new file mode 100644
index 00000000000000..229033a9f6b70d
--- /dev/null
+++ b/llvm/test/MC/AArch64/aarch64-build-attributes-asm-private-subsections.s
@@ -0,0 +1,51 @@
+// RUN: llvm-mc -triple=aarch64 %s -o - | FileCheck %s --check-prefix=ASM
+// RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o - | llvm-readelf --hex-dump=.ARM.attributes - | FileCheck %s --check-prefix=ELF
+
+// ASM: .aeabi_subsection	private_subsection_1, optional, uleb128
+// ASM: .aeabi_attribute 12, 257
+// ASM: .aeabi_subsection	private_subsection_2, required, uleb128
+// ASM: .aeabi_attribute 76, 257
+// ASM: .aeabi_subsection	private_subsection_3, optional, ntbs
+// ASM: .aeabi_attribute 34, hello_llvm
+// ASM: .aeabi_subsection	private_subsection_4, required, ntbs
+// ASM: .aeabi_attribute 777, "hello_llvm"
+// ASM: .aeabi_subsection	private_subsection_1, optional, uleb128
+// ASM: .aeabi_attribute 876, 257
+// ASM: .aeabi_subsection	private_subsection_2, required, uleb128
+// ASM: .aeabi_attribute 876, 257
+// ASM: .aeabi_subsection private_subsection_3, optional, ntbs
+// ASM: .aeabi_attribute 876, "hello_llvm"
+// ASM: .aeabi_subsection	private_subsection_4, required, ntbs
+// ASM: .aeabi_attribute 876, hello_llvm
+
+// ELF: Hex dump of section '.ARM.attributes':
+// ELF-NEXT: 0x00000000 41220000 00707269 76617465 5f737562 A"...private_sub
+// ELF-NEXT: 0x00000010 73656374 696f6e5f 31000100 0c8102ec section_1.......
+// ELF-NEXT: 0x00000020 06810222 00000070 72697661 74655f73 ..."...private_s
+// ELF-NEXT: 0x00000030 75627365 6374696f 6e5f3200 00004c81 ubsection_2...L.
+// ELF-NEXT: 0x00000040 02ec0681 02360000 00707269 76617465 .....6...private
+// ELF-NEXT: 0x00000050 5f737562 73656374 696f6e5f 33000101 _subsection_3...
+// ELF-NEXT: 0x00000060 2268656c 6c6f5f6c 6c766d00 ec062268 "hello_llvm..."h
+// ELF-NEXT: 0x00000070 656c6c6f 5f6c6c76 6d220037 00000070 ello_llvm".7...p
+// ELF-NEXT: 0x00000080 72697661 74655f73 75627365 6374696f rivate_subsectio
+// ELF-NEXT: 0x00000090 6e5f3400 00018906 2268656c 6c6f5f6c n_4....."hello_l
+// ELF-NEXT: 0x000000a0 6c766d22 00ec0668 656c6c6f 5f6c6c76 lvm"...hello_llv
+// ELF-NEXT: 0x000000b0 6d00                                m.
+
+
+.aeabi_subsection private_subsection_1, optional, uleb128
+.aeabi_attribute 12, 257
+.aeabi_subsection private_subsection_2, required, uleb128
+.aeabi_attribute 76, 257
+.aeabi_subsection private_subsection_3, optional, ntbs
+.aeabi_attribute 34, hello_llvm
+.aeabi_subsection private_subsection_4, required, ntbs
+.aeabi_attribute 777, "hello_llvm"
+.aeabi_subsection private_subsection_1, optional, uleb128
+.aeabi_attribute 876, 257
+.aeabi_subsection private_subsection_2, required, uleb128
+.aeabi_attribute 876, 257
+.aeabi_subsection private_subsection_3, optional, ntbs
+.aeabi_attribute 876, "hello_llvm"
+.aeabi_subsection private_subsection_4, required, ntbs
+.aeabi_attribute 876, hello_llvm

diff  --git a/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn
index d152aec19d1b58..008715a0b3dea5 100644
--- a/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn
+++ b/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn
@@ -33,6 +33,7 @@ static_library("Support") {
     "Windows",
   ]
   sources = [
+    "AArch64BuildAttributes.cpp"
     "ABIBreak.cpp",
     "AMDGPUMetadata.cpp",
     "APFixedPoint.cpp",
@@ -41,6 +42,7 @@ static_library("Support") {
     "APSInt.cpp",
     "ARMAttributeParser.cpp",
     "ARMBuildAttrs.cpp",
+    "AArch64BuildAttributes.cpp",
     "ARMWinEH.cpp",
     "Allocator.cpp",
     "AutoConvert.cpp",


        


More information about the llvm-commits mailing list