]> 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)
committerJohn Baldwin <jhb@FreeBSD.org>
Thu, 1 Sep 2022 22:53:21 +0000 (15:53 -0700)
- 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 a3b235ca5bb08478d7513535a5ba80f3b1837be4..0ad67e78c4370be761e6569d23c62958d2966eea 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 a8150d1ce91b25df12e2ce17650cbec597ca724e..a84a3a7c494767b38baccd06b8fc4d59626bc28d 100644 (file)
@@ -1431,6 +1431,8 @@ struct elf_backend_data
      (bfd *, struct bfd_link_info *, asection *);
   bool (*elf_backend_can_make_lsda_relative_eh_frame)
      (bfd *, struct bfd_link_info *, asection *);
+  bool (*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 2e22d0c92158da5a53fb9e6ef60954ab92272f99..498996c86b81f5f0967a993950d6806b1b6786c0 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 28dcea4a5bc576e38066a98b1ced64ff22c14bb2..5ce3d2205773a972178b422f7cf185a11f9fc494 100644 (file)
@@ -11030,6 +11030,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 bool
+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).  */
 
@@ -11185,6 +11193,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 964c38e0e1c5ccaacfd2e02c5cdc4c5e0904f8ee..b6e281cb9502b75e1a464e280d74302c67cfb38b 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
@@ -887,6 +890,7 @@ static const 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 e19333b8c91a1e2b75cdd5ed75d643c30f494f76..235d09878a0b50b3fb65ebc59d438870285348d0 100644 (file)
@@ -1,3 +1,7 @@
+2020-10-20  Siddhesh Poyarekar  <siddesh.poyarekar@arm.com>
+
+       * dwarf.c (dwarf_regnames_aarch64): Add capability registers.
+
 2022-04-01  John Baldwin  <jhb@FreeBSD.org>
 
        * readelf.c (get_freebsd_elfcore_note_type): Handle
index 15b3c81a1381c92d158635a91db90d7f188792b3..9bfe48f93add7180d4aba4e65b5756cc21a8041d 100644 (file)
@@ -8112,6 +8112,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 4f6339e14d9900ad1464b09f075bd04cd908bea0..f4470e7e25337f447f470e88048a46ed9e4747f1 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 2533f3488727b0645ce02e5369aff19ae33ad5d6..d57775561695260af06771f23fccaf03af0f32f1 100644 (file)
@@ -476,6 +476,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
@@ -2076,7 +2078,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
@@ -8883,8 +8885,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;
 }
+
+bool
+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.  */
@@ -8911,6 +8941,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 0b411f0076da6fd8afbf35b8e664f1372467b45f..9e68ed235f4b3c7a61e5331d242f3e480fcb8e23 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
+{
+  bool 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;        \
@@ -248,6 +262,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 ()
@@ -284,6 +299,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 bool tc_aarch64_cfi_startproc_exp (const char *);
+void tc_aarch64_fde_entry_init_extra(struct fde_entry *);
 
 #ifdef TE_PE
 
index 961a3b92188c340d9848919bc15b5bc73040ce43..863cc2abd96640df24de2a6ca8a2d89369901285 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
@@ -1296,7 +1300,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