diff options
author | Sudakshina Das <sudi.das@arm.com> | 2019-03-13 10:54:30 +0000 |
---|---|---|
committer | Sudakshina Das <sudi.das@arm.com> | 2019-03-13 11:47:07 +0000 |
commit | 37c18eedffe3926a330149ca93e7407917e2be38 (patch) | |
tree | bc49f9058988c84c84029fe8b302e102fa4387c6 /bfd | |
parent | cd702818c6cf25277253b3b5c23f17d2cf7a94df (diff) | |
download | binutils-37c18eedffe3926a330149ca93e7407917e2be38.zip binutils-37c18eedffe3926a330149ca93e7407917e2be38.tar.gz binutils-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.
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/ChangeLog | 37 | ||||
-rw-r--r-- | bfd/bfd-in.h | 38 | ||||
-rw-r--r-- | bfd/bfd-in2.h | 38 | ||||
-rw-r--r-- | bfd/elfnn-aarch64.c | 257 |
4 files changed, 350 insertions, 20 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 |