public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [Patch] Gas support for MIPS Compact EH
@ 2013-05-31 18:56 Moore, Catherine
  2013-06-01 11:07 ` Richard Sandiford
  0 siblings, 1 reply; 31+ messages in thread
From: Moore, Catherine @ 2013-05-31 18:56 UTC (permalink / raw)
  To: rdsandiford; +Cc: Moore, Catherine, binutils

[-- Attachment #1: Type: text/plain, Size: 322 bytes --]

Hi Richard,
These are the remaining assembler patches required to support the Compact EH format.  Will you please take a look and let me if these are ready to be committed?
Thanks,
Catherine

MIPS Compact Exception Handling Specification:
https://github.com/MentorEmbedded/cxx-abi/blob/master/MIPSCompactEH.pdf



[-- Attachment #2: gas.cl --]
[-- Type: application/octet-stream, Size: 1308 bytes --]

2013-05-13 Paul Brook <paul@codesourcery.com>

	* doc/as.texinfo: Document .cfi_sections .eh_frame_header and
	.cfi_inline_lsda.
	* dw2gencfi.c (EH_FRAME_LINKONCE): Define.
	(last_fde): New variable.
	(tc_cfi_emit_expr, tc_cfi_special_encoding): Provide defaults.
	(compact_eh): New variable.
	(FRAME_NAME): Use .gnu.extab for compact frames.
	(get_debugseg_name): Suffix all EH sections except for .text.
	(is_now_linkonce_segment): Do not squich regular compact EH
	sections together.
	(make_debug_seg): Use tc_make_debug_seg.
	(cie_entry): Add fde_encoding.
	(cfi_pseudo_table): Add "cfi_inline_lsda".
	(dot_cfi_personality, dot_cfi_lsda): Use tc_cfi_special_encoding.
	(dot_cfi_sections): Accept .eh_frame_entry.
	(dot_cfi_startproc): Set last_fde.  Call tc_cfi_endproc for compact EH.
	(get_cfi_seg): Move higher in file.
	(output_compact_unwind_data, dot_cfi_inline_lsda): New functions.
	(output_cie): Use tc_cfi_special_encoding and
	DWARF2_FDE_RELOC_ENCODING.
	(output_fde): Use tc_cfi_special_encoding.
	(cfi_emit_eh_header, output_eh_header): New functions.
	(cfi_finish): Handle compact EH frame generation.
	* dw2gencfi.h (SUPPORT_COMPACT_EH, MULTIPLE_FRAME_SECTIONS): Define.
	(EH_COMPACT_*): Define.
	(fde_entry): Add eh_header_type, eh_data_size, eh_data, eh_loc.

[-- Attachment #3: gas.patch --]
[-- Type: application/octet-stream, Size: 22979 bytes --]

Index: doc/as.texinfo
===================================================================
RCS file: /cvs/src/src/gas/doc/as.texinfo,v
retrieving revision 1.266
diff -p -u -r1.266 as.texinfo
--- doc/as.texinfo	29 Apr 2013 13:38:58 -0000	1.266
+++ doc/as.texinfo	31 May 2013 17:24:20 -0000
@@ -4479,6 +4479,9 @@ if @var{section_list} is @code{.debug_fr
 To emit both use @code{.eh_frame, .debug_frame}.  The default if this
 directive is not used is @code{.cfi_sections .eh_frame}.
 
+On targets that support compact unwinding tables these can be generated
+by specifying @code{.eh_frame_header} instead of @code{.eh_frame}.
+
 @section @code{.cfi_startproc [simple]}
 @cindex @code{cfi_startproc} directive
 @code{.cfi_startproc} is used at the beginning of each function that
@@ -4514,6 +4517,23 @@ argument is not present, otherwise secon
 or a symbol name.  The default after @code{.cfi_startproc} is @code{.cfi_lsda 0xff},
 no LSDA.
 
+@section @code{.cfi_inline_lsda} [@var{align}]
+@code{.cfi_inline_lsda} marks the start of a LSDA data section and
+switches to the corresponding @code{.gnu.extab} section.
+It must be preceded by a CFI block containing a @code{.cfi_lsda} directive and
+is only valid when generating compact EH frames (i.e.
+with @code{.cfi_sections eh_frame_entry}.
+
+If a compact encoding is being used then the table header and unwinding
+opcodes will be generated at this point, so that they are immediately
+followed by the LSDA data.  The symbol referenced by the @code{.cfi_lsda}
+directive should still be defined in case a fallback FDE based encoding
+is used.
+
+The optional @var{align} argument specifies the alignment required.
+The alignment is specified as a power of two, as with the
+@code{.p2align} directive.
+
 @section @code{.cfi_def_cfa @var{register}, @var{offset}}
 @code{.cfi_def_cfa} defines a rule for computing CFA as: @i{take
 address from @var{register} and add @var{offset} to it}.

Index: dw2gencfi.c
===================================================================
RCS file: /cvs/src/src/gas/dw2gencfi.c,v
retrieving revision 1.58
diff -p -u -r1.58 dw2gencfi.c
--- dw2gencfi.c	10 Jan 2013 19:51:54 -0000	1.58
+++ dw2gencfi.c	31 May 2013 17:24:20 -0000
@@ -76,6 +76,8 @@
 # define tc_cfi_endproc(fde) ((void) (fde))
 #endif
 
+#define EH_FRAME_LINKONCE (SUPPORT_FRAME_LINKONCE || compact_eh)
+
 #ifndef DWARF2_FORMAT
 #define DWARF2_FORMAT(SEC) dwarf2_format_32bit
 #endif
@@ -84,7 +86,7 @@
 #define DWARF2_ADDR_SIZE(bfd) (bfd_arch_bits_per_address (bfd) / 8)
 #endif
 
-#if SUPPORT_FRAME_LINKONCE
+#if MULTIPLE_FRAME_SECTIONS
 #define CUR_SEG(structp) structp->cur_seg
 #define SET_CUR_SEG(structp, seg) structp->cur_seg = seg
 #define HANDLED(structp) structp->handled
@@ -96,6 +98,11 @@
 #define SET_HANDLED(structp, val) (void) (0 && val)
 #endif
 
+#ifndef tc_cfi_special_encoding
+#define tc_cfi_emit_expr(exp, enc) (void) 0
+#define tc_cfi_special_encoding(e) 0
+#endif
+
 /* Private segment collection list.  */
 struct dwcfi_seg_list
 {
@@ -104,7 +111,11 @@ struct dwcfi_seg_list
   char * seg_name;
 };
 
-#define FRAME_NAME ".eh_frame"
+#ifdef SUPPORT_COMPACT_EH
+static bfd_boolean compact_eh;
+#else
+#define compact_eh 0
+#endif
 
 static struct hash_control *dwcfi_hash;
 
@@ -129,7 +140,12 @@ get_debugseg_name (segT seg, const char 
       dot = strchr (name + 1, '.');
 
       if (!dollar && !dot)
-	name = "";
+	{
+	  if (compact_eh && strcmp (name, ".text") != 0)
+	    return concat (base_name, ".", name, NULL);
+
+	  name = "";
+	}
       else if (!dollar)
 	name = dot;
       else if (!dot)
@@ -161,6 +177,9 @@ alloc_debugseg_item (segT seg, int subse
 static segT
 is_now_linkonce_segment (void)
 {
+  if (compact_eh)
+    return now_seg;
+
   if ((bfd_get_section_flags (stdoutput, now_seg)
        & (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD
 	  | SEC_LINK_DUPLICATES_ONE_ONLY | SEC_LINK_DUPLICATES_SAME_SIZE
@@ -180,7 +199,11 @@ make_debug_seg (segT cseg, char *name, i
   segT r;
   flagword flags;
 
+#ifdef tc_make_debug_seg
+  r = tc_make_debug_seg (cseg, name);
+#else
   r = subseg_new (name, 0);
+#endif
 
   /* Check if code segment is marked as linked once.  */
   if (!cseg)
@@ -273,12 +296,13 @@ struct cfi_escape_data
 struct cie_entry
 {
   struct cie_entry *next;
-#if SUPPORT_FRAME_LINKONCE
+#if MULTIPLE_FRAME_SECTIONS
   segT cur_seg;
 #endif
   symbolS *start_address;
   unsigned int return_column;
   unsigned int signal_frame;
+  unsigned char fde_encoding;
   unsigned char per_encoding;
   unsigned char lsda_encoding;
   expressionS personality;
@@ -551,6 +575,7 @@ static void dot_cfi_endproc (int);
 static void dot_cfi_personality (int);
 static void dot_cfi_lsda (int);
 static void dot_cfi_val_encoded_addr (int);
+static void dot_cfi_inline_lsda (int);
 
 const pseudo_typeS cfi_pseudo_table[] =
   {
@@ -576,6 +601,7 @@ const pseudo_typeS cfi_pseudo_table[] =
     { "cfi_personality", dot_cfi_personality, 0 },
     { "cfi_lsda", dot_cfi_lsda, 0 },
     { "cfi_val_encoded_addr", dot_cfi_val_encoded_addr, 0 },
+    { "cfi_inline_lsda", dot_cfi_inline_lsda, 0 },
     { NULL, NULL, 0 }
   };
 
@@ -833,14 +859,15 @@ dot_cfi_personality (int ignored ATTRIBU
     }
 
   if ((encoding & 0xff) != encoding
-      || ((encoding & 0x70) != 0
+      || ((((encoding & 0x70) != 0
 #if CFI_DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr
-	  && (encoding & 0x70) != DW_EH_PE_pcrel
+	   && (encoding & 0x70) != DW_EH_PE_pcrel
 #endif
 	  )
 	 /* leb128 can be handled, but does something actually need it?  */
-      || (encoding & 7) == DW_EH_PE_uleb128
-      || (encoding & 7) > DW_EH_PE_udata8)
+	   || (encoding & 7) == DW_EH_PE_uleb128
+	   || (encoding & 7) > DW_EH_PE_udata8)
+	&& !tc_cfi_special_encoding (encoding)))
     {
       as_bad (_("invalid or unsupported encoding in .cfi_personality"));
       ignore_rest_of_line ();
@@ -903,14 +930,15 @@ dot_cfi_lsda (int ignored ATTRIBUTE_UNUS
     }
 
   if ((encoding & 0xff) != encoding
-      || ((encoding & 0x70) != 0
+      || ((((encoding & 0x70) != 0
 #if CFI_DIFF_LSDA_OK || defined tc_cfi_emit_pcrel_expr
-	  && (encoding & 0x70) != DW_EH_PE_pcrel
+	    && (encoding & 0x70) != DW_EH_PE_pcrel
 #endif
-	  )
+	   )
 	 /* leb128 can be handled, but does something actually need it?  */
-      || (encoding & 7) == DW_EH_PE_uleb128
-      || (encoding & 7) > DW_EH_PE_udata8)
+	   || (encoding & 7) == DW_EH_PE_uleb128
+	   || (encoding & 7) > DW_EH_PE_udata8)
+	  && !tc_cfi_special_encoding (encoding)))
     {
       as_bad (_("invalid or unsupported encoding in .cfi_lsda"));
       ignore_rest_of_line ();
@@ -1022,6 +1050,8 @@ dot_cfi_val_encoded_addr (int ignored AT
 #define CFI_EMIT_debug_frame	(1 << 1)
 #define CFI_EMIT_target		(1 << 2)
 static int cfi_sections = CFI_EMIT_eh_frame;
+static int all_cfi_sections = 0;
+static struct fde_entry *last_fde;
 
 static void
 dot_cfi_sections (int ignored ATTRIBUTE_UNUSED)
@@ -1042,6 +1072,13 @@ dot_cfi_sections (int ignored ATTRIBUTE_
 	  sections |= CFI_EMIT_eh_frame;
 	else if (strncmp (name, ".debug_frame", sizeof ".debug_frame") == 0)
 	  sections |= CFI_EMIT_debug_frame;
+#if SUPPORT_COMPACT_EH
+	else if (strncmp (name, ".eh_frame_entry", sizeof ".eh_frame_entry") == 0)
+	  {
+	    compact_eh = TRUE;
+	    sections |= CFI_EMIT_eh_frame | CFI_EMIT_target;
+	  }
+#endif
 #ifdef tc_cfi_section_name
 	else if (strcmp (name, tc_cfi_section_name) == 0)
 	  sections |= CFI_EMIT_target;
@@ -1105,6 +1142,8 @@ dot_cfi_startproc (int ignored ATTRIBUTE
     }
   demand_empty_rest_of_line ();
 
+  all_cfi_sections |= cfi_sections;
+  frchain_now->frch_cfi_data->cur_fde_data->sections = cfi_sections;
   frchain_now->frch_cfi_data->cur_cfa_offset = 0;
   if (!simple)
     tc_cfi_frame_initial_instructions ();
@@ -1116,8 +1155,6 @@ dot_cfi_startproc (int ignored ATTRIBUTE
 static void
 dot_cfi_endproc (int ignored ATTRIBUTE_UNUSED)
 {
-  struct fde_entry *fde;
-
   if (frchain_now->frch_cfi_data == NULL)
     {
       as_bad (_(".cfi_endproc without corresponding .cfi_startproc"));
@@ -1125,16 +1162,147 @@ dot_cfi_endproc (int ignored ATTRIBUTE_U
       return;
     }
 
-  fde = frchain_now->frch_cfi_data->cur_fde_data;
+  last_fde = frchain_now->frch_cfi_data->cur_fde_data;
 
   cfi_end_fde (symbol_temp_new_now ());
 
   demand_empty_rest_of_line ();
 
-  if ((cfi_sections & CFI_EMIT_target) != 0)
-    tc_cfi_endproc (fde);
+  if ((cfi_sections & CFI_EMIT_target) != 0
+      || (compact_eh && (cfi_sections & CFI_EMIT_eh_frame) != 0))
+    tc_cfi_endproc (last_fde);
 }
 
+static segT
+get_cfi_seg (segT cseg, const char *base, flagword flags, int align)
+{
+  if (SUPPORT_FRAME_LINKONCE || ((flags & SEC_DEBUGGING) == 0 && compact_eh))
+    {
+      struct dwcfi_seg_list *l;
+
+      l = dwcfi_hash_find_or_make (cseg, base, flags);
+
+      cseg = l->seg;
+      subseg_set (cseg, l->subseg);
+    }
+  else
+    {
+      cseg = subseg_new (base, 0);
+      bfd_set_section_flags (stdoutput, cseg, flags);
+    }
+  record_alignment (cseg, align);
+  return cseg;
+}
+
+#if SUPPORT_COMPACT_EH
+static void
+output_compact_unwind_data (struct fde_entry *fde, int align)
+{
+  int data_size = fde->eh_data_size + 2;
+  int amask;
+  char *p;
+  char *end;
+
+  fde->eh_loc = symbol_temp_new_now ();
+  if (fde->per_encoding != DW_EH_PE_omit)
+    data_size += 4;
+
+  amask = (1 << align) - 1;
+  data_size = (data_size + amask) & ~amask;
+  p = frag_more (data_size);
+  end = p + data_size - 1;
+  if (fde->per_encoding != DW_EH_PE_omit)
+    {
+      *(p++) = 0;
+      md_number_to_chars (p, 0, 4);
+      tc_cfi_fix_eh_ref (p, &fde->personality);
+      p += 4;
+    }
+  else
+    {
+      *(p++) = 1;
+    }
+
+  memcpy (p, fde->eh_data, fde->eh_data_size);
+  p += fde->eh_data_size;
+  while (p != end)
+    *(p++) = 0x5f;
+
+  *(p++) = 0x5c;
+  fde->eh_header_type = EH_COMPACT_OUTLINE_DONE;
+}
+
+static void
+dot_cfi_inline_lsda (int ignored ATTRIBUTE_UNUSED)
+{
+  segT cfi_seg, ccseg;
+  int align;
+  long max_alignment = 28;
+
+  if (!last_fde)
+    {
+      as_bad (_("unexpected .cfi_inline_lsda"));
+      ignore_rest_of_line ();
+      return;
+    }
+
+  if (!compact_eh
+      || (last_fde->sections & CFI_EMIT_eh_frame) == 0
+      || (last_fde->eh_header_type != EH_COMPACT_LEGACY
+	  && last_fde->eh_header_type != EH_COMPACT_HAS_LSDA))
+
+    {
+      as_bad (_(".cfi_inline_lsda not valid for this frame"));
+      ignore_rest_of_line ();
+      return;
+    }
+
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
+
+  align = get_absolute_expression ();
+  if (align > max_alignment)
+    {
+      align = max_alignment;
+      as_bad (_("Alignment too large: %d. assumed."), align);
+    }
+  else if (align < 0)
+    {
+      as_warn (_("Alignment negative: 0 assumed."));
+      align = 0;
+    }
+
+  demand_empty_rest_of_line ();
+  ccseg = CUR_SEG (last_fde);
+  /* Open .gnu_extab section.  */
+  cfi_seg = get_cfi_seg (ccseg, ".gnu_extab",
+			 (SEC_ALLOC | SEC_LOAD | SEC_DATA
+			  | DWARF2_EH_FRAME_READ_ONLY),
+			 1);
+#ifdef md_fix_up_eh_frame
+  md_fix_up_eh_frame (cfi_seg);
+#else
+  (void) cfi_seg;
+#endif
+
+  frag_align (align, 0, 0);
+  record_alignment (now_seg, align);
+  if (last_fde->eh_header_type == EH_COMPACT_HAS_LSDA)
+    output_compact_unwind_data (last_fde, align);
+
+  last_fde = NULL;
+
+  return;
+}
+#else /* !SUPPORT_COMPACT_EH */
+static void
+dot_cfi_inline_lsda (int ignored ATTRIBUTE_UNUSED)
+{
+  as_bad (_(".cfi_inline_lsda is not supported for this target"));
+  ignore_rest_of_line ();
+}
+#endif
 \f
 /* Emit a single byte into the current segment.  */
 
@@ -1479,7 +1647,11 @@ output_cie (struct cie_entry *cie, bfd_b
 	  offsetT size = encoding_size (cie->per_encoding);
 	  out_one (cie->per_encoding);
 	  exp = cie->personality;
-	  if ((cie->per_encoding & 0x70) == DW_EH_PE_pcrel)
+	  if (tc_cfi_special_encoding (cie->per_encoding))
+	    {
+	      tc_cfi_emit_expr (&exp, cie->per_encoding);
+	    }
+	  else if ((cie->per_encoding & 0x70) == DW_EH_PE_pcrel)
 	    {
 #if CFI_DIFF_EXPR_OK
 	      exp.X_op = O_subtract;
@@ -1516,6 +1688,11 @@ output_cie (struct cie_entry *cie, bfd_b
 #if CFI_DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr
   enc |= DW_EH_PE_pcrel;
 #endif
+#ifdef DWARF2_FDE_RELOC_ENCODING
+  /* Allow target to override encoding.  */
+  enc = DWARF2_FDE_RELOC_ENCODING (enc);
+#endif
+  cie->fde_encoding = enc;
   if (eh_frame)
     out_one (enc);
 
@@ -1578,21 +1755,31 @@ output_fde (struct fde_entry *fde, struc
 
   if (eh_frame)
     {
-      exp.X_op = O_subtract;
-      exp.X_add_number = 0;
+      if (tc_cfi_special_encoding (cie->fde_encoding))
+	{
+	  exp.X_op = O_symbol;
+	  exp.X_add_symbol = fde->start_address;
+	  tc_cfi_emit_expr (&exp, cie->fde_encoding);
+	}
+      else
+	{
+	  exp.X_op = O_subtract;
+	  exp.X_add_number = 0;
 #if CFI_DIFF_EXPR_OK
-      exp.X_add_symbol = fde->start_address;
-      exp.X_op_symbol = symbol_temp_new_now ();
-      emit_expr (&exp, DWARF2_FDE_RELOC_SIZE);	/* Code offset.  */
+	  exp.X_add_symbol = fde->start_address;
+	  exp.X_op_symbol = symbol_temp_new_now ();
+	  emit_expr (&exp, DWARF2_FDE_RELOC_SIZE);	/* Code offset.  */
 #else
-      exp.X_op = O_symbol;
-      exp.X_add_symbol = fde->start_address;
-#ifdef tc_cfi_emit_pcrel_expr
-      tc_cfi_emit_pcrel_expr (&exp, DWARF2_FDE_RELOC_SIZE);	 /* Code offset.  */
+	  exp.X_op = O_symbol;
+	  exp.X_add_symbol = fde->start_address;
+
+#if defined(tc_cfi_emit_pcrel_expr)
+	  tc_cfi_emit_pcrel_expr (&exp, DWARF2_FDE_RELOC_SIZE);	 /* Code offset.  */
 #else
-      emit_expr (&exp, DWARF2_FDE_RELOC_SIZE);	/* Code offset.  */
+	  emit_expr (&exp, DWARF2_FDE_RELOC_SIZE);	/* Code offset.  */
 #endif
 #endif
+	}
       addr_size = DWARF2_FDE_RELOC_SIZE;
     }
   else
@@ -1617,7 +1804,11 @@ output_fde (struct fde_entry *fde, struc
   if (fde->lsda_encoding != DW_EH_PE_omit)
     {
       exp = fde->lsda;
-      if ((fde->lsda_encoding & 0x70) == DW_EH_PE_pcrel)
+      if (tc_cfi_special_encoding (cie->lsda_encoding))
+	{
+	  tc_cfi_emit_expr (&exp, cie->lsda_encoding);
+	}
+      else if ((fde->lsda_encoding & 0x70) == DW_EH_PE_pcrel)
 	{
 #if CFI_DIFF_LSDA_OK
 	  exp.X_op = O_subtract;
@@ -1821,26 +2012,66 @@ cfi_change_reg_numbers (struct cfi_insn_
 #define cfi_change_reg_numbers(insn, cseg) do { } while (0)
 #endif
 
-static segT
-get_cfi_seg (segT cseg, const char *base, flagword flags, int align)
+#if SUPPORT_COMPACT_EH
+static void
+cfi_emit_eh_header (symbolS *sym, bfd_vma addend)
 {
-  if (SUPPORT_FRAME_LINKONCE)
+  expressionS exp;
+
+  exp.X_add_number = addend;
+  exp.X_add_symbol = sym;
+  if (tc_cfi_special_encoding (DW_EH_PE_sdata4 | DW_EH_PE_pcrel))
     {
-      struct dwcfi_seg_list *l;
+      tc_cfi_emit_expr (&exp, DW_EH_PE_sdata4 | DW_EH_PE_pcrel);
+    }
+  else
+    {
+#if CFI_DIFF_EXPR_OK
+      exp.X_op = O_subtract;
+      exp.X_op_symbol = symbol_temp_new_now ();
+      emit_expr (&exp, 4);	/* Code offset.  */
+#elif defined (tc_cfi_emit_pcrel_expr)
+      exp.X_op = O_symbol;
+      tc_cfi_emit_pcrel_expr (&exp, 4);	 /* Code offset.  */
+#else
+      abort();
+#endif
+    }
+}
 
-      l = dwcfi_hash_find_or_make (cseg, base, flags);
+static void
+output_eh_header (struct fde_entry *fde)
+{
+  char *p;
+  bfd_vma addend;
 
-      cseg = l->seg;
-      subseg_set (cseg, l->subseg);
+  if (fde->eh_header_type == EH_COMPACT_INLINE)
+    addend = 0;
+  else
+    addend = 1;
+
+  cfi_emit_eh_header (fde->start_address, addend);
+
+  if (fde->eh_header_type == EH_COMPACT_INLINE)
+    {
+      p = frag_more (4);
+      /* Inline entries always use PR1.  */
+      *(p++) = 1;
+      memcpy(p, fde->eh_data, 3);
     }
   else
     {
-      cseg = subseg_new (base, 0);
-      bfd_set_section_flags (stdoutput, cseg, flags);
+      if (fde->eh_header_type == EH_COMPACT_LEGACY)
+	addend = 1;
+      else if (fde->eh_header_type == EH_COMPACT_OUTLINE
+	       || fde->eh_header_type == EH_COMPACT_OUTLINE_DONE)
+	addend = 0;
+      else
+	abort ();
+      cfi_emit_eh_header (fde->eh_loc, addend);
     }
-  record_alignment (cseg, align);
-  return cseg;
 }
+#endif
 
 void
 cfi_finish (void)
@@ -1854,13 +2085,13 @@ cfi_finish (void)
   if (all_fde_data == 0)
     return;
 
-  if ((cfi_sections & CFI_EMIT_eh_frame) != 0)
+  if ((all_cfi_sections & CFI_EMIT_eh_frame) != 0)
     {
       /* Make sure check_eh_frame doesn't do anything with our output.  */
       save_flag_traditional_format = flag_traditional_format;
       flag_traditional_format = 1;
 
-      if (!SUPPORT_FRAME_LINKONCE)
+      if (!EH_FRAME_LINKONCE)
 	{
 	  /* Open .eh_frame section.  */
 	  cfi_seg = get_cfi_seg (NULL, ".eh_frame",
@@ -1888,7 +2119,17 @@ cfi_finish (void)
 
 	  for (fde = all_fde_data; fde ; fde = fde->next)
 	    {
-	      if (SUPPORT_FRAME_LINKONCE)
+	      if ((fde->sections & CFI_EMIT_eh_frame) == 0)
+		continue;
+
+#if SUPPORT_COMPACT_EH
+	      if (fde->eh_header_type == EH_COMPACT_HAS_LSDA)
+		fde->eh_header_type = EH_COMPACT_LEGACY;
+
+	      if (fde->eh_header_type != EH_COMPACT_LEGACY)
+		continue;
+#endif
+	      if (EH_FRAME_LINKONCE)
 		{
 		  if (HANDLED (fde))
 		    continue;
@@ -1922,20 +2163,111 @@ cfi_finish (void)
 		}
 
 	      cie = select_cie_for_fde (fde, TRUE, &first, 2);
+	      fde->eh_loc = symbol_temp_new_now ();
 	      output_fde (fde, cie, TRUE, first,
 			  fde->next == NULL ? EH_FRAME_ALIGNMENT : 2);
 	    }
 	}
-      while (SUPPORT_FRAME_LINKONCE && seek_next_seg == 2);
+      while (EH_FRAME_LINKONCE && seek_next_seg == 2);
 
-      if (SUPPORT_FRAME_LINKONCE)
+      if (EH_FRAME_LINKONCE)
 	for (fde = all_fde_data; fde ; fde = fde->next)
 	  SET_HANDLED (fde, 0);
 
+#if SUPPORT_COMPACT_EH
+      if (compact_eh)
+	{
+	  /* Create remaining out of line table entries.  */
+	  do
+	    {
+	      ccseg = NULL;
+	      seek_next_seg = 0;
+
+	      for (fde = all_fde_data; fde ; fde = fde->next)
+		{
+		  if ((fde->sections & CFI_EMIT_eh_frame) == 0)
+		    continue;
+
+		  if (fde->eh_header_type != EH_COMPACT_OUTLINE)
+		    continue;
+		  if (HANDLED (fde))
+		    continue;
+		  if (seek_next_seg && CUR_SEG (fde) != ccseg)
+		    {
+		      seek_next_seg = 2;
+		      continue;
+		    }
+		  if (!seek_next_seg)
+		    {
+		      ccseg = CUR_SEG (fde);
+		      /* Open .eh_frame section.  */
+		      cfi_seg = get_cfi_seg (ccseg, ".gnu_extab",
+					     (SEC_ALLOC | SEC_LOAD | SEC_DATA
+					      | DWARF2_EH_FRAME_READ_ONLY),
+					     1);
+#ifdef md_fix_up_eh_frame
+		      md_fix_up_eh_frame (cfi_seg);
+#else
+		      (void) cfi_seg;
+#endif
+		      seek_next_seg = 1;
+		    }
+		  SET_HANDLED (fde, 1);
+
+		  frag_align (1, 0, 0);
+		  record_alignment (now_seg, 1);
+		  output_compact_unwind_data (fde, 1);
+		}
+	    }
+	  while (EH_FRAME_LINKONCE && seek_next_seg == 2);
+
+	  for (fde = all_fde_data; fde ; fde = fde->next)
+	    SET_HANDLED (fde, 0);
+
+	  /* Create index table fragments.  */
+	  do
+	    {
+	      ccseg = NULL;
+	      seek_next_seg = 0;
+
+	      for (fde = all_fde_data; fde ; fde = fde->next)
+		{
+		  if ((fde->sections & CFI_EMIT_eh_frame) == 0)
+		    continue;
+
+		  if (HANDLED (fde))
+		    continue;
+		  if (seek_next_seg && CUR_SEG (fde) != ccseg)
+		    {
+		      seek_next_seg = 2;
+		      continue;
+		    }
+		  if (!seek_next_seg)
+		    {
+		      ccseg = CUR_SEG (fde);
+		      /* Open .eh_frame_entry section.  */
+		      cfi_seg = get_cfi_seg (ccseg, ".eh_frame_entry",
+					     (SEC_ALLOC | SEC_LOAD | SEC_DATA
+					      | DWARF2_EH_FRAME_READ_ONLY),
+					     2);
+		      seek_next_seg = 1;
+		    }
+		  SET_HANDLED (fde, 1);
+
+		  output_eh_header (fde);
+		}
+	    }
+	  while (seek_next_seg == 2);
+
+	  for (fde = all_fde_data; fde ; fde = fde->next)
+	    SET_HANDLED (fde, 0);
+	}
+#endif /* SUPPORT_COMPACT_EH */
+
       flag_traditional_format = save_flag_traditional_format;
     }
 
-  if ((cfi_sections & CFI_EMIT_debug_frame) != 0)
+  if ((all_cfi_sections & CFI_EMIT_debug_frame) != 0)
     {
       int alignment = ffs (DWARF2_ADDR_SIZE (stdoutput)) - 1;
 
@@ -1958,6 +2290,9 @@ cfi_finish (void)
 
 	  for (fde = all_fde_data; fde ; fde = fde->next)
 	    {
+	      if ((fde->sections & CFI_EMIT_debug_frame) == 0)
+		continue;
+
 	      if (SUPPORT_FRAME_LINKONCE)
 		{
 		  if (HANDLED (fde))
@@ -2034,6 +2369,7 @@ const pseudo_typeS cfi_pseudo_table[] =
     { "cfi_personality", dot_cfi_dummy, 0 },
     { "cfi_lsda", dot_cfi_dummy, 0 },
     { "cfi_val_encoded_addr", dot_cfi_dummy, 0 },
+    { "cfi_inline_lsda", dot_cfi_dummy, 0 },
     { NULL, NULL, 0 }
   };
 
Index: dw2gencfi.h
===================================================================
RCS file: /cvs/src/src/gas/dw2gencfi.h,v
retrieving revision 1.10
diff -p -u -r1.10 dw2gencfi.h
--- dw2gencfi.h	7 Aug 2011 16:32:20 -0000	1.10
+++ dw2gencfi.h	31 May 2013 17:24:20 -0000
@@ -57,10 +57,18 @@ extern void cfi_add_CFA_restore_state (v
 #define SUPPORT_FRAME_LINKONCE 0
 #endif
 
+#ifdef tc_cfi_fix_eh_ref
+#define SUPPORT_COMPACT_EH 1
+#else
+#define SUPPORT_COMPACT_EH 0
+#endif
+
+#define MULTIPLE_FRAME_SECTIONS (SUPPORT_FRAME_LINKONCE || SUPPORT_COMPACT_EH)
+
 struct cfi_insn_data
 {
   struct cfi_insn_data *next;
-#if SUPPORT_FRAME_LINKONCE
+#if MULTIPLE_FRAME_SECTIONS
   segT cur_seg;
 #endif
   int insn;
@@ -97,10 +105,19 @@ struct cfi_insn_data
   } u;
 };
 
+enum {
+    EH_COMPACT_LEGACY,
+    EH_COMPACT_INLINE,
+    EH_COMPACT_OUTLINE,
+    EH_COMPACT_OUTLINE_DONE,
+    /* Outline if .cfi_inline_lsda used, otherwise legacy FDE.  */
+    EH_COMPACT_HAS_LSDA
+};
+
 struct fde_entry
 {
   struct fde_entry *next;
-#if SUPPORT_FRAME_LINKONCE
+#if MULTIPLE_FRAME_SECTIONS
   segT cur_seg;
 #endif
   symbolS *start_address;
@@ -113,9 +130,16 @@ struct fde_entry
   expressionS lsda;
   unsigned int return_column;
   unsigned int signal_frame;
-#if SUPPORT_FRAME_LINKONCE
+#if MULTIPLE_FRAME_SECTIONS
   int handled;
 #endif
+  int eh_header_type;
+  /* Compact unwinding opcodes, not including the PR byte or LSDA.  */
+  int eh_data_size;
+  bfd_byte *eh_data;
+  /* For out of line tables and FDEs.  */
+  symbolS *eh_loc;
+  int sections;
 };
 
 /* The list of all FDEs that have been collected.  */

[-- Attachment #4: gas-mips.cl --]
[-- Type: application/octet-stream, Size: 394 bytes --]

	* config/tc-mips.c (md_apply_fix): Handle BFD_RELOC_NONE.
	(mips_make_debug_seg): New function.
	(mips_unwind_reg_from_dwarf, mips_cfi_endproc, mips_cfi_fix_eh_ref,
	mips_cfi_emit_expr): New functions.
	* config/tc-mips.h (DWARF2_FDE_RELOC_SIZE): Use compact_eh.
	(DWARF2_FDE_RELOC_ENCODING): Define.
	(tc_make_debug_seg, tc_cfi_endproc, tc_cfi_emit_expr,
	tc_cfi_fix_eh_ref): Define.

[-- Attachment #5: gas-mips.patch --]
[-- Type: application/octet-stream, Size: 8841 bytes --]

Index: config/tc-mips.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-mips.c,v
retrieving revision 1.536
diff -p -u -r1.536 tc-mips.c
--- config/tc-mips.c	31 May 2013 17:04:52 -0000	1.536
+++ config/tc-mips.c	31 May 2013 17:24:20 -0000
@@ -15712,7 +15712,8 @@ md_apply_fix (fixS *fixP, valueT *valP, 
 	      || fixP->fx_r_type == BFD_RELOC_MICROMIPS_SUB
 	      || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
 	      || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
-	      || fixP->fx_r_type == BFD_RELOC_MIPS_TLS_DTPREL64);
+	      || fixP->fx_r_type == BFD_RELOC_MIPS_TLS_DTPREL64
+	      || fixP->fx_r_type == BFD_RELOC_NONE);
 
   buf = fixP->fx_frag->fr_literal + fixP->fx_where;
 
@@ -15951,6 +15952,7 @@ md_apply_fix (fixS *fixP, valueT *valP, 
         S_SET_WEAK (fixP->fx_addsy);
       break;
 
+    case BFD_RELOC_NONE:
     case BFD_RELOC_VTABLE_ENTRY:
       fixP->fx_done = 0;
       break;
@@ -19793,3 +19795,289 @@ tc_mips_regname_to_dw2regnum (char *regn
 
   return regnum;
 }
+
+#if defined (OBJ_ELF)
+segT
+mips_make_debug_seg (segT cseg, char *name)
+{
+  const char *group_name = NULL;
+  int linkonce;
+  int flags = 0;
+
+  if (cseg && (cseg->flags & SEC_LINK_ONCE) != 0)
+    {
+      group_name = elf_group_name (cseg);
+      if (group_name == NULL)
+	{
+	  as_bad (_("Group section `%s' has no group signature"),
+		  segment_name (cseg));
+	}
+      flags |= SHF_GROUP;
+      linkonce = 1;
+    }
+  obj_elf_change_section (name, SHT_PROGBITS, flags, 0, group_name, linkonce, 0);
+  return now_seg;
+}
+
+/* TODO: Can also save float regs.  */
+#define MIPS_NUM_UNWIND_REGS 32
+
+static int
+mips_unwind_reg_from_dwarf (int reg)
+{
+  if (reg > MIPS_NUM_UNWIND_REGS)
+    return -1;
+
+  return reg;
+}
+
+/* Attempt to generate compact frame unwind encodings.  */
+
+void
+mips_cfi_endproc (struct fde_entry *fde ATTRIBUTE_UNUSED)
+{
+  struct cfi_insn_data *insn;
+  int reg;
+  offsetT cfa_offset = 0;
+  offsetT next_offset = 0;
+  bfd_boolean reg_offset[MIPS_NUM_UNWIND_REGS];
+  int cfa_reg = 29;
+  bfd_byte opbuff[40];
+  int num_ops;
+  int i;
+  bfd_byte op;
+  offsetT stack_align = HAVE_NEWABI ? 16 : 8;
+  offsetT gpr_size = HAVE_64BIT_GPRS ? 8 : 4;
+
+  for (reg = 0; reg < MIPS_NUM_UNWIND_REGS; reg++)
+    reg_offset[reg] = 0;
+
+  /* Scan FDE instructions to build up stack frame layout.  */
+  for (insn = fde->data; insn; insn = insn->next)
+    {
+      switch (insn->insn)
+	{
+	case DW_CFA_advance_loc:
+	  break;
+
+	case DW_CFA_def_cfa:
+	  cfa_reg = insn->u.ri.reg;
+	  cfa_offset = insn->u.ri.offset;
+	  break;
+
+	case DW_CFA_def_cfa_register:
+	  cfa_reg = insn->u.r;
+	  break;
+
+	case DW_CFA_def_cfa_offset:
+	  cfa_offset = insn->u.i;
+	  break;
+
+	case DW_CFA_undefined:
+	case DW_CFA_same_value:
+	  reg = mips_unwind_reg_from_dwarf (insn->u.r);
+	  if (reg >= 0)
+	    reg_offset[reg] = 0;
+	  break;
+
+	case DW_CFA_offset:
+	  reg = mips_unwind_reg_from_dwarf (insn->u.ri.reg);
+	  if (reg < 0)
+	    return;
+	  if (insn->u.ri.offset >= 0)
+	    return;
+	  reg_offset[reg] = insn->u.ri.offset;
+	  break;
+
+	default:
+	  abort ();
+	}
+    }
+
+  /* Frame pointer must be callee caved.  */
+  if (cfa_reg < 16
+      || (cfa_reg > 23 && cfa_reg < 29)
+      || cfa_reg > 30)
+    return;
+
+  /* Can only increment stack pointer.  */
+  if (cfa_offset < 0)
+    return;
+
+  /* Stack must be aligned.  */
+  if ((cfa_offset & (stack_align - 1)) != 0)
+    return;
+
+  /* Registers must be contiguous.  There's only limited benefit in
+     supprting more complex layouts, so For now we also require they
+     be in order.  */
+  next_offset = -gpr_size;
+  for (i = MIPS_NUM_UNWIND_REGS - 1; i >= 0; i--)
+    {
+      if (reg_offset[i] == 0)
+	continue;
+
+      if (reg_offset[i] != next_offset)
+	return;
+
+      next_offset -= gpr_size;
+    }
+
+  num_ops = 0;
+  if (cfa_reg != 29)
+    opbuff[num_ops++] = 0x50 + cfa_reg - 16;
+
+  cfa_offset /= stack_align;
+  if (cfa_offset && cfa_offset <= 129)
+    {
+      while (cfa_offset > 64)
+	{
+	  opbuff[num_ops++] = 0x3f;
+	  cfa_offset -= 64;
+	}
+      opbuff[num_ops++] = cfa_offset - 1;
+    }
+  else if (cfa_offset > 0)
+    {
+      opbuff[num_ops++] = 0x58;
+      cfa_offset -= 129;
+      while (cfa_offset > 0x7f)
+	{
+	  opbuff[num_ops++] = (cfa_offset & 0x7f) | 0x80;
+	  cfa_offset >>= 7;
+	}
+      opbuff[num_ops++] = cfa_offset;
+    }
+
+  op = 0;
+  /* r16[-r23], [r30], r31 */
+  if (reg_offset[31])
+    {
+      if (reg_offset[30])
+	op = 0x48;
+      else
+	op = 0x40;
+
+      for (i = 29; i > 23; i--)
+	{
+	  if (reg_offset[i])
+	    op = 0;
+	}
+
+      while (i > 16 && reg_offset[i] == 0)
+	i--;
+
+      reg = i;
+      for (i = 16; i <= reg; i++)
+	if (reg_offset[i] == 0)
+	  op = 0;
+
+      if (op)
+	op |= (reg - 16);
+    }
+
+  if (!op)
+    {
+      /* mips16 save multiple.  */
+      op = 0x6c;
+      if (reg_offset[16] == 0 || reg_offset[17] == 0
+	  || reg_offset[21] == 0 || reg_offset[22] == 0
+	  || reg_offset[23] == 0 || reg_offset[31] == 0)
+	op = 0;
+
+      for (i = 24; i < 31; i++)
+	if (reg_offset[i] != 0)
+	  op = 0;
+
+      if (op && reg_offset[18] == 0)
+	op++;
+      if (reg_offset[19] == 0)
+	{
+	  if (op == 0x6d)
+	    op++;
+	  else
+	    op = 0;
+	}
+      if (reg_offset[20] == 0)
+	{
+	  if (op == 0x6e)
+	    op++;
+	  else
+	    op = 0;
+	}
+    }
+
+  if (op)
+    {
+      opbuff[num_ops++] = op;
+      reg = 15;
+    }
+  else
+    {
+      reg = 31;
+    }
+  /* Arbitrary blocks of registers.  */
+  i = 0;
+  while (reg >= 0)
+    {
+      if (reg_offset[reg] == 0)
+	{
+	  if (i)
+	    {
+	      opbuff[num_ops++] = 0x59;
+	      opbuff[num_ops++] = ((reg + 1) << 3) | (i - 1);
+	      i = 0;
+	    }
+	}
+      else
+	i++;
+      reg--;
+    }
+
+  if (i)
+    {
+      opbuff[num_ops++] = 0x59;
+      opbuff[num_ops++] = i - 1;
+    }
+
+  if (fde->lsda_encoding != DW_EH_PE_omit)
+    fde->eh_header_type = EH_COMPACT_HAS_LSDA;
+  else if (num_ops <= 3 && fde->per_encoding == DW_EH_PE_omit)
+    fde->eh_header_type = EH_COMPACT_INLINE;
+  else
+    fde->eh_header_type = EH_COMPACT_OUTLINE;
+
+  if (fde->eh_header_type == EH_COMPACT_INLINE)
+    {
+      while (num_ops < 3)
+	opbuff[num_ops++] = 0x5c;
+    }
+
+  fde->eh_data_size = num_ops;
+  fde->eh_data = (bfd_byte *) xmalloc (num_ops);
+  memcpy (fde->eh_data, opbuff, num_ops);
+}
+
+void
+mips_cfi_fix_eh_ref (char *where, expressionS *exp)
+{
+  fix_new (frag_now, where - frag_now->fr_literal, 4, exp->X_add_symbol,
+	   exp->X_add_number, FALSE, BFD_RELOC_MIPS_EH);
+}
+
+void
+mips_cfi_emit_expr (expressionS *exp, int encoding)
+{
+  char *p;
+
+  p = frag_more(4);
+  md_number_to_chars (p, 0, 4);
+  if ((encoding & 0x70) == DW_EH_PE_datarel)
+    mips_cfi_fix_eh_ref (p, exp);
+  else
+    {
+      fix_new (frag_now, p - frag_now->fr_literal, 4, exp->X_add_symbol,
+	       exp->X_add_number, TRUE, BFD_RELOC_32_PCREL);
+    }
+}
+#endif
Index: config/tc-mips.h
===================================================================
RCS file: /cvs/src/src/gas/config/tc-mips.h,v
retrieving revision 1.59
diff -p -u -r1.59 tc-mips.h
--- config/tc-mips.h	23 Sep 2012 11:14:25 -0000	1.59
+++ config/tc-mips.h	31 May 2013 17:24:20 -0000
@@ -177,7 +177,9 @@ extern enum dwarf2_format mips_dwarf2_fo
 
 extern int mips_dwarf2_addr_size (void);
 #define DWARF2_ADDR_SIZE(bfd) mips_dwarf2_addr_size ()
-#define DWARF2_FDE_RELOC_SIZE mips_dwarf2_addr_size ()
+#define DWARF2_FDE_RELOC_SIZE (compact_eh ? 4 : mips_dwarf2_addr_size ())
+#define DWARF2_FDE_RELOC_ENCODING(enc) \
+  (enc | (compact_eh ? DW_EH_PE_pcrel : 0))
 
 #define TARGET_USE_CFIPOP 1
 
@@ -190,4 +192,24 @@ extern int tc_mips_regname_to_dw2regnum 
 #define DWARF2_DEFAULT_RETURN_COLUMN 31
 #define DWARF2_CIE_DATA_ALIGNMENT (-4)
 
+#if defined (OBJ_ELF)
+
+#define tc_make_debug_seg mips_make_debug_seg
+segT mips_make_debug_seg (segT cseg, char *name);
+
+#define tc_cfi_endproc mips_cfi_endproc
+struct fde_entry;
+void mips_cfi_endproc (struct fde_entry *fde);
+
+#define tc_cfi_emit_expr mips_cfi_emit_expr
+void mips_cfi_emit_expr (expressionS *exp, int encoding);
+#define tc_cfi_special_encoding(e) \
+  ((e) == (DW_EH_PE_sdata4 | DW_EH_PE_datarel | DW_EH_PE_indirect) \
+   || (e) == (DW_EH_PE_sdata4 | DW_EH_PE_pcrel))
+
+#define tc_cfi_fix_eh_ref mips_cfi_fix_eh_ref
+void mips_cfi_fix_eh_ref (char *where, expressionS *exp);
+
+#endif /* OBJ_ELF */
+
 #endif /* TC_MIPS */

^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2015-05-05 10:04 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-05-31 18:56 [Patch] Gas support for MIPS Compact EH Moore, Catherine
2013-06-01 11:07 ` Richard Sandiford
2014-02-04 21:56   ` Moore, Catherine
2014-02-05 22:38     ` Maciej W. Rozycki
2014-02-08 16:34     ` Richard Sandiford
2014-02-08 18:48       ` Bernd Schmidt
2014-02-09 11:11         ` Richard Sandiford
2014-02-19 23:13           ` Moore, Catherine
2014-02-20 11:36             ` Richard Sandiford
2014-02-20 21:24               ` Moore, Catherine
2014-02-20 22:39                 ` Richard Sandiford
2014-02-24 20:54                   ` Moore, Catherine
2014-02-24 20:48               ` Moore, Catherine
2014-02-25  8:29                 ` Richard Sandiford
2014-03-17 13:22                   ` Moore, Catherine
2014-03-17 13:52                     ` Richard Sandiford
2014-03-19 21:12                       ` Moore, Catherine
2014-03-19 23:45                         ` Richard Sandiford
2014-03-20 14:29                           ` Moore, Catherine
2014-03-20 21:19                             ` Richard Sandiford
2014-03-06 17:44       ` Moore, Catherine
2014-03-06 22:18         ` Richard Sandiford
2014-03-25 13:50       ` Moore, Catherine
2014-03-25 14:06         ` Richard Sandiford
2014-11-17 16:10       ` Moore, Catherine
2014-11-22 14:42         ` Richard Sandiford
2015-02-08 16:59           ` Moore, Catherine
2015-02-08 17:00           ` Moore, Catherine
2015-04-16 13:28             ` Moore, Catherine
2015-05-01 13:54               ` FW: " Moore, Catherine
2015-05-05 10:04                 ` Matthew Fortune

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).