diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h index e7c2eaa93591ca2fc2cfd6f2c5a161ba0c2928a1..61affcbbb991e4c5b6c5ca28df0c60eafec3da05 100644 --- a/bfd/bfd-in.h +++ b/bfd/bfd-in.h @@ -995,11 +995,46 @@ 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_NOWARN = 1, /* BTI is enabled with --bti-nowarn. */ + BTI_WARN = 2, /* BTI is enabled with --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/without 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 e25da50aafbf4fe14b7220bb2d0791ac7899b4f6..5bc09f50c4d68dba7615007dccdc9b541e49aa04 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -1002,11 +1002,46 @@ 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_NOWARN = 1, /* BTI is enabled with --bti-nowarn. */ + BTI_WARN = 2, /* BTI is enabled with --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/without 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 5b8cc4c9701feacd0deb5c998c89d17d97864646..66fe86bbac45f2de1bce43c68036ff18ffb989a8 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_enable_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,26 @@ 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_NOWARN: + elf_aarch64_tdata (output_bfd)->no_enable_bti_warn = 1; + elf_aarch64_tdata (output_bfd)->gnu_and_prop + |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI; + break; + + case BTI_WARN: + elf_aarch64_tdata (output_bfd)->no_enable_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 +8467,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 +8967,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 +9082,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 +9182,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 +9493,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 +9505,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 +9606,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 +9639,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 +9726,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 +9780,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 +9835,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; } @@ -9718,6 +9929,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/readelf.c b/binutils/readelf.c index 7446ffeee21961bf56b12ff16afbf52e5cd35387..f4775b439fc6a14a14699c88af3fe5f07648352e 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/elf/aarch64.h b/include/elf/aarch64.h index 3133ea6f6653eefc846da224e14fc6974cb2bf54..b86a1006297891d38f55f0c29d0ac51056b0c6e3 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/NEWS b/ld/NEWS index dcf11854f528028820cbe1983bbcdd5753d97eaf..31731219ad546483ae92a7e32862986627bfc4d4 100644 --- a/ld/NEWS +++ b/ld/NEWS @@ -10,6 +10,9 @@ Changes in 2.33: * Add support for GNU_PROPERTY_AARCH64_FEATURE_1_PAC in ELF GNU program properties in the AArch64 ELF linker. +* Add --bti-nowarn for AArch64 to enable GNU_PROPERTY_AARCH64_FEATURE_1_BTI + on output without any warnings 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 45e40b510cf0da21e777f5734dcc9d1be54918a5..146bfad31fd299ef5c170b269e86afd0f3e1f5b9 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_BTI_NOWARN 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}, + { "bti-nowarn", no_argument, NULL, OPTION_BTI_NOWARN}, ' 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, _(" --bti-nowarn Turn on Branch Target Identification mechanism and generate PLTs with BTI. Generate no 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_BTI_NOWARN: + plt_type |= PLT_BTI; + bti_type = BTI_NOWARN; + 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 c6fefbbd5c3f7e5516086c7eca0e056ae243d36d..ed0bca5b081c5c016b3f8e96619b76820aa1525d 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,12 @@ 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" 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 0000000000000000000000000000000000000000..16c71024989c4ecd6bc2fc2356956ac7a4c0debf --- /dev/null +++ b/ld/testsuite/ld-aarch64/bti-plt-1.d @@ -0,0 +1,32 @@ +#name: Check --bti-nowarn emits BTI PLT (shared) +#source: bti-plt-1.s +#as: -mabi=lp64 +#ld: -shared --bti-nowarn -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 0000000000000000000000000000000000000000..9cd7cc467b32d13b8531a0c183b6e50d78971ef6 --- /dev/null +++ b/ld/testsuite/ld-aarch64/bti-plt-1.s @@ -0,0 +1,6 @@ + .text + .globl _start + .type _start,@function +_start: + bl foo + bl bar 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 0000000000000000000000000000000000000000..2c7cc0df8d4a165193bb7299b93ce814ed81f4dc --- /dev/null +++ b/ld/testsuite/ld-aarch64/bti-plt-2.d @@ -0,0 +1,11 @@ +#name: Check --bti-nowarn emits BTI feature (shared) +#source: bti-plt-1.s +#source: bti-plt-2.s +#as: -mabi=lp64 +#ld: -shared --bti-nowarn -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 0000000000000000000000000000000000000000..4c29bb879c80eea377ae666de4f5f3fac01b472f --- /dev/null +++ b/ld/testsuite/ld-aarch64/bti-plt-2.s @@ -0,0 +1,6 @@ + .text + .globl _start + .type _start,@function +func2: + bl foo2 + bl bar2 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 0000000000000000000000000000000000000000..47116cc21db775ae1470198d6ef7c6f99f09eb43 --- /dev/null +++ b/ld/testsuite/ld-aarch64/bti-plt-3.d @@ -0,0 +1,34 @@ +#name: Check --bti-nowarn emits BTI PLT (exec) +#source: bti-plt-1.s +#as: -mabi=lp64 +#ld: --bti-nowarn -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 0000000000000000000000000000000000000000..92949c0c7325121710892193f19b04c8f1e9fe29 --- /dev/null +++ b/ld/testsuite/ld-aarch64/bti-plt-4.d @@ -0,0 +1,10 @@ +#name: Check --bti-nowarn emits BTI feature (exec) +#source: bti-plt-1.s +#as: -mabi=lp64 +#ld: --bti-nowarn -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 0000000000000000000000000000000000000000..01231b69d2c4066d0fe3c49e359cef9b670ba34d --- /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-so.s b/ld/testsuite/ld-aarch64/bti-plt-so.s new file mode 100644 index 0000000000000000000000000000000000000000..d335af02536eefa77bea9ebbf5f1407817b42fa0 --- /dev/null +++ b/ld/testsuite/ld-aarch64/bti-plt-so.s @@ -0,0 +1,26 @@ + .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 diff --git a/ld/testsuite/ld-aarch64/bti-plt.ld b/ld/testsuite/ld-aarch64/bti-plt.ld new file mode 100644 index 0000000000000000000000000000000000000000..8682623d69b97cd735a7459838c0ce547723c337 --- /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) } +}