From: Siddhesh Poyarekar Date: Fri, 11 Sep 2020 03:48:11 +0000 (+0530) Subject: [Morello] Capability support for exception headers X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fa6ca5e254bb95725389f8eb87cd426def4e23f1;p=thirdparty%2Fbinutils-gdb.git [Morello] Capability support for exception headers - Identify and mark C64 frames - Identify C64 registers including DDC. - Identify 'purecap' argument to .cfi_startproc for C64 frames - Emit 'C' in augmentation string for C64 frames - Recognise the 'C' in the CIE augmentation string when parsing exception headers Difference from LLVM: The llvm assembler only uses purecap to add C to the augmentation string. The GNU assembler on the other hand uses -march and validates that purecap is passed to .cfi_startproc only for -morello+c64. This means that for code compiled for A64, if llvm sees `.cfi_startproc purecap`, it sets 'C' whereas the GNU assembler flags an error. bfd/ChangeLog: 2020-10-20 Siddhesh Poyarekar * elf-bfd.h (elf_backend_data): New callback elf_backend_eh_frame_augmentation_char. * elf-eh-frame.c (_bfd_elf_parse_eh_frame): Use it. * elfnn-aarch64.c (elf64_aarch64_eh_frame_augmentation_char): New function. (elf_backend_eh_frame_augmentation_char): New macro. * elfxx-target.h [!elf_backend_eh_frame_augmentation_char]: Set elf_backend_eh_frame_augmentation_char to NULL. (elfNN_bed): Initialise elf_backend_eh_frame_augmentation_char. binutils/ChangeLog: 2020-10-20 Siddhesh Poyarekar * dwarf.c (dwarf_regnames_aarch64): Add capability registers. gas/ChangeLog: 2020-10-20 Siddhesh Poyarekar * config/tc-aarch64.c (REG_DW_CSP, REG_DW_CLR): New macros. (s_aarch64_cfi_b_key_frame): Adjust for new entry_extras struct. (tc_aarch64_frame_initial_instructions): Adjust for C64. (tc_aarch64_fde_entry_init_extra, tc_aarch64_cfi_startproc_exp): New functions. (tc_aarch64_regname_to_dw2regnum): Support capability registers. * config/tc-aarch64.h (fde_entry): Forward declaration. (eh_entry_extras): New struct. (tc_fde_entry_extras, tc_cie_entry_extras): Use it. (tc_fde_entry_init_extra): Set to tc_aarch64_fde_entry_init_extra. (tc_output_cie_extra): Emit 'C' for C64. (tc_cie_fde_equivalent_extra): Adjust for C64. (tc_cie_entry_init_extra): Likewise. (tc_cfi_startproc_exp): New macro. (tc_aarch64_cfi_startproc_exp, tc_aarch64_fde_entry_init_extra): New function declarations. * dw2gencfi.c (tc_cfi_startproc_exp): New macro. (dot_cfi_startproc): Use it. * testsuite/gas/aarch64/morello-eh.d: New test. * testsuite/gas/aarch64/morello-eh.s: New test. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 54abe00f310..e714ede5d33 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,17 @@ +2020-10-20 Siddhesh Poyarekar + + * elf-bfd.h (elf_backend_data): New callback + elf_backend_eh_frame_augmentation_char. + * elf-eh-frame.c (_bfd_elf_parse_eh_frame): Use it. + * elfnn-aarch64.c (elf64_aarch64_eh_frame_augmentation_char): + New function. + (elf_backend_eh_frame_augmentation_char): New macro. + + * elfxx-target.h [!elf_backend_eh_frame_augmentation_char]: + Set elf_backend_eh_frame_augmentation_char to NULL. + (elfNN_bed): Initialise + elf_backend_eh_frame_augmentation_char. + 2020-10-20 Siddhesh Poyarekar * elfnn-aarch64.c (STUB_ENTRY_NAME): Add format specifier for diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 98165af1335..f383cd8bf6e 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -1390,6 +1390,8 @@ struct elf_backend_data (bfd *, struct bfd_link_info *, asection *); bfd_boolean (*elf_backend_can_make_lsda_relative_eh_frame) (bfd *, struct bfd_link_info *, asection *); + bfd_boolean (*elf_backend_eh_frame_augmentation_char) + (char); /* This function returns an encoding after computing the encoded value (and storing it in ENCODED) for the given OFFSET into OSEC, diff --git a/bfd/elf-eh-frame.c b/bfd/elf-eh-frame.c index 7a129b00f8d..54da9bec11f 100644 --- a/bfd/elf-eh-frame.c +++ b/bfd/elf-eh-frame.c @@ -597,6 +597,7 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, unsigned int num_cies; unsigned int num_entries; elf_gc_mark_hook_fn gc_mark_hook; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); htab = elf_hash_table (info); hdr_info = &htab->eh_info; @@ -623,8 +624,7 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, it (it would need to use 64-bit .eh_frame format anyway). */ REQUIRE (sec->size == (unsigned int) sec->size); - ptr_size = (get_elf_backend_data (abfd) - ->elf_backend_eh_frame_address_size (abfd, sec)); + ptr_size = bed->elf_backend_eh_frame_address_size (abfd, sec); REQUIRE (ptr_size != 0); /* Go through the section contents and work out how many FDEs and @@ -692,7 +692,7 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, buf = ehbuf; cie_count = 0; - gc_mark_hook = get_elf_backend_data (abfd)->gc_mark_hook; + gc_mark_hook = bed->gc_mark_hook; while ((bfd_size_type) (buf - ehbuf) != sec->size) { char *aug; @@ -840,8 +840,12 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, } break; default: - /* Unrecognized augmentation. Better bail out. */ - goto free_no_table; + /* Unrecognized augmentation. Better bail out if the target + cannot recognised it. */ + if (bed->elf_backend_eh_frame_augmentation_char == NULL + || (!bed->elf_backend_eh_frame_augmentation_char + (*(aug - 1)))) + goto free_no_table; } } this_inf->u.cie.aug_data_len @@ -850,8 +854,7 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, /* For shared libraries, try to get rid of as many RELATIVE relocs as possible. */ if (bfd_link_pic (info) - && (get_elf_backend_data (abfd) - ->elf_backend_can_make_relative_eh_frame + && (bed->elf_backend_can_make_relative_eh_frame (abfd, info, sec))) { if ((cie->fde_encoding & 0x70) == DW_EH_PE_absptr) diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c index bd7da1610a7..f1a43e18e0e 100644 --- a/bfd/elfnn-aarch64.c +++ b/bfd/elfnn-aarch64.c @@ -10934,6 +10934,14 @@ elfNN_aarch64_got_header_size (struct bfd_link_info *info) return GOT_ENTRY_SIZE (htab) * GOT_RESERVED_HEADER_SLOTS; } +/* Identify the 'C' in the CIE augmentation string. */ + +static bfd_boolean +elf64_aarch64_eh_frame_augmentation_char (const char aug) +{ + return aug == 'C'; +} + /* We use this so we can override certain functions (though currently we don't). */ @@ -11084,6 +11092,9 @@ const struct elf_size_info elfNN_aarch64_size_info = #define elf_backend_got_elt_size \ elfNN_aarch64_got_elt_size +#define elf_backend_eh_frame_augmentation_char \ + elf64_aarch64_eh_frame_augmentation_char + #define elf_backend_can_refcount 1 #define elf_backend_can_gc_sections 1 #define elf_backend_plt_readonly 1 diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h index d527a604f0f..ad8322e1596 100644 --- a/bfd/elfxx-target.h +++ b/bfd/elfxx-target.h @@ -654,6 +654,9 @@ #ifndef elf_backend_can_make_lsda_relative_eh_frame #define elf_backend_can_make_lsda_relative_eh_frame _bfd_elf_can_make_relative #endif +#ifndef elf_backend_eh_frame_augmentation_char +#define elf_backend_eh_frame_augmentation_char NULL +#endif #ifndef elf_backend_encode_eh_address #define elf_backend_encode_eh_address _bfd_elf_encode_eh_address #endif @@ -885,6 +888,7 @@ static struct elf_backend_data elfNN_bed = elf_backend_eh_frame_address_size, elf_backend_can_make_relative_eh_frame, elf_backend_can_make_lsda_relative_eh_frame, + elf_backend_eh_frame_augmentation_char, elf_backend_encode_eh_address, elf_backend_write_section, elf_backend_elfsym_local_is_section, diff --git a/binutils/ChangeLog b/binutils/ChangeLog index b297de9667c..635f9211a6f 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,7 @@ +2020-10-20 Siddhesh Poyarekar + + * dwarf.c (dwarf_regnames_aarch64): Add capability registers. + 2020-10-20 Alan Modra * readelf.c: Delete whitespace at end of line throughout. diff --git a/binutils/dwarf.c b/binutils/dwarf.c index e152b20438c..9db544232fe 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -7563,6 +7563,19 @@ static const char *const dwarf_regnames_aarch64[] = "z8", "z9", "z10", "z11", "z12", "z13", "z14", "z15", "z16", "z17", "z18", "z19", "z20", "z21", "z22", "z23", "z24", "z25", "z26", "z27", "z28", "z29", "z30", "z31", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, "c0", "c1", + "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", + "c10", "c11", "c12", "c13", "c14", "c15", "c16", "c17", + "c18", "c19", "c20", "c21", "c22", "c23", "c24", "c25", + "c26", "c27", "c28", "c29", "c30", "csp", NULL, "ddc", }; static void diff --git a/gas/ChangeLog b/gas/ChangeLog index dd8fd72b837..91c9c9f5a75 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,29 @@ +2020-10-20 Siddhesh Poyarekar + + * config/tc-aarch64.c (REG_DW_CSP, REG_DW_CLR): New macros. + (s_aarch64_cfi_b_key_frame): Adjust for new entry_extras + struct. + (tc_aarch64_frame_initial_instructions): Adjust for C64. + (tc_aarch64_fde_entry_init_extra, + tc_aarch64_cfi_startproc_exp): New functions. + (tc_aarch64_regname_to_dw2regnum): Support capability + registers. + * config/tc-aarch64.h (fde_entry): Forward declaration. + (eh_entry_extras): New struct. + (tc_fde_entry_extras, tc_cie_entry_extras): Use it. + (tc_fde_entry_init_extra): Set to + tc_aarch64_fde_entry_init_extra. + (tc_output_cie_extra): Emit 'C' for C64. + (tc_cie_fde_equivalent_extra): Adjust for C64. + (tc_cie_entry_init_extra): Likewise. + (tc_cfi_startproc_exp): New macro. + (tc_aarch64_cfi_startproc_exp, + tc_aarch64_fde_entry_init_extra): New function declarations. + * dw2gencfi.c (tc_cfi_startproc_exp): New macro. + (dot_cfi_startproc): Use it. + * testsuite/gas/aarch64/morello-eh.d: New test. + * testsuite/gas/aarch64/morello-eh.s: New test. + 2020-10-20 Siddhesh Poyarekar * config/tc-aarch64.c (parse_operands): Choose C64 branch diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c index 4e63ce1594c..8cc4d673593 100644 --- a/gas/config/tc-aarch64.c +++ b/gas/config/tc-aarch64.c @@ -469,6 +469,8 @@ get_reg_expected_msg (aarch64_reg_type reg_type) /* Some well known registers that we refer to directly elsewhere. */ #define REG_SP 31 #define REG_ZR 31 +#define REG_DW_CSP (31 + 198) +#define REG_DW_CLR (30 + 198) /* Instructions take 4 bytes in the object file. */ #define INSN_SIZE 4 @@ -2101,7 +2103,7 @@ s_aarch64_cfi_b_key_frame (int ignored ATTRIBUTE_UNUSED) { demand_empty_rest_of_line (); struct fde_entry *fde = frchain_now->frch_cfi_data->cur_fde_data; - fde->pauth_key = AARCH64_PAUTH_KEY_B; + fde->entry_extras.pauth_key = AARCH64_PAUTH_KEY_B; } #ifdef OBJ_ELF @@ -7962,8 +7964,36 @@ aarch64_init_frag (fragS * fragP, int max_chars) void tc_aarch64_frame_initial_instructions (void) { - cfi_add_CFA_def_cfa (REG_SP, 0); + if (IS_C64) + { + cfi_set_return_column (REG_DW_CLR); + cfi_add_CFA_def_cfa (REG_DW_CSP, 0); + } + else + cfi_add_CFA_def_cfa (REG_SP, 0); +} + + +/* The extra initialisation steps needed by AArch64 in alloc_fde_entry. + Currently only used to initialise the key used to sign the return + address. */ +void +tc_aarch64_fde_entry_init_extra(struct fde_entry *fde) +{ + fde->entry_extras.pauth_key = AARCH64_PAUTH_KEY_A; + fde->entry_extras.c64 = IS_C64; } + +bfd_boolean +tc_aarch64_cfi_startproc_exp (const char *arg) +{ + // Allow purecap only for C64 functions. + if (!strcmp ("purecap", arg) && IS_C64) + return TRUE; + + return FALSE; +} + #endif /* OBJ_ELF */ /* Convert REGNAME to a DWARF-2 register number. */ @@ -7990,6 +8020,11 @@ tc_aarch64_regname_to_dw2regnum (char *regname) case REG_TYPE_FP_Q: return reg->number + 64; + case REG_TYPE_CA_N: + case REG_TYPE_CA_SP: + case REG_TYPE_CA_D: + return reg->number + 198; + default: break; } diff --git a/gas/config/tc-aarch64.h b/gas/config/tc-aarch64.h index 5b197d45451..cd9740c7e90 100644 --- a/gas/config/tc-aarch64.h +++ b/gas/config/tc-aarch64.h @@ -52,6 +52,7 @@ | (((n) >> 24) & 0xff)) struct fix; +struct fde_entry; struct aarch64_fix { @@ -87,15 +88,17 @@ enum pointer_auth_key { AARCH64_PAUTH_KEY_B }; +struct eh_entry_extras +{ + bfd_boolean c64; + enum pointer_auth_key pauth_key; +}; + /* The extra fields required by AArch64 in fde_entry and cie_entry. Currently only used to store the key used to sign the frame's return address. */ -#define tc_fde_entry_extras enum pointer_auth_key pauth_key; -#define tc_cie_entry_extras enum pointer_auth_key pauth_key; - -/* The extra initialisation steps needed by AArch64 in alloc_fde_entry. - Currently only used to initialise the key used to sign the return - address. */ -#define tc_fde_entry_init_extra(fde) fde->pauth_key = AARCH64_PAUTH_KEY_A; +#define tc_fde_entry_extras struct eh_entry_extras entry_extras; +#define tc_cie_entry_extras struct eh_entry_extras entry_extras; +#define tc_fde_entry_init_extra(fde) tc_aarch64_fde_entry_init_extra(fde); /* Extra checks required by AArch64 when outputting the current cie_entry. Currently only used to output a 'B' if the return address is signed with the @@ -103,20 +106,31 @@ enum pointer_auth_key { #define tc_output_cie_extra(cie) \ do \ { \ - if (cie->pauth_key == AARCH64_PAUTH_KEY_B) \ + if (cie->entry_extras.pauth_key == AARCH64_PAUTH_KEY_B) \ out_one ('B'); \ + if (cie->entry_extras.c64) \ + out_one ('C'); \ } \ while (0) /* Extra equivalence checks required by AArch64 when selecting the correct cie for some fde. Currently only used to check for quivalence between keys used - to sign ther return address. */ -#define tc_cie_fde_equivalent_extra(cie, fde) (cie->pauth_key == fde->pauth_key) + to sign ther return address and whether they are either both A64 or both + C64. */ +#define tc_cie_fde_equivalent_extra(cie, fde) \ + (cie->entry_extras.pauth_key == fde->entry_extras.pauth_key \ + && cie->entry_extras.c64 == fde->entry_extras.c64) /* The extra initialisation steps needed by AArch64 in select_cie_for_fde. Currently only used to initialise the key used to sign the return address. */ -#define tc_cie_entry_init_extra(cie, fde) cie->pauth_key = fde->pauth_key; +#define tc_cie_entry_init_extra(cie, fde) \ + do \ + { \ + cie->entry_extras.pauth_key = fde->entry_extras.pauth_key; \ + cie->entry_extras.c64 = fde->entry_extras.c64; \ + } \ + while (0); #define TC_FIX_TYPE struct aarch64_fix #define TC_INIT_FIX_DATA(FIX) { (FIX)->tc_fix_data.inst = NULL; \ @@ -246,6 +260,7 @@ struct aarch64_segment_info_type /* CFI hooks. */ #define tc_regname_to_dw2regnum tc_aarch64_regname_to_dw2regnum #define tc_cfi_frame_initial_instructions tc_aarch64_frame_initial_instructions +#define tc_cfi_startproc_exp tc_aarch64_cfi_startproc_exp extern void aarch64_after_parse_args (void); #define md_after_parse_args() aarch64_after_parse_args () @@ -282,6 +297,8 @@ extern void aarch64_init_frag (struct frag *, int); extern void aarch64_handle_align (struct frag *); extern int tc_aarch64_regname_to_dw2regnum (char *regname); extern void tc_aarch64_frame_initial_instructions (void); +extern bfd_boolean tc_aarch64_cfi_startproc_exp (const char *); +void tc_aarch64_fde_entry_init_extra(struct fde_entry *); #ifdef TE_PE diff --git a/gas/dw2gencfi.c b/gas/dw2gencfi.c index 8fc956ceba7..80024bf52b9 100644 --- a/gas/dw2gencfi.c +++ b/gas/dw2gencfi.c @@ -67,6 +67,10 @@ #define tc_cfi_frame_initial_instructions() ((void)0) #endif +#ifndef tc_cfi_startproc_exp +# define tc_cfi_startproc_exp() (FALSE) +#endif + #ifndef tc_cfi_startproc # define tc_cfi_startproc() ((void)0) #endif @@ -1297,7 +1301,8 @@ dot_cfi_startproc (int ignored ATTRIBUTE_UNUSED) simple = 1; restore_line_pointer (c); } - else + /* Custom arguments to .cfi_startproc. */ + else if (!tc_cfi_startproc_exp (name)) input_line_pointer = saved_ilp; } demand_empty_rest_of_line (); diff --git a/gas/testsuite/gas/aarch64/morello-eh.d b/gas/testsuite/gas/aarch64/morello-eh.d new file mode 100644 index 00000000000..26e45deab68 --- /dev/null +++ b/gas/testsuite/gas/aarch64/morello-eh.d @@ -0,0 +1,24 @@ +#objdump: --dwarf=frames +#... +Contents of the \.eh_frame section: +#... + Augmentation: "zR" +#... + Return address column: 30 + Augmentation data: 1b + DW_CFA_def_cfa: r31 \(sp\) ofs 0 +#... + DW_CFA_def_cfa: r31 \(sp\) ofs 32 + DW_CFA_offset: r30 \(x30\) at cfa-16 + DW_CFA_offset_extended: r231 \(ddc\) at cfa-32 +#... + Augmentation: "zRC" +#... + Return address column: 228 + Augmentation data: 1b + DW_CFA_def_cfa: r229 \(csp\) ofs 0 +#... + DW_CFA_def_cfa: r229 \(csp\) ofs 32 + DW_CFA_offset_extended: r228 \(c30\) at cfa-16 + DW_CFA_offset_extended: r231 \(ddc\) at cfa-32 +#... diff --git a/gas/testsuite/gas/aarch64/morello-eh.s b/gas/testsuite/gas/aarch64/morello-eh.s new file mode 100644 index 00000000000..245818db973 --- /dev/null +++ b/gas/testsuite/gas/aarch64/morello-eh.s @@ -0,0 +1,31 @@ + .text + .arch morello + .globl f1 + .type f1,@function +f1: + .cfi_startproc + mrs c29, ddc + sub csp, csp, #96 + stp c29, c30, [sp, #64] + add c29, csp, #64 + .cfi_def_cfa sp, 32 + .cfi_offset x30, -16 + .cfi_offset ddc, -32 + ret + .size f1, .-f1 + .cfi_endproc + + .arch morello+c64 + .globl f2 + .type f2,@function +f2: + .cfi_startproc purecap + mrs c29, ddc + sub csp, csp, #96 + stp c29, c30, [csp, #64] + add c29, csp, #64 + .cfi_def_cfa csp, 32 + .cfi_offset c30, -16 + .cfi_offset ddc, -32 + .size f2, .-f2 + .cfi_endproc