aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSudakshina Das <sudi.das@arm.com>2019-03-13 10:54:30 +0000
committerSudakshina Das <sudi.das@arm.com>2019-03-13 11:47:07 +0000
commit37c18eedffe3926a330149ca93e7407917e2be38 (patch)
treebc49f9058988c84c84029fe8b302e102fa4387c6
parentcd702818c6cf25277253b3b5c23f17d2cf7a94df (diff)
downloadgdb-37c18eedffe3926a330149ca93e7407917e2be38.zip
gdb-37c18eedffe3926a330149ca93e7407917e2be38.tar.gz
gdb-37c18eedffe3926a330149ca93e7407917e2be38.tar.bz2
[BFD, LD, AArch64, 2/3] Add --force-bti to enable BTI and to select BTI enabled PLTs
This is part of the patch series to add support for BTI and PAC in AArch64 linker. 1) This patch adds a new ld command line option: --force-bti. In the presence of this option, the linker enables BTI with the GNU_PROPERTY_AARCH64_FEATURE_1_BTI feature. This gives out warning in case of missing gnu notes for BTI in inputs. 2) It also defines a new set of BTI enabled PLTs. These are used either when all the inputs are marked with GNU_PROPERTY_AARCH64_FEATURE_1_BTI or when the new --force-bti option is used. This required adding new fields in elf_aarch64_link_hash_table so that we could make the PLT related information more generic. 3) It also defines a dynamic tag DT_AARCH64_BTI_PLT. The linker uses this whenever it picks BTI enabled PLTs. 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 *** bfd/ChangeLog *** 2019-03-13 Sudakshina Das <sudi.das@arm.com> Szabolcs Nagy <szabolcs.nagy@arm.com> * bfd-in.h (aarch64_plt_type, aarch64_enable_bti_type): New. (aarch64_bti_pac_info): New. (bfd_elf64_aarch64_set_options): Add aarch64_bti_pac_info argument. (bfd_elf32_aarch64_set_options): Likewise. * bfd-in2.h: Regenerate * elfnn-aarch64.c (PLT_BTI_ENTRY_SIZE): New. (PLT_BTI_SMALL_ENTRY_SIZE, PLT_BTI_TLSDESC_ENTRY_SIZE): New. (elfNN_aarch64_small_plt0_bti_entry): New. (elfNN_aarch64_small_plt_bti_entry): New. (elfNN_aarch64_tlsdesc_small_plt_bti_entry): New. (elf_aarch64_obj_tdata): Add no_bti_warn and plt_type fields. (elf_aarch64_link_hash_table): Add plt0_entry, plt_entry and tlsdesc_plt_entry_size fields. (elfNN_aarch64_link_hash_table_create): Initialise the new fields. (setup_plt_values): New helper function. (bfd_elfNN_aarch64_set_options): Use new bp_info to set plt sizes and bti enable type. (elfNN_aarch64_allocate_dynrelocs): Use new size members instead of fixed macros. (elfNN_aarch64_size_dynamic_sections): Likewise and add checks. (elfNN_aarch64_create_small_pltn_entry): Use new generic pointers to plt stubs instead of fixed ones and update filling them according to the need for bti. (elfNN_aarch64_init_small_plt0_entry): Likewise. (elfNN_aarch64_finish_dynamic_sections): Likewise. (get_plt_type, elfNN_aarch64_get_synthetic_symtab): New. (elfNN_aarch64_plt_sym_val): Update size accordingly. (elfNN_aarch64_link_setup_gnu_properties): Set up plts if BTI GNU NOTE is set. (bfd_elfNN_get_synthetic_symtab): Define. (elfNN_aarch64_merge_gnu_properties): Give out warning with --force-bti and mising BTI NOTE SECTION. *** binutils/ChangeLog *** 2019-03-13 Sudakshina Das <sudi.das@arm.com> Szabolcs Nagy <szabolcs.nagy@arm.com> * readelf.c (get_aarch64_dynamic_type): New. (get_dynamic_type): Use above for EM_AARCH64. (dynamic_section_aarch64_val): New. (process_dynamic_section): Use above for EM_AARCH64. *** include/ChangeLog *** 2019-03-13 Sudakshina Das <sudi.das@arm.com> Szabolcs Nagy <szabolcs.nagy@arm.com> * elf/aarch64.h (DT_AARCH64_BTI_PLT): New. *** ld/ChangeLog *** 2019-03-13 Sudakshina Das <sudi.das@arm.com> Szabolcs Nagy <szabolcs.nagy@arm.com> * NEWS: Document --force-bti. * emultempl/aarch64elf.em (plt_type, bti_type, OPTION_FORCE_BTI): New. (PARSE_AND_LIST_SHORTOPTS, PARSE_AND_LIST_OPTIONS): Add force-bti. (PARSE_AND_LIST_ARGS_CASES): Handle OPTION_FORCE_BTI. * testsuite/ld-aarch64/aarch64-elf.exp: Add all the tests below. * testsuite/ld-aarch64/bti-plt-1.d: New test. * testsuite/ld-aarch64/bti-plt-1.s: New test. * testsuite/ld-aarch64/bti-plt-2.s: New test. * testsuite/ld-aarch64/bti-plt-2.d: New test. * testsuite/ld-aarch64/bti-plt-3.d: New test. * testsuite/ld-aarch64/bti-plt-4.d: New test. * testsuite/ld-aarch64/bti-plt-5.d: New test. * testsuite/ld-aarch64/bti-plt-6.d: New test. * testsuite/ld-aarch64/bti-plt-7.d: New test. * testsuite/ld-aarch64/bti-plt-so.s: New test. * testsuite/ld-aarch64/bti-plt.ld: New test.
-rw-r--r--bfd/ChangeLog37
-rw-r--r--bfd/bfd-in.h38
-rw-r--r--bfd/bfd-in2.h38
-rw-r--r--bfd/elfnn-aarch64.c257
-rw-r--r--binutils/ChangeLog8
-rw-r--r--binutils/readelf.c31
-rw-r--r--include/ChangeLog5
-rw-r--r--include/elf/aarch64.h2
-rw-r--r--ld/ChangeLog19
-rw-r--r--ld/NEWS4
-rw-r--r--ld/emultempl/aarch64elf.em17
-rw-r--r--ld/testsuite/ld-aarch64/aarch64-elf.exp10
-rw-r--r--ld/testsuite/ld-aarch64/bti-plt-1.d32
-rw-r--r--ld/testsuite/ld-aarch64/bti-plt-1.s21
-rw-r--r--ld/testsuite/ld-aarch64/bti-plt-2.d11
-rw-r--r--ld/testsuite/ld-aarch64/bti-plt-2.s21
-rw-r--r--ld/testsuite/ld-aarch64/bti-plt-3.d34
-rw-r--r--ld/testsuite/ld-aarch64/bti-plt-4.d10
-rw-r--r--ld/testsuite/ld-aarch64/bti-plt-5.d28
-rw-r--r--ld/testsuite/ld-aarch64/bti-plt-6.d15
-rw-r--r--ld/testsuite/ld-aarch64/bti-plt-7.d15
-rw-r--r--ld/testsuite/ld-aarch64/bti-plt-so.s41
-rw-r--r--ld/testsuite/ld-aarch64/bti-plt.ld14
23 files changed, 687 insertions, 21 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 3e5c7c2..6e7748e 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,4 +1,41 @@
2019-03-13 Sudakshina Das <sudi.das@arm.com>
+ Szabolcs Nagy <szabolcs.nagy@arm.com>
+
+ * bfd-in.h (aarch64_plt_type, aarch64_enable_bti_type): New.
+ (aarch64_bti_pac_info): New.
+ (bfd_elf64_aarch64_set_options): Add aarch64_bti_pac_info argument.
+ (bfd_elf32_aarch64_set_options): Likewise.
+ * bfd-in2.h: Regenerate
+ * elfnn-aarch64.c (PLT_BTI_ENTRY_SIZE): New.
+ (PLT_BTI_SMALL_ENTRY_SIZE, PLT_BTI_TLSDESC_ENTRY_SIZE): New.
+ (elfNN_aarch64_small_plt0_bti_entry): New.
+ (elfNN_aarch64_small_plt_bti_entry): New.
+ (elfNN_aarch64_tlsdesc_small_plt_bti_entry): New.
+ (elf_aarch64_obj_tdata): Add no_bti_warn and plt_type fields.
+ (elf_aarch64_link_hash_table): Add plt0_entry, plt_entry and
+ tlsdesc_plt_entry_size fields.
+ (elfNN_aarch64_link_hash_table_create): Initialise the new fields.
+ (setup_plt_values): New helper function.
+ (bfd_elfNN_aarch64_set_options): Use new bp_info to set plt sizes and
+ bti enable type.
+ (elfNN_aarch64_allocate_dynrelocs): Use new size members instead of
+ fixed macros.
+ (elfNN_aarch64_size_dynamic_sections): Likewise and add checks.
+ (elfNN_aarch64_create_small_pltn_entry): Use new generic pointers
+ to plt stubs instead of fixed ones and update filling them according
+ to the need for bti.
+ (elfNN_aarch64_init_small_plt0_entry): Likewise.
+ (elfNN_aarch64_finish_dynamic_sections): Likewise.
+ (get_plt_type, elfNN_aarch64_get_synthetic_symtab): New.
+ (elfNN_aarch64_plt_sym_val): Update size accordingly.
+ (elfNN_aarch64_link_setup_gnu_properties): Set up plts if BTI GNU NOTE
+ is set.
+ (bfd_elfNN_get_synthetic_symtab): Define.
+ (elfNN_aarch64_merge_gnu_properties): Give out warning with --force-bti
+ and mising BTI NOTE SECTION.
+
+
+2019-03-13 Sudakshina Das <sudi.das@arm.com>
* elf-properties.c (_bfd_elf_link_setup_gnu_properties): Exclude
linker created inputs from merge.
diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h
index e7c2eaa..b753a9e 100644
--- a/bfd/bfd-in.h
+++ b/bfd/bfd-in.h
@@ -995,11 +995,45 @@ extern void bfd_elf64_aarch64_init_maps
extern void bfd_elf32_aarch64_init_maps
(bfd *);
+/* Types of PLTs based on the level of security. This would be a
+ bit-mask to denote which of the combinations of security features
+ are enabled:
+ - No security feature PLTs
+ - PLTs with BTI instruction
+ - PLTs with PAC instruction
+*/
+typedef enum
+{
+ PLT_NORMAL = 0x0, /* Normal plts. */
+ PLT_BTI = 0x1, /* plts with bti. */
+ PLT_PAC = 0x2, /* plts with pointer authentication. */
+ PLT_BTI_PAC = PLT_BTI | PLT_PAC
+} aarch64_plt_type;
+
+/* To indicate if BTI is enabled with/without warning. */
+typedef enum
+{
+ BTI_NONE = 0, /* BTI is not enabled. */
+ BTI_WARN = 1, /* BTI is enabled with --force-bti. */
+} aarch64_enable_bti_type;
+
+/* A structure to encompass all information coming from BTI or PAC
+ related command line options. This involves the "PLT_TYPE" to determine
+ which version of PLTs to pick and "BTI_TYPE" to determine if
+ BTI should be turned on with any warnings. */
+typedef struct
+{
+ aarch64_plt_type plt_type;
+ aarch64_enable_bti_type bti_type;
+} aarch64_bti_pac_info;
+
extern void bfd_elf64_aarch64_set_options
- (bfd *, struct bfd_link_info *, int, int, int, int, int, int);
+ (bfd *, struct bfd_link_info *, int, int, int, int, int, int,
+ aarch64_bti_pac_info);
extern void bfd_elf32_aarch64_set_options
- (bfd *, struct bfd_link_info *, int, int, int, int, int, int);
+ (bfd *, struct bfd_link_info *, int, int, int, int, int, int,
+ aarch64_bti_pac_info);
/* ELF AArch64 mapping symbol support. */
#define BFD_AARCH64_SPECIAL_SYM_TYPE_MAP (1 << 0)
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index e25da50..33a2940 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -1002,11 +1002,45 @@ extern void bfd_elf64_aarch64_init_maps
extern void bfd_elf32_aarch64_init_maps
(bfd *);
+/* Types of PLTs based on the level of security. This would be a
+ bit-mask to denote which of the combinations of security features
+ are enabled:
+ - No security feature PLTs
+ - PLTs with BTI instruction
+ - PLTs with PAC instruction
+*/
+typedef enum
+{
+ PLT_NORMAL = 0x0, /* Normal plts. */
+ PLT_BTI = 0x1, /* plts with bti. */
+ PLT_PAC = 0x2, /* plts with pointer authentication. */
+ PLT_BTI_PAC = PLT_BTI | PLT_PAC
+} aarch64_plt_type;
+
+/* To indicate if BTI is enabled with/without warning. */
+typedef enum
+{
+ BTI_NONE = 0, /* BTI is not enabled. */
+ BTI_WARN = 1, /* BTI is enabled with --force-bti. */
+} aarch64_enable_bti_type;
+
+/* A structure to encompass all information coming from BTI or PAC
+ related command line options. This involves the "PLT_TYPE" to determine
+ which version of PLTs to pick and "BTI_TYPE" to determine if
+ BTI should be turned on with any warnings. */
+typedef struct
+{
+ aarch64_plt_type plt_type;
+ aarch64_enable_bti_type bti_type;
+} aarch64_bti_pac_info;
+
extern void bfd_elf64_aarch64_set_options
- (bfd *, struct bfd_link_info *, int, int, int, int, int, int);
+ (bfd *, struct bfd_link_info *, int, int, int, int, int, int,
+ aarch64_bti_pac_info);
extern void bfd_elf32_aarch64_set_options
- (bfd *, struct bfd_link_info *, int, int, int, int, int, int);
+ (bfd *, struct bfd_link_info *, int, int, int, int, int, int,
+ aarch64_bti_pac_info);
/* ELF AArch64 mapping symbol support. */
#define BFD_AARCH64_SPECIAL_SYM_TYPE_MAP (1 << 0)
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 5b8cc4c..69b8f83 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -267,6 +267,10 @@
#define PLT_ENTRY_SIZE (32)
#define PLT_SMALL_ENTRY_SIZE (16)
#define PLT_TLSDESC_ENTRY_SIZE (32)
+/* PLT sizes with BTI insn. */
+#define PLT_BTI_ENTRY_SIZE (36)
+#define PLT_BTI_SMALL_ENTRY_SIZE (20)
+#define PLT_BTI_TLSDESC_ENTRY_SIZE (36)
/* Encoding of the nop instruction. */
#define INSN_NOP 0xd503201f
@@ -297,9 +301,27 @@ static const bfd_byte elfNN_aarch64_small_plt0_entry[PLT_ENTRY_SIZE] =
0x1f, 0x20, 0x03, 0xd5, /* nop */
};
+static const bfd_byte elfNN_aarch64_small_plt0_bti_entry[PLT_BTI_ENTRY_SIZE] =
+{
+ 0x5f, 0x24, 0x03, 0xd5, /* bti c. */
+ 0xf0, 0x7b, 0xbf, 0xa9, /* stp x16, x30, [sp, #-16]! */
+ 0x10, 0x00, 0x00, 0x90, /* adrp x16, (GOT+16) */
+#if ARCH_SIZE == 64
+ 0x11, 0x0A, 0x40, 0xf9, /* ldr x17, [x16, #PLT_GOT+0x10] */
+ 0x10, 0x42, 0x00, 0x91, /* add x16, x16,#PLT_GOT+0x10 */
+#else
+ 0x11, 0x0A, 0x40, 0xb9, /* ldr w17, [x16, #PLT_GOT+0x8] */
+ 0x10, 0x22, 0x00, 0x11, /* add w16, w16,#PLT_GOT+0x8 */
+#endif
+ 0x20, 0x02, 0x1f, 0xd6, /* br x17 */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+};
+
/* Per function entry in a procedure linkage table looks like this
if the distance between the PLTGOT and the PLT is < 4GB use
- these PLT entries. */
+ these PLT entries. Use BTI versions of the PLTs when enabled. */
static const bfd_byte elfNN_aarch64_small_plt_entry[PLT_SMALL_ENTRY_SIZE] =
{
0x10, 0x00, 0x00, 0x90, /* adrp x16, PLTGOT + n * 8 */
@@ -314,6 +336,21 @@ static const bfd_byte elfNN_aarch64_small_plt_entry[PLT_SMALL_ENTRY_SIZE] =
};
static const bfd_byte
+elfNN_aarch64_small_plt_bti_entry[PLT_BTI_SMALL_ENTRY_SIZE] =
+{
+ 0x5f, 0x24, 0x03, 0xd5, /* bti c. */
+ 0x10, 0x00, 0x00, 0x90, /* adrp x16, PLTGOT + n * 8 */
+#if ARCH_SIZE == 64
+ 0x11, 0x02, 0x40, 0xf9, /* ldr x17, [x16, PLTGOT + n * 8] */
+ 0x10, 0x02, 0x00, 0x91, /* add x16, x16, :lo12:PLTGOT + n * 8 */
+#else
+ 0x11, 0x02, 0x40, 0xb9, /* ldr w17, [x16, PLTGOT + n * 4] */
+ 0x10, 0x02, 0x00, 0x11, /* add w16, w16, :lo12:PLTGOT + n * 4 */
+#endif
+ 0x20, 0x02, 0x1f, 0xd6, /* br x17. */
+};
+
+static const bfd_byte
elfNN_aarch64_tlsdesc_small_plt_entry[PLT_TLSDESC_ENTRY_SIZE] =
{
0xe2, 0x0f, 0xbf, 0xa9, /* stp x2, x3, [sp, #-16]! */
@@ -331,6 +368,25 @@ elfNN_aarch64_tlsdesc_small_plt_entry[PLT_TLSDESC_ENTRY_SIZE] =
0x1f, 0x20, 0x03, 0xd5, /* nop */
};
+static const bfd_byte
+elfNN_aarch64_tlsdesc_small_plt_bti_entry[PLT_BTI_TLSDESC_ENTRY_SIZE] =
+{
+ 0x5f, 0x24, 0x03, 0xd5, /* bti c. */
+ 0xe2, 0x0f, 0xbf, 0xa9, /* stp x2, x3, [sp, #-16]! */
+ 0x02, 0x00, 0x00, 0x90, /* adrp x2, 0 */
+ 0x03, 0x00, 0x00, 0x90, /* adrp x3, 0 */
+#if ARCH_SIZE == 64
+ 0x42, 0x00, 0x40, 0xf9, /* ldr x2, [x2, #0] */
+ 0x63, 0x00, 0x00, 0x91, /* add x3, x3, 0 */
+#else
+ 0x42, 0x00, 0x40, 0xb9, /* ldr w2, [x2, #0] */
+ 0x63, 0x00, 0x00, 0x11, /* add w3, w3, 0 */
+#endif
+ 0x40, 0x00, 0x1f, 0xd6, /* br x2 */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+};
+
#define elf_info_to_howto elfNN_aarch64_info_to_howto
#define elf_info_to_howto_rel elfNN_aarch64_info_to_howto
@@ -2438,6 +2494,13 @@ struct elf_aarch64_obj_tdata
/* All GNU_PROPERTY_AARCH64_FEATURE_1_AND properties. */
uint32_t gnu_and_prop;
+
+ /* Zero to warn when linking objects with incompatible
+ GNU_PROPERTY_AARCH64_FEATURE_1_BTI. */
+ int no_bti_warn;
+
+ /* PLT type based on security. */
+ aarch64_plt_type plt_type;
};
#define elf_aarch64_tdata(bfd) \
@@ -2543,9 +2606,15 @@ struct elf_aarch64_link_hash_table
/* The number of bytes in the initial entry in the PLT. */
bfd_size_type plt_header_size;
- /* The number of bytes in the subsequent PLT etries. */
+ /* The bytes of the initial PLT entry. */
+ const bfd_byte *plt0_entry;
+
+ /* The number of bytes in the subsequent PLT entries. */
bfd_size_type plt_entry_size;
+ /* The bytes of the subsequent PLT entry. */
+ const bfd_byte *plt_entry;
+
/* Small local sym cache. */
struct sym_cache sym_cache;
@@ -2588,6 +2657,9 @@ struct elf_aarch64_link_hash_table
yet. */
bfd_vma tlsdesc_plt;
+ /* The number of bytes in the PLT enty for the TLS descriptor. */
+ bfd_size_type tlsdesc_plt_entry_size;
+
/* The GOT offset for the lazy trampoline. Communicated to the
loader via DT_TLSDESC_GOT. The magic value (bfd_vma) -1
indicates an offset is not allocated. */
@@ -2831,7 +2903,10 @@ elfNN_aarch64_link_hash_table_create (bfd *abfd)
}
ret->plt_header_size = PLT_ENTRY_SIZE;
+ ret->plt0_entry = elfNN_aarch64_small_plt0_entry;
ret->plt_entry_size = PLT_SMALL_ENTRY_SIZE;
+ ret->plt_entry = elfNN_aarch64_small_plt_entry;
+ ret->tlsdesc_plt_entry_size = PLT_TLSDESC_ENTRY_SIZE;
ret->obfd = abfd;
ret->dt_tlsdesc_got = (bfd_vma) - 1;
@@ -4599,6 +4674,28 @@ bfd_elfNN_aarch64_init_maps (bfd *abfd)
}
}
+static void
+setup_plt_values (struct bfd_link_info *link_info,
+ aarch64_plt_type plt_type)
+{
+ struct elf_aarch64_link_hash_table *globals;
+ globals = elf_aarch64_hash_table (link_info);
+
+ if (plt_type == PLT_BTI)
+ {
+ globals->plt_header_size = PLT_BTI_ENTRY_SIZE;
+ globals->plt0_entry = elfNN_aarch64_small_plt0_bti_entry;
+ globals->tlsdesc_plt_entry_size = PLT_BTI_TLSDESC_ENTRY_SIZE;
+
+ /* Only in ET_EXEC we need PLTn with BTI. */
+ if (bfd_link_pde (link_info))
+ {
+ globals->plt_entry_size = PLT_BTI_SMALL_ENTRY_SIZE;
+ globals->plt_entry = elfNN_aarch64_small_plt_bti_entry;
+ }
+ }
+}
+
/* Set option values needed during linking. */
void
bfd_elfNN_aarch64_set_options (struct bfd *output_bfd,
@@ -4607,7 +4704,8 @@ bfd_elfNN_aarch64_set_options (struct bfd *output_bfd,
int no_wchar_warn, int pic_veneer,
int fix_erratum_835769,
int fix_erratum_843419,
- int no_apply_dynamic_relocs)
+ int no_apply_dynamic_relocs,
+ aarch64_bti_pac_info bp_info)
{
struct elf_aarch64_link_hash_table *globals;
@@ -4621,6 +4719,20 @@ bfd_elfNN_aarch64_set_options (struct bfd *output_bfd,
BFD_ASSERT (is_aarch64_elf (output_bfd));
elf_aarch64_tdata (output_bfd)->no_enum_size_warning = no_enum_warn;
elf_aarch64_tdata (output_bfd)->no_wchar_size_warning = no_wchar_warn;
+
+ switch (bp_info.bti_type)
+ {
+ case BTI_WARN:
+ elf_aarch64_tdata (output_bfd)->no_bti_warn = 0;
+ elf_aarch64_tdata (output_bfd)->gnu_and_prop
+ |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
+ break;
+
+ default:
+ break;
+ }
+ elf_aarch64_tdata (output_bfd)->plt_type = bp_info.plt_type;
+ setup_plt_values (link_info, bp_info.plt_type);
}
static bfd_vma
@@ -8349,7 +8461,7 @@ elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
/* Make room for this entry. For now we only create the
small model PLT entries. We later need to find a way
of relaxing into these from the large model PLT entries. */
- s->size += PLT_SMALL_ENTRY_SIZE;
+ s->size += htab->plt_entry_size;
/* We also need to make an entry in the .got.plt section, which
will be placed in the .got section by the linker script. */
@@ -8849,10 +8961,10 @@ elfNN_aarch64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
if (htab->tlsdesc_plt)
{
if (htab->root.splt->size == 0)
- htab->root.splt->size += PLT_ENTRY_SIZE;
+ htab->root.splt->size += htab->plt_header_size;
htab->tlsdesc_plt = htab->root.splt->size;
- htab->root.splt->size += PLT_TLSDESC_ENTRY_SIZE;
+ htab->root.splt->size += htab->tlsdesc_plt_entry_size;
/* If we're not using lazy TLS relocations, don't generate the
GOT entry required. */
@@ -8964,6 +9076,10 @@ elfNN_aarch64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
&& (!add_dynamic_entry (DT_TLSDESC_PLT, 0)
|| !add_dynamic_entry (DT_TLSDESC_GOT, 0)))
return FALSE;
+
+ if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_BTI)
+ && !add_dynamic_entry (DT_AARCH64_BTI_PLT, 0))
+ return FALSE;
}
if (relocs)
@@ -9060,7 +9176,13 @@ elfNN_aarch64_create_small_pltn_entry (struct elf_link_hash_entry *h,
gotplt->output_offset + got_offset;
/* Copy in the boiler-plate for the PLTn entry. */
- memcpy (plt_entry, elfNN_aarch64_small_plt_entry, PLT_SMALL_ENTRY_SIZE);
+ memcpy (plt_entry, htab->plt_entry, htab->plt_entry_size);
+
+ /* First instruction in BTI enabled PLT stub is a BTI
+ instruction so skip it. */
+ if (elf_aarch64_tdata (output_bfd)->plt_type & PLT_BTI
+ && elf_elfheader (output_bfd)->e_type == ET_EXEC)
+ plt_entry = plt_entry + 4;
/* Fill in the top 21 bits for this: ADRP x16, PLT_GOT + n * 8.
ADRP: ((PG(S+A)-PG(P)) >> 12) & 0x1fffff */
@@ -9365,10 +9487,10 @@ elfNN_aarch64_init_small_plt0_entry (bfd *output_bfd ATTRIBUTE_UNUSED,
bfd_vma plt_base;
- memcpy (htab->root.splt->contents, elfNN_aarch64_small_plt0_entry,
- PLT_ENTRY_SIZE);
+ memcpy (htab->root.splt->contents, htab->plt0_entry,
+ htab->plt_header_size);
elf_section_data (htab->root.splt->output_section)->this_hdr.sh_entsize =
- PLT_ENTRY_SIZE;
+ htab->plt_header_size;
plt_got_2nd_ent = (htab->root.sgotplt->output_section->vma
+ htab->root.sgotplt->output_offset
@@ -9377,18 +9499,24 @@ elfNN_aarch64_init_small_plt0_entry (bfd *output_bfd ATTRIBUTE_UNUSED,
plt_base = htab->root.splt->output_section->vma +
htab->root.splt->output_offset;
+ /* First instruction in BTI enabled PLT stub is a BTI
+ instruction so skip it. */
+ bfd_byte *plt0_entry = htab->root.splt->contents;
+ if (elf_aarch64_tdata (output_bfd)->plt_type & PLT_BTI)
+ plt0_entry = plt0_entry + 4;
+
/* Fill in the top 21 bits for this: ADRP x16, PLT_GOT + n * 8.
ADRP: ((PG(S+A)-PG(P)) >> 12) & 0x1fffff */
elf_aarch64_update_plt_entry (output_bfd, BFD_RELOC_AARCH64_ADR_HI21_PCREL,
- htab->root.splt->contents + 4,
+ plt0_entry + 4,
PG (plt_got_2nd_ent) - PG (plt_base + 4));
elf_aarch64_update_plt_entry (output_bfd, BFD_RELOC_AARCH64_LDSTNN_LO12,
- htab->root.splt->contents + 8,
+ plt0_entry + 8,
PG_OFFSET (plt_got_2nd_ent));
elf_aarch64_update_plt_entry (output_bfd, BFD_RELOC_AARCH64_ADD_LO12,
- htab->root.splt->contents + 12,
+ plt0_entry + 12,
PG_OFFSET (plt_got_2nd_ent));
}
@@ -9472,9 +9600,18 @@ elfNN_aarch64_finish_dynamic_sections (bfd *output_bfd,
bfd_put_NN (output_bfd, (bfd_vma) 0,
htab->root.sgot->contents + htab->dt_tlsdesc_got);
+ const bfd_byte *entry = elfNN_aarch64_tlsdesc_small_plt_entry;
+ htab->tlsdesc_plt_entry_size = PLT_TLSDESC_ENTRY_SIZE;
+
+ aarch64_plt_type type = elf_aarch64_tdata (output_bfd)->plt_type;
+ if (type == PLT_BTI)
+ {
+ entry = elfNN_aarch64_tlsdesc_small_plt_bti_entry;
+ htab->tlsdesc_plt_entry_size = PLT_BTI_TLSDESC_ENTRY_SIZE;
+ }
+
memcpy (htab->root.splt->contents + htab->tlsdesc_plt,
- elfNN_aarch64_tlsdesc_small_plt_entry,
- sizeof (elfNN_aarch64_tlsdesc_small_plt_entry));
+ entry, htab->tlsdesc_plt_entry_size);
{
bfd_vma adrp1_addr =
@@ -9496,6 +9633,15 @@ elfNN_aarch64_finish_dynamic_sections (bfd *output_bfd,
bfd_byte *plt_entry =
htab->root.splt->contents + htab->tlsdesc_plt;
+ /* First instruction in BTI enabled PLT stub is a BTI
+ instruction so skip it. */
+ if (type & PLT_BTI)
+ {
+ plt_entry = plt_entry + 4;
+ adrp1_addr = adrp1_addr + 4;
+ adrp2_addr = adrp2_addr + 4;
+ }
+
/* adrp x2, DT_TLSDESC_GOT */
elf_aarch64_update_plt_entry (output_bfd,
BFD_RELOC_AARCH64_ADR_HI21_PCREL,
@@ -9574,6 +9720,53 @@ elfNN_aarch64_finish_dynamic_sections (bfd *output_bfd,
return TRUE;
}
+/* Check if BTI enabled PLTs are needed. Returns the type needed. */
+static aarch64_plt_type
+get_plt_type (bfd *abfd)
+{
+ aarch64_plt_type ret = PLT_NORMAL;
+ bfd_byte *contents, *extdyn, *extdynend;
+ asection *sec = bfd_get_section_by_name (abfd, ".dynamic");
+ if (!sec || !bfd_malloc_and_get_section (abfd, sec, &contents))
+ return ret;
+ extdyn = contents;
+ extdynend = contents + sec->size;
+ for (; extdyn < extdynend; extdyn += sizeof (ElfNN_External_Dyn))
+ {
+ Elf_Internal_Dyn dyn;
+ bfd_elfNN_swap_dyn_in (abfd, extdyn, &dyn);
+
+ /* Let's check the processor specific dynamic array tags. */
+ bfd_vma tag = dyn.d_tag;
+ if (tag < DT_LOPROC || tag > DT_HIPROC)
+ continue;
+
+ switch (tag)
+ {
+ case DT_AARCH64_BTI_PLT:
+ ret = PLT_BTI;
+ break;
+
+ default: break;
+ }
+ }
+ free (contents);
+ return ret;
+}
+
+static long
+elfNN_aarch64_get_synthetic_symtab (bfd *abfd,
+ long symcount,
+ asymbol **syms,
+ long dynsymcount,
+ asymbol **dynsyms,
+ asymbol **ret)
+{
+ elf_aarch64_tdata (abfd)->plt_type = get_plt_type (abfd);
+ return _bfd_elf_get_synthetic_symtab (abfd, symcount, syms,
+ dynsymcount, dynsyms, ret);
+}
+
/* Return address for Ith PLT stub in section PLT, for relocation REL
or (bfd_vma) -1 if it should not be included. */
@@ -9581,7 +9774,16 @@ static bfd_vma
elfNN_aarch64_plt_sym_val (bfd_vma i, const asection *plt,
const arelent *rel ATTRIBUTE_UNUSED)
{
- return plt->vma + PLT_ENTRY_SIZE + i * PLT_SMALL_ENTRY_SIZE;
+ size_t plt0_size = PLT_ENTRY_SIZE;
+ size_t pltn_size = PLT_SMALL_ENTRY_SIZE;
+
+ if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_BTI)
+ {
+ plt0_size = PLT_BTI_ENTRY_SIZE;
+ if (elf_elfheader (plt->owner)->e_type == ET_EXEC)
+ pltn_size = PLT_BTI_SMALL_ENTRY_SIZE;
+ }
+ return plt->vma + plt0_size + i * pltn_size;
}
/* Returns TRUE if NAME is an AArch64 mapping symbol.
@@ -9627,6 +9829,9 @@ 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;
+ elf_aarch64_tdata (info->output_bfd)->plt_type
+ |= (prop & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) ? PLT_BTI : 0;
+ setup_plt_values (info, elf_aarch64_tdata (info->output_bfd)->plt_type);
return pbfd;
}
@@ -9641,6 +9846,23 @@ elfNN_aarch64_merge_gnu_properties (struct bfd_link_info *info,
{
uint32_t prop
= elf_aarch64_tdata (info->output_bfd)->gnu_and_prop;
+
+ /* If output has been marked with BTI using command line argument, give out
+ warning if necessary. */
+ if ((prop & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)
+ && (!elf_aarch64_tdata (info->output_bfd)->no_bti_warn))
+ {
+ if ((aprop && !(aprop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI))
+ || (bprop && !(bprop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI))
+ /* If either property is NULL, it means its bfd did not have any
+ property. */
+ || !aprop || !bprop)
+ {
+ _bfd_error_handler (_("warning: BTI turned on by --force-bti when "
+ "all inputs do not have BTI in NOTE section."));
+ }
+ }
+
return _bfd_aarch64_elf_merge_gnu_properties (info, abfd, aprop,
bprop, prop);
}
@@ -9718,6 +9940,9 @@ const struct elf_size_info elfNN_aarch64_size_info =
#define bfd_elfNN_find_nearest_line \
elfNN_aarch64_find_nearest_line
+#define bfd_elfNN_get_synthetic_symtab \
+ elfNN_aarch64_get_synthetic_symtab
+
#define bfd_elfNN_mkobject \
elfNN_aarch64_mkobject
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 894eb55..b2adf16 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,4 +1,12 @@
2019-03-13 Sudakshina Das <sudi.das@arm.com>
+ Szabolcs Nagy <szabolcs.nagy@arm.com>
+
+ * readelf.c (get_aarch64_dynamic_type): New.
+ (get_dynamic_type): Use above for EM_AARCH64.
+ (dynamic_section_aarch64_val): New.
+ (process_dynamic_section): Use above for EM_AARCH64.
+
+2019-03-13 Sudakshina Das <sudi.das@arm.com>
* readelf.c (decode_aarch64_feature_1_and): New.
(print_gnu_property_note): Add case for AArch64 gnu notes.
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 7446ffe..f4775b4 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -1798,6 +1798,17 @@ dump_relocations (Filedata * filedata,
}
static const char *
+get_aarch64_dynamic_type (unsigned long type)
+{
+ switch (type)
+ {
+ case DT_AARCH64_BTI_PLT: return "AARCH64_BTI_PLT";
+ default:
+ return NULL;
+ }
+}
+
+static const char *
get_mips_dynamic_type (unsigned long type)
{
switch (type)
@@ -2170,6 +2181,9 @@ get_dynamic_type (Filedata * filedata, unsigned long type)
switch (filedata->file_header.e_machine)
{
+ case EM_AARCH64:
+ result = get_aarch64_dynamic_type (type);
+ break;
case EM_MIPS:
case EM_MIPS_RS3_LE:
result = get_mips_dynamic_type (type);
@@ -9345,6 +9359,20 @@ process_unwind (Filedata * filedata)
}
static void
+dynamic_section_aarch64_val (Elf_Internal_Dyn * entry)
+{
+ switch (entry->d_tag)
+ {
+ case DT_AARCH64_BTI_PLT:
+ break;
+ default:
+ print_vma (entry->d_un.d_ptr, PREFIX_HEX);
+ break;
+ }
+ putchar ('\n');
+}
+
+static void
dynamic_section_mips_val (Elf_Internal_Dyn * entry)
{
switch (entry->d_tag)
@@ -10358,6 +10386,9 @@ process_dynamic_section (Filedata * filedata)
{
switch (filedata->file_header.e_machine)
{
+ case EM_AARCH64:
+ dynamic_section_aarch64_val (entry);
+ break;
case EM_MIPS:
case EM_MIPS_RS3_LE:
dynamic_section_mips_val (entry);
diff --git a/include/ChangeLog b/include/ChangeLog
index cf4353c..d67f80f 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,4 +1,9 @@
2019-03-13 Sudakshina Das <sudi.das@arm.com>
+ Szabolcs Nagy <szabolcs.nagy@arm.com>
+
+ * elf/aarch64.h (DT_AARCH64_BTI_PLT): New.
+
+2019-03-13 Sudakshina Das <sudi.das@arm.com>
* elf/common.h (GNU_PROPERTY_AARCH64_FEATURE_1_AND): New.
(GNU_PROPERTY_AARCH64_FEATURE_1_BTI): New.
diff --git a/include/elf/aarch64.h b/include/elf/aarch64.h
index 3133ea6..b86a100 100644
--- a/include/elf/aarch64.h
+++ b/include/elf/aarch64.h
@@ -35,6 +35,8 @@
entry point. */
#define SHF_COMDEF 0x80000000 /* Section may be multiply defined
in the input to a link step. */
+/* Processor specific dynamic array tags. */
+#define DT_AARCH64_BTI_PLT (DT_LOPROC + 1)
/* Relocation types. */
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 32b5387..151877d 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,4 +1,23 @@
2019-03-13 Sudakshina Das <sudi.das@arm.com>
+ Szabolcs Nagy <szabolcs.nagy@arm.com>
+
+ * NEWS: Document --force-bti.
+ * emultempl/aarch64elf.em (plt_type, bti_type, OPTION_FORCE_BTI): New.
+ (PARSE_AND_LIST_SHORTOPTS, PARSE_AND_LIST_OPTIONS): Add force-bti.
+ (PARSE_AND_LIST_ARGS_CASES): Handle OPTION_FORCE_BTI.
+ * testsuite/ld-aarch64/aarch64-elf.exp: Add all the tests below.
+ * testsuite/ld-aarch64/bti-plt-1.d: New test.
+ * testsuite/ld-aarch64/bti-plt-1.s: New test.
+ * testsuite/ld-aarch64/bti-plt-2.d: New test.
+ * testsuite/ld-aarch64/bti-plt-3.d: New test.
+ * testsuite/ld-aarch64/bti-plt-4.d: New test.
+ * testsuite/ld-aarch64/bti-plt-5.d: New test.
+ * testsuite/ld-aarch64/bti-plt-6.d: New test.
+ * testsuite/ld-aarch64/bti-plt-7.d: New test.
+ * testsuite/ld-aarch64/bti-plt-so.s: New test.
+ * testsuite/ld-aarch64/bti-plt.ld: New test.
+
+2019-03-13 Sudakshina Das <sudi.das@arm.com>
* NEWS: Document GNU_PROPERTY_AARCH64_FEATURE_1_BTI and
GNU_PROPERTY_AARCH64_FEATURE_1_PAC.
diff --git a/ld/NEWS b/ld/NEWS
index dcf1185..ed8dfc5 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -10,6 +10,10 @@ Changes in 2.33:
* Add support for GNU_PROPERTY_AARCH64_FEATURE_1_PAC in ELF GNU program
properties in the AArch64 ELF linker.
+* Add --force-bti for AArch64 to enable GNU_PROPERTY_AARCH64_FEATURE_1_BTI
+ on output while warning about missing GNU_PROPERTY_AARCH64_FEATURE_1_BTI
+ on inputs and use PLTs protected with BTI.
+
Changes in 2.32:
* Report property change in linker map file when merging GNU properties.
diff --git a/ld/emultempl/aarch64elf.em b/ld/emultempl/aarch64elf.em
index 45e40b5..02243d9 100644
--- a/ld/emultempl/aarch64elf.em
+++ b/ld/emultempl/aarch64elf.em
@@ -33,6 +33,8 @@ static int pic_veneer = 0;
static int fix_erratum_835769 = 0;
static int fix_erratum_843419 = 0;
static int no_apply_dynamic_relocs = 0;
+static aarch64_plt_type plt_type = PLT_NORMAL;
+static aarch64_enable_bti_type bti_type = BTI_NONE;
static void
gld${EMULATION_NAME}_before_parse (void)
@@ -308,12 +310,17 @@ aarch64_elf_create_output_section_statements (void)
return;
}
+ aarch64_bti_pac_info bp_info;
+ bp_info.plt_type = plt_type;
+ bp_info.bti_type = bti_type;
+
bfd_elf${ELFSIZE}_aarch64_set_options (link_info.output_bfd, &link_info,
no_enum_size_warning,
no_wchar_size_warning,
pic_veneer,
fix_erratum_835769, fix_erratum_843419,
- no_apply_dynamic_relocs);
+ no_apply_dynamic_relocs,
+ bp_info);
stub_file = lang_add_input_file ("linker stubs",
lang_input_file_is_fake_enum,
@@ -365,6 +372,7 @@ PARSE_AND_LIST_PROLOGUE='
#define OPTION_FIX_ERRATUM_835769 313
#define OPTION_FIX_ERRATUM_843419 314
#define OPTION_NO_APPLY_DYNAMIC_RELOCS 315
+#define OPTION_FORCE_BTI 316
'
PARSE_AND_LIST_SHORTOPTS=p
@@ -378,6 +386,7 @@ PARSE_AND_LIST_LONGOPTS='
{ "fix-cortex-a53-835769", no_argument, NULL, OPTION_FIX_ERRATUM_835769},
{ "fix-cortex-a53-843419", no_argument, NULL, OPTION_FIX_ERRATUM_843419},
{ "no-apply-dynamic-relocs", no_argument, NULL, OPTION_NO_APPLY_DYNAMIC_RELOCS},
+ { "force-bti", no_argument, NULL, OPTION_FORCE_BTI},
'
PARSE_AND_LIST_OPTIONS='
@@ -398,6 +407,7 @@ PARSE_AND_LIST_OPTIONS='
fprintf (file, _(" --fix-cortex-a53-835769 Fix erratum 835769\n"));
fprintf (file, _(" --fix-cortex-a53-843419 Fix erratum 843419\n"));
fprintf (file, _(" --no-apply-dynamic-relocs Do not apply link-time values for dynamic relocations\n"));
+ fprintf (file, _(" --force-bti Turn on Branch Target Identification mechanism and generate PLTs with BTI. Generate warnings for missing BTI on inputs\n"));
'
PARSE_AND_LIST_ARGS_CASES='
@@ -429,6 +439,11 @@ PARSE_AND_LIST_ARGS_CASES='
no_apply_dynamic_relocs = 1;
break;
+ case OPTION_FORCE_BTI:
+ plt_type |= PLT_BTI;
+ bti_type = BTI_WARN;
+ break;
+
case OPTION_STUBGROUP_SIZE:
{
const char *end;
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index c6fefbb..906534b 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -374,6 +374,8 @@ 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"
+run_dump_test "bti-plt-1"
+run_dump_test "bti-plt-2"
set aarch64elflinktests {
{"ld-aarch64/so with global symbol" "-shared" "" "" {copy-reloc-so.s}
@@ -389,6 +391,14 @@ set aarch64elflinktests {
{"ld-aarch64/func sym hash opt for exe"
"-e0 --hash-style=gnu tmpdir/func-in-so.so" "" ""
{func-sym-hash-opt.s} {{readelf --dyn-sym func-sym-hash-opt.d}} "hash-opt"}
+ {"Build bti-plt-so for PLT tests" "-shared" "" "" {bti-plt-so.s}
+ {} "libbti-plt-so.so"}
}
run_ld_link_tests $aarch64elflinktests
+
+run_dump_test "bti-plt-3"
+run_dump_test "bti-plt-4"
+run_dump_test "bti-plt-5"
+run_dump_test "bti-plt-6"
+run_dump_test "bti-plt-7"
diff --git a/ld/testsuite/ld-aarch64/bti-plt-1.d b/ld/testsuite/ld-aarch64/bti-plt-1.d
new file mode 100644
index 0000000..b7b58a8
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/bti-plt-1.d
@@ -0,0 +1,32 @@
+#name: Check --force-bti emits BTI PLT (shared)
+#source: bti-plt-1.s
+#as: -mabi=lp64
+#ld: -shared --force-bti -T bti-plt.ld
+#objdump: -dr -j .plt
+
+[^:]*: *file format elf64-.*aarch64
+
+Disassembly of section \.plt:
+
+[0-9]+ <.*>:
+.*: d503245f bti c
+.*: a9bf7bf0 stp x16, x30, \[sp, #-16\]!
+.*: 90000090 adrp x16, 28000 <_GLOBAL_OFFSET_TABLE_>
+.*: f9400e11 ldr x17, \[x16, #24\]
+.*: 91006210 add x16, x16, #0x18
+.*: d61f0220 br x17
+.*: d503201f nop
+.*: d503201f nop
+.*: d503201f nop
+
+[0-9]+ <.*>:
+.*: 90000090 adrp x16, 28000 <_GLOBAL_OFFSET_TABLE_>
+.*: f9401211 ldr x17, \[x16, #32\]
+.*: 91008210 add x16, x16, #0x20
+.*: d61f0220 br x17
+
+[0-9]+ <.*>:
+.*: 90000090 adrp x16, 28000 <_GLOBAL_OFFSET_TABLE_>
+.*: f9401611 ldr x17, \[x16, #40\]
+.*: 9100a210 add x16, x16, #0x28
+.*: d61f0220 br x17
diff --git a/ld/testsuite/ld-aarch64/bti-plt-1.s b/ld/testsuite/ld-aarch64/bti-plt-1.s
new file mode 100644
index 0000000..78e1aaa
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/bti-plt-1.s
@@ -0,0 +1,21 @@
+ .text
+ .globl _start
+ .type _start,@function
+_start:
+ bl foo
+ bl bar
+ .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:
diff --git a/ld/testsuite/ld-aarch64/bti-plt-2.d b/ld/testsuite/ld-aarch64/bti-plt-2.d
new file mode 100644
index 0000000..c26e47a
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/bti-plt-2.d
@@ -0,0 +1,11 @@
+#name: Check --force-bti emits BTI feature (shared)
+#source: bti-plt-1.s
+#source: bti-plt-2.s
+#as: -mabi=lp64
+#ld: -shared --force-bti -T bti-plt.ld
+#readelf: -n
+
+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/bti-plt-2.s b/ld/testsuite/ld-aarch64/bti-plt-2.s
new file mode 100644
index 0000000..fff945c
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/bti-plt-2.s
@@ -0,0 +1,21 @@
+ .text
+ .globl _start
+ .type _start,@function
+func2:
+ bl foo2
+ bl bar2
+ .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:
diff --git a/ld/testsuite/ld-aarch64/bti-plt-3.d b/ld/testsuite/ld-aarch64/bti-plt-3.d
new file mode 100644
index 0000000..0d4c467
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/bti-plt-3.d
@@ -0,0 +1,34 @@
+#name: Check --force-bti emits BTI PLT (exec)
+#source: bti-plt-1.s
+#as: -mabi=lp64
+#ld: --force-bti -e _start -T bti-plt.ld -L./tmpdir -lbti-plt-so
+#objdump: -dr -j .plt
+
+[^:]*: *file format elf64-.*aarch64
+
+Disassembly of section \.plt:
+
+[0-9]+ <.*>:
+.*: d503245f bti c
+.*: a9bf7bf0 stp x16, x30, \[sp, #-16\]!
+.*: 90000090 adrp x16, 28000 <_GLOBAL_OFFSET_TABLE_>
+.*: f9400e11 ldr x17, \[x16, #24\]
+.*: 91006210 add x16, x16, #0x18
+.*: d61f0220 br x17
+.*: d503201f nop
+.*: d503201f nop
+.*: d503201f nop
+
+[0-9]+ <.*>:
+.*: d503245f bti c
+.*: 90000090 adrp x16, 28000 <_GLOBAL_OFFSET_TABLE_>
+.*: f9401211 ldr x17, \[x16, #32\]
+.*: 91008210 add x16, x16, #0x20
+.*: d61f0220 br x17
+
+[0-9]+ <.*>:
+.*: d503245f bti c
+.*: 90000090 adrp x16, 28000 <_GLOBAL_OFFSET_TABLE_>
+.*: f9401611 ldr x17, \[x16, #40\]
+.*: 9100a210 add x16, x16, #0x28
+.*: d61f0220 br x17
diff --git a/ld/testsuite/ld-aarch64/bti-plt-4.d b/ld/testsuite/ld-aarch64/bti-plt-4.d
new file mode 100644
index 0000000..90aeed2
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/bti-plt-4.d
@@ -0,0 +1,10 @@
+#name: Check --force-bti emits BTI feature (exec)
+#source: bti-plt-1.s
+#as: -mabi=lp64
+#ld: --force-bti -e _start -T bti-plt.ld -L./tmpdir -lbti-plt-so
+#readelf: -n
+
+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/bti-plt-5.d b/ld/testsuite/ld-aarch64/bti-plt-5.d
new file mode 100644
index 0000000..01231b6
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/bti-plt-5.d
@@ -0,0 +1,28 @@
+#name: BTI PLT with only GNU PROP
+#source: property-bti-pac1.s
+#as: -mabi=lp64 -defsym __property_bti__=1
+#ld: -e _start -L./tmpdir -lbti-plt-so
+#objdump: -dr -j .plt
+#target: *linux*
+
+[^:]*: *file format elf64-.*aarch64
+
+Disassembly of section \.plt:
+
+[0-9a-f]+ <.*>:
+.*: d503245f bti c
+.*: a9bf7bf0 stp x16, x30, \[sp, #-16\]!
+.*: 90000090 adrp x16, 410000 <_start\+0xfd28>
+.*: f9421611 ldr x17, \[x16, #1064\]
+.*: 9110a210 add x16, x16, #0x428
+.*: d61f0220 br x17
+.*: d503201f nop
+.*: d503201f nop
+.*: d503201f nop
+
+[0-9a-f]+ <.*>:
+.*: d503245f bti c
+.*: 90000090 adrp x16, 410000 <_start\+0xfd28>
+.*: f9421a11 ldr x17, \[x16, #1072\]
+.*: 9110c210 add x16, x16, #0x430
+.*: d61f0220 br x17
diff --git a/ld/testsuite/ld-aarch64/bti-plt-6.d b/ld/testsuite/ld-aarch64/bti-plt-6.d
new file mode 100644
index 0000000..c7d5169
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/bti-plt-6.d
@@ -0,0 +1,15 @@
+#name: Warn with one missing GNU NOTE BTI input
+#source: property-bti-pac1.s
+#source: property-bti-pac2.s
+#as: -mabi=lp64 -defsym __property_pac__=1
+#ld: -shared --force-bti
+#warning: .*: warning: BTI turned on by --force-bti.*$
+#readelf: -n
+
+# Should warn about the missing input BTI NOTE but should
+# still mark output as BTI
+
+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/bti-plt-7.d b/ld/testsuite/ld-aarch64/bti-plt-7.d
new file mode 100644
index 0000000..625f284
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/bti-plt-7.d
@@ -0,0 +1,15 @@
+#name: Warn when neither inputs has GNU NOTE BTI
+#source: property-bti-pac1.s
+#source: plt_mapping_symbol.s
+#as: -mabi=lp64
+#ld: -shared --force-bti
+#warning: .*: warning: BTI turned on by --force-bti.*$
+#readelf: -n
+
+# Should warn about the missing input BTI NOTE but should
+# still mark output as BTI
+
+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/bti-plt-so.s b/ld/testsuite/ld-aarch64/bti-plt-so.s
new file mode 100644
index 0000000..2c11356
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/bti-plt-so.s
@@ -0,0 +1,41 @@
+ .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
+bar:
+ 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 bar, .-bar
+ .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:
diff --git a/ld/testsuite/ld-aarch64/bti-plt.ld b/ld/testsuite/ld-aarch64/bti-plt.ld
new file mode 100644
index 0000000..8682623
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/bti-plt.ld
@@ -0,0 +1,14 @@
+OUTPUT_ARCH(aarch64)
+ENTRY(_start)
+SECTIONS
+{
+ . = 0x10000;
+ .rela.plt : { *(.rela.plt) *(.rela.iplt) }
+ . = 0x18000;
+ .plt : { *(.plt) *(.iplt) }
+ . = 0x20000;
+ .text : { *(.text) }
+ . = 0x28000;
+ .got : { *(.got) *(.got.plt) }
+ .ARM.attributes 0 : { *(.ARM.atttributes) }
+}