This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] C6X automagic cantinuwing marking


The patch below adds linker processing of C6X unwinding table sections.  As on 
ARM we add CANTUNWIND entries for text sections with no correspongin unwinding 
table, eliminate duplicate index entries.

The linker tests implicitly test the R_C6000_PREL31 relocation.

Ok?

2011-05-03  Paul Brook  <paul@codesourcery.com>

	bfd/
	* bfd-in.h (elf32_tic6x_fix_exidx_coverage): Add prototype.
	* bfd-in2.h: Regenerate.
	* elf32-tic6x.c: Include limits.h.
	(tic6x_unwind_edit_type, tic6x_unwind_table_edit,
	_tic6x_elf_section_data): New.
	(elf32_tic6x_section_data): Define.
	(elf32_tic6x_new_section_hook): Allocate target specific data.
	(elf32_tic6x_add_unwind_table_edit): New function.
	(get_tic6x_elf_section_data, elf32_tic6x_adjust_exidx_size,
	elf32_tic6x_insert_cantunwind_after, elf32_tic6x_add_low31,
	elf32_tic6x_copy_exidx_entry): New functions.
	(elf_backend_write_section): Define.

	ld/
	* emultempl/tic6xdsbt.em (merge_exidx_entries): New.
	(compare_output_sec_vma): New function.
	(gld${EMULATION_NAME}_after_allocation): New function.
	(OPTION_NO_MERGE_EXIDX_ENTRIES): Define.
	(PARSE_AND_LIST_OPTIONS): Add --no-merge-exidx-entries.
	(PARSE_AND_LIST_ARGS_CASES): Add OPTION_NO_MERGE_EXIDX_ENTRIES.
	(LDEMUL_AFTER_ALLOCATION): Set.
	* ld.texinfo: Document c6x --no-merge-exidx-entries.

	ld/testsuite/
	* ld-tic6x/discard-unwind.ld: New.
	* ld-tic6x/unwind.ld: New.
	* ld-tic6x/unwind-1.d: New test.
	* ld-tic6x/unwind-1.s: New test.
	* ld-tic6x/unwind-2.d: New test.
	* ld-tic6x/unwind-2.s: New test.
	* ld-tic6x/unwind-3.d: New test.
	* ld-tic6x/unwind-3.s: New test.
	* ld-tic6x/unwind-4.d: New test.
	* ld-tic6x/unwind-4.s: New test.
	* ld-tic6x/unwind-5.d: New test.
	* ld-tic6x/unwind-5.s: New test.
	* ld-tic6x/unwind-6.d: New test.
diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h
index d536897..21b7cc2 100644
--- a/bfd/bfd-in.h
+++ b/bfd/bfd-in.h
@@ -912,6 +912,10 @@ extern bfd_boolean elf32_arm_build_stubs
 extern bfd_boolean elf32_arm_fix_exidx_coverage
 (struct bfd_section **, unsigned int, struct bfd_link_info *, bfd_boolean);
 
+/* C6x unwind section editing support.  */
+extern bfd_boolean elf32_tic6x_fix_exidx_coverage
+(struct bfd_section **, unsigned int, struct bfd_link_info *, bfd_boolean);
+
 /* PowerPC @tls opcode transform/validate.  */
 extern unsigned int _bfd_elf_ppc_at_tls_transform
   (unsigned int, unsigned int);
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 76836b1..75ead7c 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -919,6 +919,10 @@ extern bfd_boolean elf32_arm_build_stubs
 extern bfd_boolean elf32_arm_fix_exidx_coverage
 (struct bfd_section **, unsigned int, struct bfd_link_info *, bfd_boolean);
 
+/* C6x unwind section editing support.  */
+extern bfd_boolean elf32_tic6x_fix_exidx_coverage
+(struct bfd_section **, unsigned int, struct bfd_link_info *, bfd_boolean);
+
 /* PowerPC @tls opcode transform/validate.  */
 extern unsigned int _bfd_elf_ppc_at_tls_transform
   (unsigned int, unsigned int);
diff --git a/bfd/elf32-tic6x.c b/bfd/elf32-tic6x.c
index 45ead5f..1f0ad52 100644
--- a/bfd/elf32-tic6x.c
+++ b/bfd/elf32-tic6x.c
@@ -22,6 +22,7 @@
    MA 02110-1301, USA.  */
 
 #include "sysdep.h"
+#include <limits.h>
 #include "bfd.h"
 #include "libbfd.h"
 #include "libiberty.h"
@@ -75,6 +76,52 @@ struct elf32_tic6x_link_hash_entry
   struct elf_dyn_relocs *dyn_relocs;
 };
 
+typedef enum
+{
+  DELETE_EXIDX_ENTRY,
+  INSERT_EXIDX_CANTUNWIND_AT_END
+}
+tic6x_unwind_edit_type;
+
+/* A (sorted) list of edits to apply to an unwind table.  */
+typedef struct tic6x_unwind_table_edit
+{
+  tic6x_unwind_edit_type type;
+  /* Note: we sometimes want to insert an unwind entry corresponding to a
+     section different from the one we're currently writing out, so record the
+     (text) section this edit relates to here.  */
+  asection *linked_section;
+  unsigned int index;
+  struct tic6x_unwind_table_edit *next;
+}
+tic6x_unwind_table_edit;
+
+typedef struct _tic6x_elf_section_data
+{
+  /* Information about mapping symbols.  */
+  struct bfd_elf_section_data elf;
+  /* Information about unwind tables.  */
+  union
+  {
+    /* Unwind info attached to a text section.  */
+    struct
+    {
+      asection *tic6x_exidx_sec;
+    } text;
+
+    /* Unwind info attached to an .ARM.exidx section.  */
+    struct
+    {
+      tic6x_unwind_table_edit *unwind_edit_list;
+      tic6x_unwind_table_edit *unwind_edit_tail;
+    } exidx;
+  } u;
+}
+_tic6x_elf_section_data;
+
+#define elf32_tic6x_section_data(sec) \
+  ((_tic6x_elf_section_data *) elf_section_data (sec))
+
 struct elf32_tic6x_obj_tdata
 {
   struct elf_obj_tdata root;
@@ -2095,6 +2142,18 @@ elf32_tic6x_new_section_hook (bfd *abfd, asection *sec)
 {
   bfd_boolean ret;
 
+  /* Allocate target specific section data.  */
+  if (!sec->used_by_bfd)
+    {
+      _tic6x_elf_section_data *sdata;
+      bfd_size_type amt = sizeof (*sdata);
+
+      sdata = (_tic6x_elf_section_data *) bfd_zalloc (abfd, amt);
+      if (sdata == NULL)
+	return FALSE;
+      sec->used_by_bfd = sdata;
+    }
+
   ret = _bfd_elf_new_section_hook (abfd, sec);
   sec->use_rela_p = elf32_tic6x_tdata (abfd)->use_rela_p;
 
@@ -3966,6 +4025,409 @@ elf32_tic6x_copy_private_data (bfd * ibfd, bfd * obfd)
   return TRUE;
 }
 
+/* Add a new unwind edit to the list described by HEAD, TAIL.  If TINDEX is zero,
+   adds the edit to the start of the list.  (The list must be built in order of
+   ascending TINDEX: the function's callers are primarily responsible for
+   maintaining that condition).  */
+
+static void
+elf32_tic6x_add_unwind_table_edit (tic6x_unwind_table_edit **head,
+				   tic6x_unwind_table_edit **tail,
+				   tic6x_unwind_edit_type type,
+				   asection *linked_section,
+				   unsigned int tindex)
+{
+  tic6x_unwind_table_edit *new_edit = (tic6x_unwind_table_edit *)
+      xmalloc (sizeof (tic6x_unwind_table_edit));
+  
+  new_edit->type = type;
+  new_edit->linked_section = linked_section;
+  new_edit->index = tindex;
+  
+  if (tindex > 0)
+    {
+      new_edit->next = NULL;
+
+      if (*tail)
+	(*tail)->next = new_edit;
+
+      (*tail) = new_edit;
+
+      if (!*head)
+	(*head) = new_edit;
+    }
+  else
+    {
+      new_edit->next = *head;
+
+      if (!*tail)
+	*tail = new_edit;
+
+      *head = new_edit;
+    }
+}
+
+static _tic6x_elf_section_data *
+get_tic6x_elf_section_data (asection * sec)
+{
+  if (sec && sec->owner && is_tic6x_elf (sec->owner))
+    return elf32_tic6x_section_data (sec);
+  else
+    return NULL;
+}
+
+
+/* Increase the size of EXIDX_SEC by ADJUST bytes.  ADJUST mau be negative.  */
+static void
+elf32_tic6x_adjust_exidx_size (asection *exidx_sec, int adjust)
+{
+  asection *out_sec;
+
+  if (!exidx_sec->rawsize)
+    exidx_sec->rawsize = exidx_sec->size;
+
+  bfd_set_section_size (exidx_sec->owner, exidx_sec, exidx_sec->size + adjust);
+  out_sec = exidx_sec->output_section;
+  /* Adjust size of output section.  */
+  bfd_set_section_size (out_sec->owner, out_sec, out_sec->size +adjust);
+}
+
+/* Insert an EXIDX_CANTUNWIND marker at the end of a section.  */
+static void
+elf32_tic6x_insert_cantunwind_after (asection *text_sec, asection *exidx_sec)
+{
+  struct _tic6x_elf_section_data *exidx_data;
+
+  exidx_data = get_tic6x_elf_section_data (exidx_sec);
+  elf32_tic6x_add_unwind_table_edit (
+    &exidx_data->u.exidx.unwind_edit_list,
+    &exidx_data->u.exidx.unwind_edit_tail,
+    INSERT_EXIDX_CANTUNWIND_AT_END, text_sec, UINT_MAX);
+
+  elf32_tic6x_adjust_exidx_size (exidx_sec, 8);
+}
+
+/* Scan .cx6abi.exidx tables, and create a list describing edits which
+   should be made to those tables, such that:
+   
+     1. Regions without unwind data are marked with EXIDX_CANTUNWIND entries.
+     2. Duplicate entries are merged together (EXIDX_CANTUNWIND, or unwind
+        codes which have been inlined into the index).
+
+   If MERGE_EXIDX_ENTRIES is false, duplicate entries are not merged.
+
+   The edits are applied when the tables are written
+   (in elf32_tic6x_write_section).
+*/
+
+bfd_boolean
+elf32_tic6x_fix_exidx_coverage (asection **text_section_order,
+				unsigned int num_text_sections,
+				struct bfd_link_info *info,
+				bfd_boolean merge_exidx_entries)
+{
+  bfd *inp;
+  unsigned int last_second_word = 0, i;
+  asection *last_exidx_sec = NULL;
+  asection *last_text_sec = NULL;
+  int last_unwind_type = -1;
+
+  /* Walk over all EXIDX sections, and create backlinks from the corrsponding
+     text sections.  */
+  for (inp = info->input_bfds; inp != NULL; inp = inp->link_next)
+    {
+      asection *sec;
+      
+      for (sec = inp->sections; sec != NULL; sec = sec->next)
+        {
+	  struct bfd_elf_section_data *elf_sec = elf_section_data (sec);
+	  Elf_Internal_Shdr *hdr = &elf_sec->this_hdr;
+	  
+	  if (!hdr || hdr->sh_type != SHT_C6000_UNWIND)
+	    continue;
+	  
+	  if (elf_sec->linked_to)
+	    {
+	      Elf_Internal_Shdr *linked_hdr
+	        = &elf_section_data (elf_sec->linked_to)->this_hdr;
+	      struct _tic6x_elf_section_data *linked_sec_tic6x_data
+	        = get_tic6x_elf_section_data (linked_hdr->bfd_section);
+
+	      if (linked_sec_tic6x_data == NULL)
+	        continue;
+
+	      /* Link this .c6xabi.exidx section back from the
+		 text section it describes.  */
+	      linked_sec_tic6x_data->u.text.tic6x_exidx_sec = sec;
+	    }
+	}
+    }
+
+  /* Walk all text sections in order of increasing VMA.  Eilminate duplicate
+     index table entries (EXIDX_CANTUNWIND and inlined unwind opcodes),
+     and add EXIDX_CANTUNWIND entries for sections with no unwind table data.  */
+
+  for (i = 0; i < num_text_sections; i++)
+    {
+      asection *sec = text_section_order[i];
+      asection *exidx_sec;
+      struct _tic6x_elf_section_data *tic6x_data
+       	= get_tic6x_elf_section_data (sec);
+      struct _tic6x_elf_section_data *exidx_data;
+      bfd_byte *contents = NULL;
+      int deleted_exidx_bytes = 0;
+      bfd_vma j;
+      tic6x_unwind_table_edit *unwind_edit_head = NULL;
+      tic6x_unwind_table_edit *unwind_edit_tail = NULL;
+      Elf_Internal_Shdr *hdr;
+      bfd *ibfd;
+
+      if (tic6x_data == NULL)
+        continue;
+
+      exidx_sec = tic6x_data->u.text.tic6x_exidx_sec;
+      if (exidx_sec == NULL)
+	{
+	  /* Section has no unwind data.  */
+	  if (last_unwind_type == 0 || !last_exidx_sec)
+	    continue;
+
+	  /* Ignore zero sized sections.  */
+	  if (sec->size == 0)
+	    continue;
+
+	  elf32_tic6x_insert_cantunwind_after (last_text_sec, last_exidx_sec);
+	  last_unwind_type = 0;
+	  continue;
+	}
+
+      /* Skip /DISCARD/ sections.  */
+      if (bfd_is_abs_section (exidx_sec->output_section))
+	continue;
+
+      hdr = &elf_section_data (exidx_sec)->this_hdr;
+      if (hdr->sh_type != SHT_C6000_UNWIND)
+        continue;
+      
+      exidx_data = get_tic6x_elf_section_data (exidx_sec);
+      if (exidx_data == NULL)
+        continue;
+      
+      ibfd = exidx_sec->owner;
+	  
+      if (hdr->contents != NULL)
+	contents = hdr->contents;
+      else if (! bfd_malloc_and_get_section (ibfd, exidx_sec, &contents))
+	/* An error?  */
+	continue;
+
+      for (j = 0; j < hdr->sh_size; j += 8)
+	{
+	  unsigned int second_word = bfd_get_32 (ibfd, contents + j + 4);
+	  int unwind_type;
+	  int elide = 0;
+
+	  /* An EXIDX_CANTUNWIND entry.  */
+	  if (second_word == 1)
+	    {
+	      if (last_unwind_type == 0)
+		elide = 1;
+	      unwind_type = 0;
+	    }
+	  /* Inlined unwinding data.  Merge if equal to previous.  */
+	  else if ((second_word & 0x80000000) != 0)
+	    {
+	      if (merge_exidx_entries
+		  && last_second_word == second_word
+		  && last_unwind_type == 1)
+		elide = 1;
+	      unwind_type = 1;
+	      last_second_word = second_word;
+	    }
+	  /* Normal table entry.  In theory we could merge these too,
+	     but duplicate entries are likely to be much less common.  */
+	  else
+	    unwind_type = 2;
+
+	  if (elide)
+	    {
+	      elf32_tic6x_add_unwind_table_edit (&unwind_edit_head,
+		  &unwind_edit_tail, DELETE_EXIDX_ENTRY, NULL, j / 8);
+
+	      deleted_exidx_bytes += 8;
+	    }
+
+	  last_unwind_type = unwind_type;
+	}
+
+      /* Free contents if we allocated it ourselves.  */
+      if (contents != hdr->contents)
+        free (contents);
+
+      /* Record edits to be applied later (in elf32_tic6x_write_section).  */
+      exidx_data->u.exidx.unwind_edit_list = unwind_edit_head;
+      exidx_data->u.exidx.unwind_edit_tail = unwind_edit_tail;
+	  
+      if (deleted_exidx_bytes > 0)
+	elf32_tic6x_adjust_exidx_size (exidx_sec, -deleted_exidx_bytes);
+
+      last_exidx_sec = exidx_sec;
+      last_text_sec = sec;
+    }
+
+  /* Add terminating CANTUNWIND entry.  */
+  if (last_exidx_sec && last_unwind_type != 0)
+    elf32_tic6x_insert_cantunwind_after (last_text_sec, last_exidx_sec);
+
+  return TRUE;
+}
+
+/* Add ADDEND to lower 31 bits of VAL, leaving other bits unmodified.  */
+
+static unsigned long
+elf32_tic6x_add_low31 (unsigned long val, bfd_vma addend)
+{
+  return (val & ~0x7ffffffful) | ((val + addend) & 0x7ffffffful);
+}
+
+/* Copy an .c6xabi.exidx table entry, adding OFFSET to (applied) PREL31
+   relocations.  OFFSET is in bytes, and will be scaled before encoding.  */
+
+
+static void
+elf32_tic6x_copy_exidx_entry (bfd *output_bfd, bfd_byte *to, bfd_byte *from,
+			      bfd_vma offset)
+{
+  unsigned long first_word = bfd_get_32 (output_bfd, from);
+  unsigned long second_word = bfd_get_32 (output_bfd, from + 4);
+
+  offset >>= 1;
+  /* High bit of first word is supposed to be zero.  */
+  if ((first_word & 0x80000000ul) == 0)
+    first_word = elf32_tic6x_add_low31 (first_word, offset);
+  
+  /* If the high bit of the first word is clear, and the bit pattern is not 0x1
+     (EXIDX_CANTUNWIND), this is an offset to an .ARM.extab entry.  */
+  if ((second_word != 0x1) && ((second_word & 0x80000000ul) == 0))
+    second_word = elf32_tic6x_add_low31 (second_word, offset);
+  
+  bfd_put_32 (output_bfd, first_word, to);
+  bfd_put_32 (output_bfd, second_word, to + 4);
+}
+
+/* Do the actual mangling of exception index tables.  */
+
+static bfd_boolean
+elf32_tic6x_write_section (bfd *output_bfd,
+			 struct bfd_link_info *link_info,
+			 asection *sec,
+			 bfd_byte *contents)
+{
+  _tic6x_elf_section_data *tic6x_data;
+  struct elf32_tic6x_link_hash_table *globals
+    = elf32_tic6x_hash_table (link_info);
+  bfd_vma offset = sec->output_section->vma + sec->output_offset;
+
+  if (globals == NULL)
+    return FALSE;
+
+  /* If this section has not been allocated an _tic6x_elf_section_data
+     structure then we cannot record anything.  */
+  tic6x_data = get_tic6x_elf_section_data (sec);
+  if (tic6x_data == NULL)
+    return FALSE;
+
+  if (tic6x_data->elf.this_hdr.sh_type != SHT_C6000_UNWIND)
+    return FALSE;
+
+  tic6x_unwind_table_edit *edit_node
+    = tic6x_data->u.exidx.unwind_edit_list;
+  /* Now, sec->size is the size of the section we will write.  The original
+     size (before we merged duplicate entries and inserted EXIDX_CANTUNWIND
+     markers) was sec->rawsize.  (This isn't the case if we perform no
+     edits, then rawsize will be zero and we should use size).  */
+  bfd_byte *edited_contents = (bfd_byte *) bfd_malloc (sec->size);
+  unsigned int input_size = sec->rawsize ? sec->rawsize : sec->size;
+  unsigned int in_index, out_index;
+  bfd_vma add_to_offsets = 0;
+
+  for (in_index = 0, out_index = 0; in_index * 8 < input_size || edit_node;)
+    {
+      if (edit_node)
+	{
+	  unsigned int edit_index = edit_node->index;
+	  
+	  if (in_index < edit_index && in_index * 8 < input_size)
+	    {
+	      elf32_tic6x_copy_exidx_entry (output_bfd,
+		  edited_contents + out_index * 8,
+		  contents + in_index * 8, add_to_offsets);
+	      out_index++;
+	      in_index++;
+	    }
+	  else if (in_index == edit_index
+		   || (in_index * 8 >= input_size
+		       && edit_index == UINT_MAX))
+	    {
+	      switch (edit_node->type)
+		{
+		case DELETE_EXIDX_ENTRY:
+		  in_index++;
+		  add_to_offsets += 8;
+		  break;
+		
+		case INSERT_EXIDX_CANTUNWIND_AT_END:
+		  {
+		    asection *text_sec = edit_node->linked_section;
+		    bfd_vma text_offset = text_sec->output_section->vma
+					  + text_sec->output_offset
+					  + text_sec->size;
+		    bfd_vma exidx_offset = offset + out_index * 8;
+		    unsigned long prel31_offset;
+
+		    /* Note: this is meant to be equivalent to an
+		       R_C6000_PREL31 relocation.  These synthetic
+		       EXIDX_CANTUNWIND markers are not relocated by the
+		       usual BFD method.  */
+		    prel31_offset = ((text_offset - exidx_offset) >> 1)
+				    & 0x7ffffffful;
+
+		    /* First address we can't unwind.  */
+		    bfd_put_32 (output_bfd, prel31_offset,
+				&edited_contents[out_index * 8]);
+
+		    /* Code for EXIDX_CANTUNWIND.  */
+		    bfd_put_32 (output_bfd, 0x1,
+				&edited_contents[out_index * 8 + 4]);
+
+		    out_index++;
+		    add_to_offsets -= 8;
+		  }
+		  break;
+		}
+	      
+	      edit_node = edit_node->next;
+	    }
+	}
+      else
+	{
+	  /* No more edits, copy remaining entries verbatim.  */
+	  elf32_tic6x_copy_exidx_entry (output_bfd,
+	      edited_contents + out_index * 8,
+	      contents + in_index * 8, add_to_offsets);
+	  out_index++;
+	  in_index++;
+	}
+    }
+
+  if (!(sec->flags & SEC_EXCLUDE) && !(sec->flags & SEC_NEVER_LOAD))
+    bfd_set_section_contents (output_bfd, sec->output_section,
+			      edited_contents,
+			      (file_ptr) sec->output_offset, sec->size);
+
+  return TRUE;
+}
+
 #define TARGET_LITTLE_SYM	bfd_elf32_tic6x_le_vec
 #define TARGET_LITTLE_NAME	"elf32-tic6x-le"
 #define TARGET_BIG_SYM		bfd_elf32_tic6x_be_vec
@@ -4023,6 +4485,7 @@ elf32_tic6x_copy_private_data (bfd * ibfd, bfd * obfd)
   elf32_tic6x_size_dynamic_sections
 #define elf_backend_finish_dynamic_sections \
   elf32_tic6x_finish_dynamic_sections
+#define elf_backend_write_section	elf32_tic6x_write_section
 #define elf_info_to_howto		elf32_tic6x_info_to_howto
 #define elf_info_to_howto_rel		elf32_tic6x_info_to_howto_rel
 
diff --git a/ld/emultempl/tic6xdsbt.em b/ld/emultempl/tic6xdsbt.em
index 875148e..d0e345d 100644
--- a/ld/emultempl/tic6xdsbt.em
+++ b/ld/emultempl/tic6xdsbt.em
@@ -31,6 +31,8 @@ static struct elf32_tic6x_params params =
   0, 64
 };
 
+static int merge_exidx_entries = -1;
+
 static int
 is_tic6x_target (void)
 {
@@ -58,6 +60,92 @@ tic6x_after_open (void)
 
   gld${EMULATION_NAME}_after_open ();
 }
+
+static int
+compare_output_sec_vma (const void *a, const void *b)
+{
+  asection *asec = *(asection **) a, *bsec = *(asection **) b;
+  asection *aout = asec->output_section, *bout = bsec->output_section;
+  bfd_vma avma, bvma;
+  
+  /* If there's no output section for some reason, compare equal.  */
+  if (!aout || !bout)
+    return 0;
+  
+  avma = aout->vma + asec->output_offset;
+  bvma = bout->vma + bsec->output_offset;
+  
+  if (avma > bvma)
+    return 1;
+  else if (avma < bvma)
+    return -1;
+  
+  return 0;
+}
+
+static void
+gld${EMULATION_NAME}_after_allocation (void)
+{
+  int layout_changed = 0;
+
+  if (!link_info.relocatable)
+    {
+      /* Build a sorted list of input text sections, then use that to process
+	 the unwind table index.  */
+      unsigned int list_size = 10;
+      asection **sec_list = (asection **)
+          xmalloc (list_size * sizeof (asection *));
+      unsigned int sec_count = 0;
+
+      LANG_FOR_EACH_INPUT_STATEMENT (is)
+	{
+	  bfd *abfd = is->the_bfd;
+	  asection *sec;
+	  
+	  if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
+	    continue;
+	  
+	  for (sec = abfd->sections; sec != NULL; sec = sec->next)
+	    {
+	      asection *out_sec = sec->output_section;
+
+	      if (out_sec
+		  && elf_section_data (sec)
+		  && elf_section_type (sec) == SHT_PROGBITS
+		  && (elf_section_flags (sec) & SHF_EXECINSTR) != 0
+		  && (sec->flags & SEC_EXCLUDE) == 0
+		  && sec->sec_info_type != ELF_INFO_TYPE_JUST_SYMS
+		  && out_sec != bfd_abs_section_ptr)
+		{
+		  if (sec_count == list_size)
+		    {
+		      list_size *= 2;
+		      sec_list = (asection **) 
+                          xrealloc (sec_list, list_size * sizeof (asection *));
+		    }
+
+		  sec_list[sec_count++] = sec;
+		}
+	    }
+	}
+	
+      qsort (sec_list, sec_count, sizeof (asection *), &compare_output_sec_vma);
+      
+      if (elf32_tic6x_fix_exidx_coverage (sec_list, sec_count, &link_info,
+					   merge_exidx_entries))
+	layout_changed = 1;
+      
+      free (sec_list);
+    }
+
+  /* bfd_elf32_discard_info just plays with debugging sections,
+     ie. doesn't affect any code, so we can delay resizing the
+     sections.  */
+  if (bfd_elf_discard_info (link_info.output_bfd, & link_info))
+    layout_changed = 1;
+
+  gld${EMULATION_NAME}_map_segments (layout_changed);
+}
 EOF
 
 # This code gets inserted into the generic elf32.sc linker script
@@ -65,11 +153,13 @@ EOF
 PARSE_AND_LIST_PROLOGUE='
 #define OPTION_DSBT_INDEX		300
 #define OPTION_DSBT_SIZE		301
+#define OPTION_NO_MERGE_EXIDX_ENTRIES   302
 '
 
 PARSE_AND_LIST_LONGOPTS='
   {"dsbt-index", required_argument, NULL, OPTION_DSBT_INDEX},
   {"dsbt-size", required_argument, NULL, OPTION_DSBT_SIZE},
+  { "no-merge-exidx-entries", no_argument, NULL, OPTION_NO_MERGE_EXIDX_ENTRIES },
 '
 
 PARSE_AND_LIST_OPTIONS='
@@ -77,6 +167,7 @@ PARSE_AND_LIST_OPTIONS='
   fprintf (file, _("\t\t\tUse this as the DSBT index for the output object\n"));
   fprintf (file, _("  --dsbt-size <index>\n"));
   fprintf (file, _("\t\t\tUse this as the number of entries in the DSBT table\n"));
+  fprintf (file, _("  --no-merge-exidx-entries    Disable merging exidx entries\n"));
 '
 
 PARSE_AND_LIST_ARGS_CASES='
@@ -100,6 +191,9 @@ PARSE_AND_LIST_ARGS_CASES='
 	einfo (_("%P%F: invalid --dsbt-size %s\n"), optarg);
       }
       break;
+   case OPTION_NO_MERGE_EXIDX_ENTRIES:
+      merge_exidx_entries = 0;
 '
 
 LDEMUL_AFTER_OPEN=tic6x_after_open
+LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index 800f0d4..58de9d8 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -2637,6 +2637,9 @@ to @var{index}.  The default is 0, which is appropriate for generating
 executables.  If a shared library is generated with a DSBT index of 0, the
 @code{R_C6000_DSBT_INDEX} relocs are copied into the output file.
 
+@kindex --no-merge-exidx-entries
+The @samp{--no-merge-exidx-entries} switch disables the merging of adjacent exidx entries in debuginfo.
+
 @end table
 
 @c man end
diff --git a/ld/testsuite/ld-tic6x/discard-unwind.ld b/ld/testsuite/ld-tic6x/discard-unwind.ld
new file mode 100644
index 0000000..9d1b4eb
--- /dev/null
+++ b/ld/testsuite/ld-tic6x/discard-unwind.ld
@@ -0,0 +1,17 @@
+/* Script for unwinding ld tests */
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = 0x8000;
+  .text           :
+  {
+    *(.before)
+    *(.text)
+    *(.after)
+    *(.c6xabi.extab*)
+    *(.glue_7)
+    *(.v4_bx)
+  } =0
+  /DISCARD/ : { *(.c6xabi.exidx*) }
+  .c6xabi.attribues 0 : { *(.c6xabi.atttributes) }
+}
diff --git a/ld/testsuite/ld-tic6x/unwind-1.d b/ld/testsuite/ld-tic6x/unwind-1.d
new file mode 100644
index 0000000..11a24d4
--- /dev/null
+++ b/ld/testsuite/ld-tic6x/unwind-1.d
@@ -0,0 +1,10 @@
+#ld: -T unwind.ld
+#objdump: -s
+
+.*:     file format.*
+
+#...
+Contents of section .c6xabi.exidx:
+ 9000 (00f8ff7f 07020083 1cf8ff7f 01000000|7ffff800 83000207 7ffff81c 00000001)  .*
+Contents of section .far:
+#...
diff --git a/ld/testsuite/ld-tic6x/unwind-1.s b/ld/testsuite/ld-tic6x/unwind-1.s
new file mode 100644
index 0000000..5783a40
--- /dev/null
+++ b/ld/testsuite/ld-tic6x/unwind-1.s
@@ -0,0 +1,25 @@
+	.cfi_sections .c6xabi.exidx
+	.text
+	.global _start
+	.type _start, %function
+_start:
+	.cfi_startproc
+	.cfi_offset B3, 0
+	.cfi_def_cfa_offset 8
+	nop
+	.p2align 6
+	.cfi_endproc
+	.personalityindex 3
+	.endp
+
+	# Section with no unwinding information.
+	# Linker should insert a cantunwind entry.
+	.section .after, "xa"
+	.global __c6xabi_unwind_cpp_pr3
+	.type __c6xabi_unwind_cpp_pr3, %function
+__c6xabi_unwind_cpp_pr3:
+	nop
+	.p2align 6
+
+	.section .far
+	.word 0
diff --git a/ld/testsuite/ld-tic6x/unwind-2.d b/ld/testsuite/ld-tic6x/unwind-2.d
new file mode 100644
index 0000000..11a24d4
--- /dev/null
+++ b/ld/testsuite/ld-tic6x/unwind-2.d
@@ -0,0 +1,10 @@
+#ld: -T unwind.ld
+#objdump: -s
+
+.*:     file format.*
+
+#...
+Contents of section .c6xabi.exidx:
+ 9000 (00f8ff7f 07020083 1cf8ff7f 01000000|7ffff800 83000207 7ffff81c 00000001)  .*
+Contents of section .far:
+#...
diff --git a/ld/testsuite/ld-tic6x/unwind-2.s b/ld/testsuite/ld-tic6x/unwind-2.s
new file mode 100644
index 0000000..dbfd3bd
--- /dev/null
+++ b/ld/testsuite/ld-tic6x/unwind-2.s
@@ -0,0 +1,23 @@
+	.cfi_sections .c6xabi.exidx
+	.text
+
+	.global __c6xabi_unwind_cpp_pr3
+	.type __c6xabi_unwind_cpp_pr3, %function
+__c6xabi_unwind_cpp_pr3:
+	.global _start
+	.type _start, %function
+_start:
+	.cfi_startproc
+	.cfi_offset B3, 0
+	.cfi_def_cfa_offset 8
+	nop
+	.p2align 6
+	.cfi_endproc
+	.personalityindex 3
+	.endp
+
+	# last text section has unwind information. Linker should append a
+	# terminating cantunwind entry.
+
+	.section .far
+	.word 0
diff --git a/ld/testsuite/ld-tic6x/unwind-3.d b/ld/testsuite/ld-tic6x/unwind-3.d
new file mode 100644
index 0000000..9ec69a0
--- /dev/null
+++ b/ld/testsuite/ld-tic6x/unwind-3.d
@@ -0,0 +1,11 @@
+#ld: -T unwind.ld
+#objdump: -s
+
+.*:     file format.*
+
+#...
+Contents of section .c6xabi.exidx:
+ 9000 (00f8ff7f 07020083 1cf8ff7f 01000000|7ffff800 83000207 7ffff81c 00000001)  .*
+ 9010 (38f8ff7f 07040083 54f8ff7f 01000000|7ffff838 82000407 7ffff854 00000001)  .*
+Contents of section .far:
+#...
diff --git a/ld/testsuite/ld-tic6x/unwind-3.s b/ld/testsuite/ld-tic6x/unwind-3.s
new file mode 100644
index 0000000..480ee49
--- /dev/null
+++ b/ld/testsuite/ld-tic6x/unwind-3.s
@@ -0,0 +1,39 @@
+	.cfi_sections .c6xabi.exidx
+	.text
+	# section without unwind info
+	.global _start
+	.type _start, %function
+_start:
+	b .s2 _before
+	nop 5
+	.p2align 6
+
+	# Section that will be placed first
+	.section .before, "xa"
+	.type _before, %function
+_before:
+	.cfi_startproc
+	.cfi_offset B3, 0
+	.cfi_def_cfa_offset 8
+	nop
+	.p2align 6
+	.cfi_endproc
+	.personalityindex 3
+	.endp
+
+	# section that will be placed last
+	.section .after, "xa"
+	.global __c6xabi_unwind_cpp_pr3
+	.type __c6xabi_unwind_cpp_pr3, %function
+__c6xabi_unwind_cpp_pr3:
+	.cfi_startproc
+	.cfi_offset B10, 0
+	.cfi_def_cfa_offset 8
+	nop
+	.p2align 6
+	.cfi_endproc
+	.personalityindex 3
+	.endp
+
+	.section .far
+	.word 0
diff --git a/ld/testsuite/ld-tic6x/unwind-4.d b/ld/testsuite/ld-tic6x/unwind-4.d
new file mode 100644
index 0000000..e5c628e
--- /dev/null
+++ b/ld/testsuite/ld-tic6x/unwind-4.d
@@ -0,0 +1,11 @@
+#ld: -T unwind.ld
+#objdump: -s
+
+.*:     file format.*
+
+#...
+Contents of section .c6xabi.exidx:
+ 9000 (00f8ff7f 07020083 1cf8ff7f 7af8ff7f|7ffff800 83000207 7ffff81c 7ffff87a)  .*
+ 9010 (38f8ff7f 07020083 56f8ff7f 01000000|7ffff838 83000207 7ffff856 00000001)  .*
+Contents of section .far:
+#...
diff --git a/ld/testsuite/ld-tic6x/unwind-4.s b/ld/testsuite/ld-tic6x/unwind-4.s
new file mode 100644
index 0000000..83f3d0d
--- /dev/null
+++ b/ld/testsuite/ld-tic6x/unwind-4.s
@@ -0,0 +1,68 @@
+	.cfi_sections .c6xabi.exidx
+	.text
+	# out of line table entry
+	.global _start
+	.type _start, %function
+_start:
+	.cfi_startproc
+	.cfi_offset B3, 0
+	.cfi_def_cfa_offset 8
+	nop
+	.p2align 6
+	.cfi_endproc
+	.personalityindex 3
+	.handlerdata
+	.word 0
+	.endp
+
+	# entry that can be merged
+	.cfi_startproc
+	.cfi_offset B3, 0
+	.cfi_def_cfa_offset 8
+	nop
+	.p2align 6
+	.cfi_endproc
+	.personalityindex 3
+	.endp
+
+	# Section that will be placed first
+	.section .before, "xa"
+	.type _before, %function
+_before:
+	.cfi_startproc
+	.cfi_offset B3, 0
+	.cfi_def_cfa_offset 8
+	nop
+	.p2align 6
+	.cfi_endproc
+	.personalityindex 3
+	.endp
+
+	# section that will be placed last
+	.section .after, "xa"
+	.global __c6xabi_unwind_cpp_pr3
+	.type __c6xabi_unwind_cpp_pr3, %function
+__c6xabi_unwind_cpp_pr3:
+	# entry that can be merged
+	.cfi_startproc
+	.cfi_offset B3, 0
+	.cfi_def_cfa_offset 8
+	nop
+	.cfi_endproc
+	.personalityindex 3
+	.endp
+
+	# final function is cantunwind, so output table size is smaller
+	# than sum of input sections
+	.global foo
+	.type foo, %function
+foo:
+	.cfi_startproc
+	nop
+	.p2align 6
+	.cfi_endproc
+	.cantunwind
+	.endp
+
+	.section .far
+	.word 0
diff --git a/ld/testsuite/ld-tic6x/unwind-5.d b/ld/testsuite/ld-tic6x/unwind-5.d
new file mode 100644
index 0000000..4928874
--- /dev/null
+++ b/ld/testsuite/ld-tic6x/unwind-5.d
@@ -0,0 +1,7 @@
+#ld: -T discard-unwind.ld
+#objdump: -s
+
+.*:     file format.*
+
+# Check we don't crash when discarding unwind info.
+#...
diff --git a/ld/testsuite/ld-tic6x/unwind-5.s b/ld/testsuite/ld-tic6x/unwind-5.s
new file mode 100644
index 0000000..b4fc213
--- /dev/null
+++ b/ld/testsuite/ld-tic6x/unwind-5.s
@@ -0,0 +1,16 @@
+	.cfi_sections .c6xabi.exidx
+	.text
+	.global __c6xabi_unwind_cpp_pr3
+	.type __c6xabi_unwind_cpp_pr3, %function
+__c6xabi_unwind_cpp_pr3:
+	.global _start
+	.type _start, %function
+_start:
+	.cfi_startproc
+	.cfi_offset B3, 0
+	.cfi_def_cfa_offset 8
+	nop
+	.p2align 6
+	.cfi_endproc
+	.personalityindex 3
+	.endp
diff --git a/ld/testsuite/ld-tic6x/unwind-6.d b/ld/testsuite/ld-tic6x/unwind-6.d
new file mode 100644
index 0000000..5de8ee6
--- /dev/null
+++ b/ld/testsuite/ld-tic6x/unwind-6.d
@@ -0,0 +1,13 @@
+#ld: -T unwind.ld
+#source unwind-4.s
+#as: -mgenerate-rel
+#objdump: -s
+
+.*:     file format.*
+
+#...
+Contents of section .c6xabi.exidx:
+ 9000 (00f8ff7f 07020083 1cf8ff7f 7af8ff7f|7ffff800 83000207 7ffff81c 7ffff87a)  .*
+ 9010 (38f8ff7f 07020083 56f8ff7f 01000000|7ffff838 83000207 7ffff856 00000001)  .*
+Contents of section .far:
+#...
diff --git a/ld/testsuite/ld-tic6x/unwind.ld b/ld/testsuite/ld-tic6x/unwind.ld
new file mode 100644
index 0000000..5cb22a8
--- /dev/null
+++ b/ld/testsuite/ld-tic6x/unwind.ld
@@ -0,0 +1,22 @@
+/* Script for unwinding ld tests */
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = 0x8000;
+  .text           :
+  {
+    *(.before)
+    *(.text)
+    *(.after)
+    *(.c6xabi.extab*)
+    *(.glue_7)
+    *(.v4_bx)
+  } =0
+  . = 0x9000;
+  .c6xabi.exidx : { *(.c6xabi.exidx*) }
+  . = 0xa000;
+  .got            : { *(.got) *(.got.plt)}
+  . = 0x12340000;
+  .far : { *(.far) }
+  .c6xabi.attribues 0 : { *(.c6xabi.atttributes) }
+}
-- 
1.7.4.4


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]