aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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) }
+}