[BFD,LD,AArch64,1/4] Add support for GNU PROPERTIES in AArch64 for BTI and PAC

Message ID 935ee242-d6e0-63f2-f369-4a264fe15d99@arm.com
State New
Headers show
Series
  • Add support for AArch64 BTI and PAC in the linker
Related show

Commit Message

Sudakshina Das March 6, 2019, 10:30 a.m.
Hi

On 06/03/2019 10:26, Sudakshina Das wrote:
> Hi

> 

> This patch series is aimed at giving support for the new Armv8.3-A 

> Pointer Authentication and Armv8.5-A Branch Target Identification 

> feature in the linker.

> 

> In order to support these, we propose to make the following changes:

> 1) We have defined .note.gnu.property for AArch64.

> 2) We have defined a new Program Property type

> GNU_PROPERTY_AARCH64_FEATURE_1_AND and used 2 bits to represent

> BTI and PAC respectively.

>    - GNU_PROPERTY_AARCH64_FEATURE_1_BTI

>    - GNU_PROPERTY_AARCH64_FEATURE_1_PAC (We have only reserved this bit

>      for now.)

> 3) We also need custom PLTs when these features are turned on and thus

> we have defined the following processor-specific dynamic array tags:

>    - DT_AARCH64_BTI_PLT

>    - DT_AARCH64_PAC_PLT

> Details of these can be found in the new AArch64 ELF documentation:

> https://developer.arm.com/docs/ihi0056/latest/elf-for-the-arm-64-bit-architecture-aarch64-abi-2018q4 

> 

> 

> Command line options:

> We introduce a new set of command line options for the linker in order 

> to support the correct PLTs

> 1) --pac-plt : In the presence of this option, the linker uses a PAC 

> enabled PLT. It also uses the dynamic tag DT_AARCH64_PAC_PLT to reflect 

> the same. Other tools like Objdump can use this to determine the size of 

> the PLTs.

> 2) --bti: In the presence of this option, the linker enables BTI with 

> the GNU_PROPERTY_AARCH64_FEATURE_1_BTI feature and also uses a BTI 

> enabled PLT. It also uses the dynamic tag DT_AARCH64_BTI_PLT to reflect 

> the choice of the PLTs. Other tools like Objdump can use this to 

> determine the size of the PLTs. Using this option can give a warning if 

> not all input objects are marked with GNU_PROPERTY_AARCH64_FEATURE_1_BTI.

> 3)--bti-nowarn - Same as above but does not emit any warnings.

> 

> In terms of the PLTs, in the presence of both --pac-plt and 

> --bti/--bti-nowarn, the linker chooses the PLTs protected with both BTI 

> and PAC and uses both DT_AARCH64_PAC_PLT and DT_AARCH64_BTI_PLT.

> 

> Interaction between Command line arguments and GNU NOTE section

> 1) For PAC, in the presence of --pac-plt along with BIND_NOW, the linker 

> can choose to ignore the pac-plt directive and use smaller PLTs without 

> compromising on security,

> 2) For BTI, the linker must also check for the 

> GNU_PROPERTY_AARCH64_FEATURE_1_BTI in its input. If all inputs have 

> GNU_PROPERTY_AARCH64_FEATURE_1_BTI, the final output will also be marked 

> as such. The PLT should also be protected with a BTI PLT in this case. 

> Thus even if there is no linker option to use BTI PLT, the linker

> should be able to use them depending on the NOTE section. The user can 

> use the linker option --bti, to make sure that their intention of having 

> all input objects (and hence the output) marked with BTI is not 

> disrupted by any stray objects as this option will warn about it.

> 

> 

> The following patches implement these changes as follows:

> [1/4] Add support for GNU PROPERTIES in AArch64 for BTI and PAC:

> [2/4] Add --bti-nowarn to enable BTI without warning and to select BTI 

> enabled PLTs

> [3/4] Add --bti to enable BTI and select BTI enabled PLTs but also warn 

> for missing NOTE sections.

> [4/4] Add --pac-plt to enable PLTs protected with PAC.

> 

> This is my first time making such intrusive changes to the linker. 

> Please be kind :P

> 

> Thanks

> Sudi


This is part of the patch series to add support for BTI and
PAC in AArch64 linker.

This patch implements the following:
1) This extends in the gnu property support in the linker for
AArch64 by defining backend hooks for elf_backend_setup_gnu_properties,
elf_backend_merge_gnu_properties and elf_backend_parse_gnu_properties.
2) It defines AArch64 specific GNU property
GNU_PROPERTY_AARCH64_FEATURE_1_AND and 2 bit for BTI and PAC in it.
3) It also adds support in readelf.c to read and print these new
GNU properties in AArch64.
All these are made according to the new AArch64 ELF ABI
https://developer.arm.com/docs/ihi0056/latest/elf-for-the-arm-64-bit-architecture-aarch64-abi-2018q4

Build and regression tests all pass on aarch64-none-linux-gnu and
new tests are added.

Is this ok for trunk?

Thanks
Sudi

*** bfd/ChangeLog ***

2019-xx-xx  Sudakshina Das  <sudi.das@arm.com>

	* elf-properties.c (_bfd_elf_link_setup_gnu_properties): Exclude
	linker created inputs from merge.
	* elfnn-aarch64.c (struct elf_aarch64_obj_tdata): Add field for
	GNU_PROPERTY_AARCH64_FEATURE_1_AND properties.
	(elfNN_aarch64_link_setup_gnu_properties): New.
	(elfNN_aarch64_merge_gnu_properties): New.
	(elf_backend_setup_gnu_properties): Define for AArch64.
	(elf_backend_merge_gnu_properties): Likewise.
	* elfxx-aarch64.c (_bfd_aarch64_elf_link_setup_gnu_properties): Define.
	(_bfd_aarch64_elf_parse_gnu_properties): Define.
	(_bfd_aarch64_elf_merge_gnu_properties): Define.
	* elfxx-aarch64.h (_bfd_aarch64_elf_link_setup_gnu_properties): Declare.
	(_bfd_aarch64_elf_parse_gnu_properties): Declare.
	(_bfd_aarch64_elf_merge_gnu_properties): Declare.
	(elf_backend_parse_gnu_properties): Define for AArch64.

*** binutils/ChangeLog ***

2019-xx-xx  Sudakshina Das  <sudi.das@arm.com>

	* readelf.c (decode_aarch64_feature_1_and): New.
	(print_gnu_property_note): Add case for AArch64 gnu notes.

*** include/ChangeLog ***

2019-xx-xx  Sudakshina Das  <sudi.das@arm.com>

	* elf/common.h (GNU_PROPERTY_AARCH64_FEATURE_1_AND): New.
	(GNU_PROPERTY_AARCH64_FEATURE_1_BTI): New.
	(GNU_PROPERTY_AARCH64_FEATURE_1_PAC): New.

*** ld/ChangeLog ***

2019-xx-xx  Sudakshina Das  <sudi.das@arm.com>

	* NEWS: Document GNU_PROPERTY_AARCH64_FEATURE_1_BTI and
	GNU_PROPERTY_AARCH64_FEATURE_1_PAC.
	* testsuite/ld-aarch64/aarch64-elf.exp: Add run commands for new tests.
	* testsuite/ld-aarch64/property-bti-pac1.d: New test.
	* testsuite/ld-aarch64/property-bti-pac1.s: New test.
	* testsuite/ld-aarch64/property-bti-pac2.d: New test.
	* testsuite/ld-aarch64/property-bti-pac2.s: New test.
	* testsuite/ld-aarch64/property-bti-pac3.d: New test.

Patch

diff --git a/bfd/elf-properties.c b/bfd/elf-properties.c
index 5e48d75faa2694538cbbb74af0a86bfe85da3fd3..0c3f19ce56a36bb18d9afd2e140d735eeaf9c6a9 100644
--- a/bfd/elf-properties.c
+++ b/bfd/elf-properties.c
@@ -555,7 +555,7 @@  _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info)
 
   for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next)
     if (abfd != first_pbfd
-	&& (abfd->flags & (DYNAMIC | BFD_PLUGIN)) == 0)
+	&& (abfd->flags & (DYNAMIC | BFD_PLUGIN | BFD_LINKER_CREATED)) == 0)
       {
 	elf_property_list *null_ptr = NULL;
 	elf_property_list **listp = &null_ptr;
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index faa27611d466ce75e5c02d8bbcfca6459618d4bd..5b8cc4c9701feacd0deb5c998c89d17d97864646 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -2435,6 +2435,9 @@  struct elf_aarch64_obj_tdata
 
   /* Zero to warn when linking objects with incompatible wchar_t sizes.  */
   int no_wchar_size_warning;
+
+  /* All GNU_PROPERTY_AARCH64_FEATURE_1_AND properties.  */
+  uint32_t gnu_and_prop;
 };
 
 #define elf_aarch64_tdata(bfd)				\
@@ -9615,6 +9618,32 @@  elfNN_aarch64_backend_symbol_processing (bfd *abfd, asymbol *sym)
     sym->flags |= BSF_KEEP;
 }
 
+/* Implement elf_backend_setup_gnu_properties for AArch64.  It serves as a
+   wrapper function for _bfd_aarch64_elf_link_setup_gnu_properties to account
+   for the effect of GNU properties of the output_bfd.  */
+static bfd *
+elfNN_aarch64_link_setup_gnu_properties (struct bfd_link_info *info)
+{
+  uint32_t prop = elf_aarch64_tdata (info->output_bfd)->gnu_and_prop;
+  bfd *pbfd = _bfd_aarch64_elf_link_setup_gnu_properties (info, &prop);
+  elf_aarch64_tdata (info->output_bfd)->gnu_and_prop = prop;
+  return pbfd;
+}
+
+/* Implement elf_backend_merge_gnu_properties for AArch64.  It serves as a
+   wrapper function for _bfd_aarch64_elf_merge_gnu_properties to account
+   for the effect of GNU properties of the output_bfd.  */
+static bfd_boolean
+elfNN_aarch64_merge_gnu_properties (struct bfd_link_info *info,
+				       bfd *abfd,
+				       elf_property *aprop,
+				       elf_property *bprop)
+{
+  uint32_t prop
+    = elf_aarch64_tdata (info->output_bfd)->gnu_and_prop;
+  return  _bfd_aarch64_elf_merge_gnu_properties (info, abfd, aprop,
+						 bprop, prop);
+}
 
 /* We use this so we can override certain functions
    (though currently we don't).  */
@@ -9754,6 +9783,12 @@  const struct elf_size_info elfNN_aarch64_size_info =
 #define elf_backend_symbol_processing		\
   elfNN_aarch64_backend_symbol_processing
 
+#define elf_backend_setup_gnu_properties	\
+  elfNN_aarch64_link_setup_gnu_properties
+
+#define elf_backend_merge_gnu_properties	\
+  elfNN_aarch64_merge_gnu_properties
+
 #define elf_backend_can_refcount       1
 #define elf_backend_can_gc_sections    1
 #define elf_backend_plt_readonly       1
diff --git a/bfd/elfxx-aarch64.h b/bfd/elfxx-aarch64.h
index 1f9ce09675f5e21da4ddff5a1e72d75552110c3f..a6d1792687cf39a68beb3235f5875d50bfc3ad4e 100644
--- a/bfd/elfxx-aarch64.h
+++ b/bfd/elfxx-aarch64.h
@@ -55,3 +55,19 @@  _bfd_aarch64_elf_write_core_note (bfd *, char *, int *, int, ...);
 #define elf_backend_grok_prstatus	_bfd_aarch64_elf_grok_prstatus
 #define elf_backend_grok_psinfo		_bfd_aarch64_elf_grok_psinfo
 #define elf_backend_write_core_note	_bfd_aarch64_elf_write_core_note
+
+extern bfd *
+_bfd_aarch64_elf_link_setup_gnu_properties (struct bfd_link_info *,
+					    uint32_t *);
+
+extern enum elf_property_kind
+_bfd_aarch64_elf_parse_gnu_properties (bfd *, unsigned int,
+				       bfd_byte *, unsigned int);
+
+extern bfd_boolean
+_bfd_aarch64_elf_merge_gnu_properties (struct bfd_link_info *, bfd *,
+				       elf_property *, elf_property *,
+				       uint32_t);
+
+#define elf_backend_parse_gnu_properties	\
+  _bfd_aarch64_elf_parse_gnu_properties
diff --git a/bfd/elfxx-aarch64.c b/bfd/elfxx-aarch64.c
index 32a9d972824d653785358f933a1157533f6e9779..cae94d03e8453de0cceee1619668fff71a609edf 100644
--- a/bfd/elfxx-aarch64.c
+++ b/bfd/elfxx-aarch64.c
@@ -683,3 +683,183 @@  _bfd_aarch64_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_ty
       }
     }
 }
+
+/* Find the first input bfd with GNU property and merge it with GPROP.  If no
+   such input is found, add it to a new section at the last input.  Update
+   GPROP accordingly.  */
+bfd *
+_bfd_aarch64_elf_link_setup_gnu_properties (struct bfd_link_info *info,
+					    uint32_t *gprop)
+{
+  asection *sec;
+  bfd *pbfd;
+  bfd *ebfd = NULL;
+  elf_property *prop;
+
+  uint32_t gnu_prop = *gprop;
+
+  /* Find a normal input file with GNU property note.  */
+  for (pbfd = info->input_bfds;
+       pbfd != NULL;
+       pbfd = pbfd->link.next)
+    if (bfd_get_flavour (pbfd) == bfd_target_elf_flavour
+	&& bfd_count_sections (pbfd) != 0)
+      {
+	ebfd = pbfd;
+
+	if (elf_properties (pbfd) != NULL)
+	  break;
+      }
+
+  /* If ebfd != NULL it is either an input with property note or the last
+     input.  Either way if we have gnu_prop, we should add it (by creating
+     a section if needed).  */
+  if (ebfd != NULL && gnu_prop)
+    {
+      prop = _bfd_elf_get_property (ebfd,
+				    GNU_PROPERTY_AARCH64_FEATURE_1_AND,
+				    4);
+      prop->u.number |= gnu_prop;
+      prop->pr_kind = property_number;
+
+      /* pbfd being NULL implies ebfd is the last input.  Create the GNU
+	 property note section.  */
+      if (pbfd == NULL)
+	{
+	  sec = bfd_make_section_with_flags (ebfd,
+					     NOTE_GNU_PROPERTY_SECTION_NAME,
+					     (SEC_ALLOC
+					      | SEC_LOAD
+					      | SEC_IN_MEMORY
+					      | SEC_READONLY
+					      | SEC_HAS_CONTENTS
+					      | SEC_DATA));
+	  if (sec == NULL)
+	    info->callbacks->einfo (
+	      _("%F%P: failed to create GNU property section\n"));
+
+	  elf_section_type (sec) = SHT_NOTE;
+	}
+    }
+
+  pbfd = _bfd_elf_link_setup_gnu_properties (info);
+
+  if (bfd_link_relocatable (info))
+    return pbfd;
+
+  /* If pbfd has any GNU_PROPERTY_AARCH64_FEATURE_1_AND properties, update
+     gnu_prop accordingly.  */
+  if (pbfd != NULL)
+    {
+      elf_property_list *p;
+
+      /* The property list is sorted in order of type.  */
+      for (p = elf_properties (pbfd); p; p = p->next)
+	{
+	  /* Check for all GNU_PROPERTY_AARCH64_FEATURE_1_AND.  */
+	  if (GNU_PROPERTY_AARCH64_FEATURE_1_AND == p->property.pr_type)
+	    {
+	      gnu_prop = (p->property.u.number
+			  & (GNU_PROPERTY_AARCH64_FEATURE_1_PAC
+			      | GNU_PROPERTY_AARCH64_FEATURE_1_BTI));
+	      break;
+	    }
+	  else if (GNU_PROPERTY_AARCH64_FEATURE_1_AND < p->property.pr_type)
+	    break;
+	}
+    }
+  *gprop = gnu_prop;
+  return pbfd;
+}
+
+/* Define elf_backend_parse_gnu_properties for AArch64.  */
+enum elf_property_kind
+_bfd_aarch64_elf_parse_gnu_properties (bfd *abfd, unsigned int type,
+				       bfd_byte *ptr, unsigned int datasz)
+{
+  elf_property *prop;
+
+  switch (type)
+    {
+    case GNU_PROPERTY_AARCH64_FEATURE_1_AND:
+      if (datasz != 4)
+	{
+	  _bfd_error_handler
+	    ( _("error: %pB: <corrupt AArch64 used size: 0x%x>"),
+	     abfd, datasz);
+	  return property_corrupt;
+	}
+      prop = _bfd_elf_get_property (abfd, type, datasz);
+      /* Combine properties of the same type.  */
+      prop->u.number |= bfd_h_get_32 (abfd, ptr);
+      prop->pr_kind = property_number;
+      break;
+
+    default:
+      return property_ignored;
+    }
+
+  return property_number;
+}
+
+/* Merge AArch64 GNU property BPROP with APROP also accounting for PROP.
+   If APROP isn't NULL, merge it with BPROP and/or PROP.  Vice-versa if BROP
+   isn't NULL.  Return TRUE if there is any update to APROP or if BPROP should
+   be merge with ABFD.  */
+bfd_boolean
+_bfd_aarch64_elf_merge_gnu_properties (struct bfd_link_info *info
+				       ATTRIBUTE_UNUSED,
+				       bfd *abfd ATTRIBUTE_UNUSED,
+				       elf_property *aprop,
+				       elf_property *bprop,
+				       uint32_t prop)
+{
+  unsigned int orig_number;
+  bfd_boolean updated = FALSE;
+  unsigned int pr_type = aprop != NULL ? aprop->pr_type : bprop->pr_type;
+
+  switch (pr_type)
+    {
+    case GNU_PROPERTY_AARCH64_FEATURE_1_AND:
+      {
+	if (aprop != NULL && bprop != NULL)
+	  {
+	    orig_number = aprop->u.number;
+	    aprop->u.number = (orig_number & bprop->u.number) | prop;
+	    updated = orig_number != aprop->u.number;
+	    /* Remove the property if all feature bits are cleared.  */
+	    if (aprop->u.number == 0)
+	      aprop->pr_kind = property_remove;
+	    break;
+	  }
+	/* If either is NULL, the AND would be 0 so, if there is
+	   any PROP, asign it to the input that is not NULL.  */
+	if (prop)
+	  {
+	    if (aprop != NULL)
+	      {
+		orig_number = aprop->u.number;
+		aprop->u.number = prop;
+		updated = orig_number != aprop->u.number;
+	      }
+	    else
+	      {
+		bprop->u.number = prop;
+		updated = TRUE;
+	      }
+	  }
+	/* No PROP and BPROP is NULL, so remove APROP.  */
+	else if (aprop != NULL)
+	  {
+	    aprop->pr_kind = property_remove;
+	    updated = TRUE;
+	  }
+      }
+      break;
+
+    default:
+      abort ();
+    }
+
+  return updated;
+}
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 38e9f1b3455c0f92ff53b76630a1bb80ee08c8e2..7446ffeee21961bf56b12ff16afbf52e5cd35387 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -17342,6 +17342,33 @@  decode_x86_feature_2 (unsigned int bitmask)
 }
 
 static void
+decode_aarch64_feature_1_and (unsigned int bitmask)
+{
+  while (bitmask)
+    {
+      unsigned int bit = bitmask & (- bitmask);
+
+      bitmask &= ~ bit;
+      switch (bit)
+	{
+	case GNU_PROPERTY_AARCH64_FEATURE_1_BTI:
+	  printf ("BTI");
+	  break;
+
+	case GNU_PROPERTY_AARCH64_FEATURE_1_PAC:
+	  printf ("PAC");
+	  break;
+
+	default:
+	  printf (_("<unknown: %x>"), bit);
+	  break;
+	}
+      if (bitmask)
+	printf (", ");
+    }
+}
+
+static void
 print_gnu_property_note (Filedata * filedata, Elf_Internal_Note * pnote)
 {
   unsigned char * ptr = (unsigned char *) pnote->descdata;
@@ -17475,6 +17502,18 @@  print_gnu_property_note (Filedata * filedata, Elf_Internal_Note * pnote)
 		  break;
 		}
 	    }
+	  else if (filedata->file_header.e_machine == EM_AARCH64)
+	    {
+	      if (type == GNU_PROPERTY_AARCH64_FEATURE_1_AND)
+		{
+		  printf ("AArch64 feature: ");
+		  if (datasz != 4)
+		    printf (_("<corrupt length: %#x> "), datasz);
+		  else
+		    decode_aarch64_feature_1_and (byte_get (ptr, 4));
+		  goto next;
+		}
+	    }
 	}
       else
 	{
diff --git a/include/elf/common.h b/include/elf/common.h
index e8faf67be3707f60c1f9a178ed4730551238835b..ebdb8212d118ed02132b8f94f26b628c1e1f681d 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -841,6 +841,12 @@ 
 #define GNU_PROPERTY_X86_FEATURE_2_XSAVEOPT	(1U << 8)
 #define GNU_PROPERTY_X86_FEATURE_2_XSAVEC	(1U << 9)
 
+/* AArch64 specific GNU PROPERTY.  */
+#define GNU_PROPERTY_AARCH64_FEATURE_1_AND	0xc0000000
+
+#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI	(1U << 0)
+#define GNU_PROPERTY_AARCH64_FEATURE_1_PAC	(1U << 1)
+
 /* Values used in GNU .note.ABI-tag notes (NT_GNU_ABI_TAG).  */
 #define GNU_ABI_TAG_LINUX	0
 #define GNU_ABI_TAG_HURD	1
diff --git a/ld/NEWS b/ld/NEWS
index d737af70516547ecb4723a7e316493408d920353..dcf11854f528028820cbe1983bbcdd5753d97eaf 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,15 @@ 
 -*- text -*-
 
+Changes in 2.33:
+
+* Add target handlers for AArch64 for ELF GNU program properties.
+
+* Add support for GNU_PROPERTY_AARCH64_FEATURE_1_BTI in ELF GNU program
+  properties in the AArch64 ELF linker.
+
+* Add support for GNU_PROPERTY_AARCH64_FEATURE_1_PAC in ELF GNU program
+  properties in the AArch64 ELF linker.
+
 Changes in 2.32:
 
 * Report property change in linker map file when merging GNU properties.
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index 2b9fad5604b64d44e0fe48aa471bc726d9ce4332..c6fefbbd5c3f7e5516086c7eca0e056ae243d36d 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -371,6 +371,10 @@  run_dump_test_lp64 "rela-abs-relative-opt"
 
 run_dump_test_lp64 "pie-bind-locally"
 
+run_dump_test "property-bti-pac1"
+run_dump_test "property-bti-pac2"
+run_dump_test "property-bti-pac3"
+
 set aarch64elflinktests {
   {"ld-aarch64/so with global symbol" "-shared" "" "" {copy-reloc-so.s}
     {} "copy-reloc-so.so"}
diff --git a/ld/testsuite/ld-aarch64/property-bti-pac1.d b/ld/testsuite/ld-aarch64/property-bti-pac1.d
new file mode 100644
index 0000000000000000000000000000000000000000..a681ad94f885506da7831230a93e26eecb800c8a
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/property-bti-pac1.d
@@ -0,0 +1,11 @@ 
+#name: GNU Property (single input, combine section)
+#source: property-bti-pac1.s
+#as: -march=armv8.5-a -defsym __mult__=0
+#ld: -shared
+#readelf: -n
+#target: *linux*
+
+Displaying notes found in: .note.gnu.property
+  Owner                 Data size	Description
+  GNU                  0x00000010	NT_GNU_PROPERTY_TYPE_0
+      Properties: AArch64 feature: BTI, PAC
diff --git a/ld/testsuite/ld-aarch64/property-bti-pac1.s b/ld/testsuite/ld-aarch64/property-bti-pac1.s
new file mode 100644
index 0000000000000000000000000000000000000000..414c9277f1dabc5fdc08b8b71716c44ea8bc8343
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/property-bti-pac1.s
@@ -0,0 +1,37 @@ 
+	.text
+	.globl _start
+	.type _start,@function
+_start:
+	mov x1, #2
+.ifndef __mult__
+	bl foo
+.endif
+	.section ".note.gnu.property", "a"
+	.p2align 3
+	.long 1f - 0f		/* name length */
+	.long 5f - 2f		/* data length */
+	.long 5			/* note type */
+0:	.asciz "GNU"		/* vendor name */
+1:
+	.p2align 3
+2:	.long 0xc0000000	/* pr_type.  */
+	.long 4f - 3f		/* pr_datasz.  */
+3:
+	.long 0x2		/* PAC.  */
+4:
+	.p2align 3
+5:
+	.p2align 3
+	.long 1f - 0f		/* name length */
+	.long 5f - 2f		/* data length */
+	.long 5			/* note type */
+0:	.asciz "GNU"		/* vendor name */
+1:
+	.p2align 3
+2:	.long 0xc0000000	/* pr_type.  */
+	.long 4f - 3f		/* pr_datasz.  */
+3:
+	.long 0x1		/* BTI.  */
+4:
+	.p2align 3
+5:
diff --git a/ld/testsuite/ld-aarch64/property-bti-pac2.d b/ld/testsuite/ld-aarch64/property-bti-pac2.d
new file mode 100644
index 0000000000000000000000000000000000000000..bc2eaada9ecdb952efd1c9c57d715773ed216852
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/property-bti-pac2.d
@@ -0,0 +1,12 @@ 
+#name: GNU Property (combine multiple with BTI)
+#source: property-bti-pac1.s
+#source: property-bti-pac2.s
+#as: -mabi=lp64 -defsym __property_bti__=1
+#ld: -e _start
+#readelf: -n
+#target: *linux*
+
+Displaying notes found in: .note.gnu.property
+  Owner                 Data size	Description
+  GNU                  0x00000010	NT_GNU_PROPERTY_TYPE_0
+      Properties: AArch64 feature: BTI
diff --git a/ld/testsuite/ld-aarch64/property-bti-pac2.s b/ld/testsuite/ld-aarch64/property-bti-pac2.s
new file mode 100644
index 0000000000000000000000000000000000000000..cdec8d998724e67bcc778bba77eac7bf85c05626
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/property-bti-pac2.s
@@ -0,0 +1,50 @@ 
+	.text
+	.global	foo
+	.type	foo, %function
+foo:
+	sub	sp, sp, #16
+	mov	w0, 9
+	str	w0, [sp, 12]
+	ldr	w0, [sp, 12]
+	add	w0, w0, 4
+	str	w0, [sp, 12]
+	nop
+	add	sp, sp, 16
+	ret
+	.size	foo, .-foo
+	.global	bar
+	.type	bar, %function
+.ifdef __property_bti__
+	.section ".note.gnu.property", "a"
+	.p2align 3
+	.long 1f - 0f		/* name length */
+	.long 5f - 2f		/* data length */
+	.long 5			/* note type */
+0:	.asciz "GNU"		/* vendor name */
+1:
+	.p2align 3
+2:	.long 0xc0000000	/* pr_type.  */
+	.long 4f - 3f		/* pr_datasz.  */
+3:
+	.long 0x1		/* BTI.  */
+4:
+	.p2align 3
+5:
+.endif
+.ifdef __property_pac__
+	.section ".note.gnu.property", "a"
+	.p2align 3
+	.long 1f - 0f		/* name length */
+	.long 5f - 2f		/* data length */
+	.long 5			/* note type */
+0:	.asciz "GNU"		/* vendor name */
+1:
+	.p2align 3
+2:	.long 0xc0000000	/* pr_type.  */
+	.long 4f - 3f		/* pr_datasz.  */
+3:
+	.long 0x2		/* PAC.  */
+4:
+	.p2align 3
+5:
+.endif
diff --git a/ld/testsuite/ld-aarch64/property-bti-pac3.d b/ld/testsuite/ld-aarch64/property-bti-pac3.d
new file mode 100644
index 0000000000000000000000000000000000000000..5290f4bd8110d127e19712ce8891bb54bdfbc352
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/property-bti-pac3.d
@@ -0,0 +1,12 @@ 
+#name: GNU Property (combine multiple with PAC)
+#source: property-bti-pac1.s
+#source: property-bti-pac2.s
+#as: -mabi=lp64 -defsym __property_pac__=1
+#ld: -e _start
+#readelf: -n
+#target: *linux*
+
+Displaying notes found in: .note.gnu.property
+  Owner                 Data size	Description
+  GNU                  0x00000010	NT_GNU_PROPERTY_TYPE_0
+      Properties: AArch64 feature: PAC