]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
[Morello] Capability support for exception headers
authorSiddhesh Poyarekar <siddesh.poyarekar@arm.com>
Fri, 11 Sep 2020 03:48:11 +0000 (09:18 +0530)
committerLuis Machado <luis.machado@linaro.org>
Tue, 20 Oct 2020 18:04:23 +0000 (15:04 -0300)
- 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  <siddesh.poyarekar@arm.com>

* 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  <siddesh.poyarekar@arm.com>

* dwarf.c (dwarf_regnames_aarch64): Add capability registers.

gas/ChangeLog:

2020-10-20  Siddhesh Poyarekar  <siddesh.poyarekar@arm.com>

* 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.

13 files changed:
bfd/ChangeLog
bfd/elf-bfd.h
bfd/elf-eh-frame.c
bfd/elfnn-aarch64.c
bfd/elfxx-target.h
binutils/ChangeLog
binutils/dwarf.c
gas/ChangeLog
gas/config/tc-aarch64.c
gas/config/tc-aarch64.h
gas/dw2gencfi.c
gas/testsuite/gas/aarch64/morello-eh.d [new file with mode: 0644]
gas/testsuite/gas/aarch64/morello-eh.s [new file with mode: 0644]

index 54abe00f3105a0f022559f6df0a16399bd616ef6..e714ede5d336194445666d34dbf0a5fc8c262ace 100644 (file)
@@ -1,3 +1,17 @@
+2020-10-20  Siddhesh Poyarekar  <siddesh.poyarekar@arm.com>
+
+       * 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  <siddesh.poyarekar@arm.com>
 
        * elfnn-aarch64.c (STUB_ENTRY_NAME): Add format specifier for
index 98165af1335743835d5249cd174d15dc6d8c396b..f383cd8bf6eeae1e0a83b176cf067f02430aec09 100644 (file)
@@ -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,
index 7a129b00f8d78fecd8c450ef8aca564eea4a9485..54da9bec11f2ccbc2746f1c5da5dcaa3570a6481 100644 (file)
@@ -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)
index bd7da1610a785e561b520bb28e408f8b27c40030..f1a43e18e0e57a33dbc0638b34d149aed5b64e70 100644 (file)
@@ -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
index d527a604f0f521164afd97818ec8477661a2dded..ad8322e1596ab472a438590ae60398cf53dbb278 100644 (file)
 #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,
index b297de9667c382963a4ab8bb7149a4077bf991f9..635f9211a6f3dcc59909ff45d918b5b70715757e 100644 (file)
@@ -1,3 +1,7 @@
+2020-10-20  Siddhesh Poyarekar  <siddesh.poyarekar@arm.com>
+
+       * dwarf.c (dwarf_regnames_aarch64): Add capability registers.
+
 2020-10-20  Alan Modra  <amodra@gmail.com>
 
        * readelf.c: Delete whitespace at end of line throughout.
index e152b20438cc160e76d72dce9b64632aaabbc922..9db544232fe9be2dc334e43b0b8c7d118e756f88 100644 (file)
@@ -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
index dd8fd72b837d5c9d3d9bf4dede041175ae492155..91c9c9f5a7522dd6a038e0790b26db5c61f77f17 100644 (file)
@@ -1,3 +1,29 @@
+2020-10-20  Siddhesh Poyarekar  <siddesh.poyarekar@arm.com>
+
+       * 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  <siddesh.poyarekar@arm.com>
 
        * config/tc-aarch64.c (parse_operands): Choose C64 branch
index 4e63ce1594c02dbf32258b9e06af95615c1267fb..8cc4d673593a4c5a67c347b2318891baa8af3a10 100644 (file)
@@ -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;
     }
index 5b197d454518bd7e2416a5b0ae86b4d0b034896e..cd9740c7e90b31a8cf8595b0329ea8c1977ba1e1 100644 (file)
@@ -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
 
index 8fc956ceba727119c1d385ead32073468202b72d..80024bf52b9f6666c5c1467ca4622543c0014f50 100644 (file)
 #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 (file)
index 0000000..26e45de
--- /dev/null
@@ -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 (file)
index 0000000..245818d
--- /dev/null
@@ -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