public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] Test also relocations for ARM unwinding section
@ 2016-09-11  9:31 Akihiko Odaki
  2016-09-13  6:48 ` [PATCH] ARM: Fix relocation of EXIDX sections Akihiko Odaki
  0 siblings, 1 reply; 8+ messages in thread
From: Akihiko Odaki @ 2016-09-11  9:31 UTC (permalink / raw)
  To: binutils; +Cc: Paul Brook, Akihiko Odaki

As reported in PR binutils/20595, BFD has a bug that it doesn't delete
relocations for deleted exidx. This change allows the testsuite to find the
flaw.
---
 ld/testsuite/ld-arm/unwind-4.d | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/ld/testsuite/ld-arm/unwind-4.d b/ld/testsuite/ld-arm/unwind-4.d
index 0a4427a..0bed0dc 100644
--- a/ld/testsuite/ld-arm/unwind-4.d
+++ b/ld/testsuite/ld-arm/unwind-4.d
@@ -1,9 +1,23 @@
-#ld: -T arm.ld
-#objdump: -s
+#ld: -q -T arm.ld
+#objdump: -sr
 
 .*:     file format.*
 
 #...
+RELOCATION RECORDS FOR \[\.ARM\.exidx\]:
+OFFSET   TYPE              VALUE 
+00000000 R_ARM_PREL31      \.text
+00000000 R_ARM_NONE        __aeabi_unwind_cpp_pr0
+00000008 R_ARM_PREL31      \.text
+00000008 R_ARM_NONE        __aeabi_unwind_cpp_pr1
+0000000c R_ARM_PREL31      \.text
+00000010 R_ARM_PREL31      \.text
+00000010 R_ARM_NONE        __aeabi_unwind_cpp_pr0
+00000018 R_ARM_PREL31      \.text
+
+
+Contents of section .text:
+#...
 Contents of section .ARM.exidx:
  8020 (e0ffff7f b0b0a880 dcffff7f e8ffff7f|7fffffe0 80a8b0b0 7fffffdc 7fffffe8)  .*
  8030 (d8ffff7f b0b0a880 d8ffff7f 01000000|7fffffd8 80a8b0b0 7fffffd8 00000001)  .*
-- 
2.9.3

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

* [PATCH] ARM: Fix relocation of EXIDX sections
  2016-09-11  9:31 [PATCH] Test also relocations for ARM unwinding section Akihiko Odaki
@ 2016-09-13  6:48 ` Akihiko Odaki
  2016-09-13  7:16   ` Andreas Schwab
                     ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Akihiko Odaki @ 2016-09-13  6:48 UTC (permalink / raw)
  To: binutils; +Cc: Paul Brook, Yury Usishchev, Akihiko Odaki

As reported in PR binutils/20595, BFD has a bug that it doesn't delete
relocations for deleted exidx. This change fixes the behavior.

bfd * elf-bfd.h: Add callback to count relocations in the final output.
    * elf-arm.c (elf32_arm_add_relocation): Deleted.
    (elf32_arm_write_section): Move additional relocation to emit_relocs.
    (elf32_arm_count_output_relocs): New function.
    (emit_relocs): New function.
    (elf32_arm_emit_relocs): New function.
    (elf32_arm_vxworks_emit_relocs): New function.
    (elf_backend_emit_relocs): Updated to use the new functions.
    (elf_backend_count_output_relocs): New define.
    * bfd/elflink.c (bfd_elf_final_link): Do not add additional_reloc_count
    to the relocation count.
    (_bfd_elf_link_size_reloc_section): Use callback to count the
    relocations which will be in output.
    (_bfd_elf_default_count_output_relocs): New function.
    * bfd/elfxx-target.h (elf_backend_count_output_relocs): New define.
---
 bfd/elf-bfd.h      |   8 ++
 bfd/elf32-arm.c    | 257 +++++++++++++++++++++++++++++++++++++++++++----------
 bfd/elflink.c      |  60 +++++++++----
 bfd/elfxx-target.h |   4 +
 4 files changed, 264 insertions(+), 65 deletions(-)

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 163ef35..1c7aa5a 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1176,6 +1176,11 @@ struct elf_backend_data
   unsigned int (*elf_backend_count_additional_relocs)
     (asection *);
 
+  /* Count relocations to be output. The result may be different if the
+     input relocations are expected to be modified by the backend. */
+  unsigned int (* elf_backend_count_output_relocs)
+    (struct bfd_link_info *info, asection *o);
+
   /* Say whether to sort relocs output by ld -r and ld --emit-relocs,
      by r_offset.  If NULL, default to true.  */
   bfd_boolean (*sort_relocs_p)
@@ -2143,6 +2148,9 @@ extern bfd_boolean _bfd_elf_link_output_relocs
   (bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *,
    struct elf_link_hash_entry **);
 
+extern unsigned int _bfd_elf_default_count_output_relocs
+  (struct bfd_link_info *info ATTRIBUTE_UNUSED, asection *o);
+
 extern bfd_boolean _bfd_elf_adjust_dynamic_copy
   (struct bfd_link_info *, struct elf_link_hash_entry *, asection *);
 
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 3d4a458..bda1c3f 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -17365,39 +17365,6 @@ stm32l4xx_create_replacing_stub (struct elf32_arm_link_hash_table * htab,
 /* End of stm32l4xx work-around.  */
 
 
-static void
-elf32_arm_add_relocation (bfd *output_bfd, struct bfd_link_info *info,
-			  asection *output_sec, Elf_Internal_Rela *rel)
-{
-  BFD_ASSERT (output_sec && rel);
-  struct bfd_elf_section_reloc_data *output_reldata;
-  struct elf32_arm_link_hash_table *htab;
-  struct bfd_elf_section_data *oesd = elf_section_data (output_sec);
-  Elf_Internal_Shdr *rel_hdr;
-
-
-  if (oesd->rel.hdr)
-    {
-      rel_hdr = oesd->rel.hdr;
-      output_reldata = &(oesd->rel);
-    }
-  else if (oesd->rela.hdr)
-    {
-      rel_hdr = oesd->rela.hdr;
-      output_reldata = &(oesd->rela);
-    }
-  else
-    {
-      abort ();
-    }
-
-  bfd_byte *erel = rel_hdr->contents;
-  erel += output_reldata->count * rel_hdr->sh_entsize;
-  htab = elf32_arm_hash_table (info);
-  SWAP_RELOC_OUT (htab) (output_bfd, rel, erel);
-  output_reldata->count++;
-}
-
 /* Do code byteswapping.  Return FALSE afterwards so that the section is
    written out as normal.  */
 
@@ -17649,18 +17616,6 @@ elf32_arm_write_section (bfd *output_bfd,
 			       adjust offset by hand.  */
 			    prel31_offset = text_sec->output_offset
 					    + text_sec->size;
-
-			    /* New relocation entity.  */
-			    asection *text_out = text_sec->output_section;
-			    Elf_Internal_Rela rel;
-			    rel.r_addend = 0;
-			    rel.r_offset = exidx_offset;
-			    rel.r_info = ELF32_R_INFO (text_out->target_index,
-						       R_ARM_PREL31);
-
-			    elf32_arm_add_relocation (output_bfd, link_info,
-						      sec->output_section,
-						      &rel);
 			  }
 
 			/* First address we can't unwind.  */
@@ -18175,6 +18130,69 @@ elf32_arm_count_additional_relocs (asection *sec)
   return arm_data->additional_reloc_count;
 }
 
+static unsigned int
+elf32_arm_count_output_relocs (struct bfd_link_info *info, asection *o)
+{
+  struct bfd_elf_section_data *esdo;
+  struct bfd_link_order *p;
+  bfd_size_type count;
+
+  esdo = elf_section_data (o->output_section);
+  if (esdo->this_hdr.sh_type != SHT_ARM_EXIDX)
+    return _bfd_elf_default_count_output_relocs (info, o);
+
+  count = 0;
+  for (p = o->map_head.link_order; p != NULL; p = p->next)
+    {
+      struct _arm_elf_section_data *arm_data;
+      arm_unwind_table_edit *edit_list;
+      Elf_Internal_Rela *relocs;
+      asection *sec;
+      unsigned int i;
+
+      if (p->type == bfd_section_reloc_link_order
+	  || p->type == bfd_symbol_reloc_link_order)
+	{
+	  count++;
+	  continue;
+	}
+
+      sec = p->u.indirect.section;
+      arm_data = get_arm_elf_section_data (sec);
+
+      if (arm_data->additional_reloc_count)
+	count += arm_data->additional_reloc_count;
+
+      edit_list = arm_data->u.exidx.unwind_edit_list;
+      if (!edit_list)
+	{
+	  count += sec->reloc_count;
+	  continue;
+	}
+
+      relocs = _bfd_elf_link_read_relocs (sec->owner, sec, NULL, NULL,
+					  info->keep_memory);
+
+      for (i = 0; i < sec->reloc_count; i++)
+	{
+	  arm_unwind_table_edit *edit_node;
+	  unsigned int index;
+
+	  index = (relocs[i].r_offset - sec->vma) / 8;
+
+	  for (edit_node = edit_list;
+	       edit_node->next && edit_node->next->index > index;
+	       edit_node++);
+
+	  if (edit_node->type != DELETE_EXIDX_ENTRY ||
+	      edit_node->index != index)
+	    count++;
+	}
+    }
+
+  return count;
+}
+
 /* Called to set the sh_flags, sh_link and sh_info fields of OSECTION which
    has a type >= SHT_LOOS.  Returns TRUE if these fields were initialised 
    FALSE otherwise.  ISECTION is the best guess matching section from the
@@ -18303,6 +18321,139 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
     sym->flags |= BSF_KEEP;
 }
 
+static bfd_boolean
+emit_relocs (bfd *output_bfd,
+	     asection *input_section,
+	     Elf_Internal_Shdr *input_rel_hdr,
+	     Elf_Internal_Rela *internal_relocs,
+	     struct elf_link_hash_entry **rel_hash,
+	     bfd_boolean (*fallback) (bfd *, asection *,
+				      Elf_Internal_Shdr *,
+				      Elf_Internal_Rela *,
+				      struct elf_link_hash_entry **))
+{
+  _arm_elf_section_data *arm_data;
+  struct bfd_elf_section_reloc_data *output_reldata;
+  Elf_Internal_Shdr *output_rel_hdr;
+  Elf_Internal_Rela *irela;
+  Elf_Internal_Rela *irelaend;
+  asection *output_section;
+  const struct elf_backend_data *bed;
+  void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
+  struct bfd_elf_section_data *esdo;
+  arm_unwind_table_edit *edit_list, *edit_tail;
+  bfd_byte *erel;
+  bfd_vma offset;
+
+  arm_data = get_arm_elf_section_data (input_section);
+
+  if (!arm_data || arm_data->elf.this_hdr.sh_type != SHT_ARM_EXIDX)
+    goto fallback_label;
+
+  edit_list = arm_data->u.exidx.unwind_edit_list;
+  edit_tail = arm_data->u.exidx.unwind_edit_tail;
+
+  if (!edit_list)
+    goto fallback_label;
+
+  output_section = input_section->output_section;
+  offset = output_section->vma + input_section->output_offset;
+
+  bed = get_elf_backend_data (output_bfd);
+  esdo = elf_section_data (output_section);
+  if (esdo->rel.hdr && esdo->rel.hdr->sh_entsize == input_rel_hdr->sh_entsize)
+    {
+      output_reldata = &esdo->rel;
+      swap_out = bed->s->swap_reloc_out;
+    }
+  else if (esdo->rela.hdr &&
+	   esdo->rela.hdr->sh_entsize == input_rel_hdr->sh_entsize)
+    {
+      output_reldata = &esdo->rela;
+      swap_out = bed->s->swap_reloca_out;
+    }
+  else
+    {
+      (*_bfd_error_handler)
+	(_("%B: relocation size mismatch in %B section %A"),
+	 output_bfd, input_section->owner, input_section);
+	 bfd_set_error (bfd_error_wrong_format);
+      return FALSE;
+    }
+
+  output_rel_hdr = output_reldata->hdr;
+  erel = output_rel_hdr->contents;
+  erel += output_reldata->count * input_rel_hdr->sh_entsize;
+
+  irela = internal_relocs;
+  irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr)
+		      * bed->s->int_rels_per_ext_rel);
+  while (irela < irelaend)
+    {
+      arm_unwind_table_edit *edit_node, *edit_next;
+      Elf_Internal_Rela rel;
+      bfd_vma bias;
+      bfd_vma index;
+
+      index = (irela->r_offset - offset) / 8;
+
+      bias = 0;
+      edit_node = edit_list;
+      for (edit_next = edit_list;
+	   edit_next && edit_next->index <= index;
+	   edit_next = edit_node->next)
+	{
+	  bias++;
+	  edit_node = edit_next;
+	}
+
+      if (edit_node->type != DELETE_EXIDX_ENTRY || edit_node->index != index)
+	{
+	  rel.r_offset = irela->r_offset - bias * 8;
+	  rel.r_info = irela->r_info;
+	  rel.r_addend = irela->r_addend;
+
+	  (*swap_out) (output_bfd, &rel, erel);
+	  erel += output_rel_hdr->sh_entsize;
+	  output_reldata->count++;
+	}
+
+      irela += bed->s->int_rels_per_ext_rel;
+    }
+
+  if (edit_tail->type == INSERT_EXIDX_CANTUNWIND_AT_END)
+    {
+      /* New relocation entity.  */
+      asection *text_sec = edit_tail->linked_section;
+      asection *text_out = text_sec->output_section;
+      bfd_vma exidx_offset = offset + input_section->size - 8;
+      Elf_Internal_Rela rel;
+
+      rel.r_addend = 0;
+      rel.r_offset = exidx_offset;
+      rel.r_info = ELF32_R_INFO (text_out->target_index, R_ARM_PREL31);
+      (*swap_out) (output_bfd, &rel, erel);
+      output_reldata->count++;
+    }
+
+  return TRUE;
+
+fallback_label:
+  return fallback (output_bfd, input_section, input_rel_hdr,
+		   internal_relocs, rel_hash);
+}
+
+static bfd_boolean
+elf32_arm_emit_relocs (bfd *output_bfd,
+			       asection *input_section,
+			       Elf_Internal_Shdr *input_rel_hdr,
+			       Elf_Internal_Rela *internal_relocs,
+			       struct elf_link_hash_entry **rel_hash)
+{
+  return emit_relocs (output_bfd, input_section, input_rel_hdr, internal_relocs,
+		      rel_hash, _bfd_elf_link_output_relocs);
+}
+
 #undef  elf_backend_copy_special_section_fields
 #define elf_backend_copy_special_section_fields elf32_arm_copy_special_section_fields
 
@@ -18333,6 +18484,7 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
 #define bfd_elf32_bfd_final_link		elf32_arm_final_link
 #define bfd_elf32_get_synthetic_symtab  elf32_arm_get_synthetic_symtab
 
+#define elf_backend_emit_relocs			elf32_arm_emit_relocs
 #define elf_backend_get_symbol_type             elf32_arm_get_symbol_type
 #define elf_backend_gc_mark_hook                elf32_arm_gc_mark_hook
 #define elf_backend_gc_mark_extra_sections	elf32_arm_gc_mark_extra_sections
@@ -18361,6 +18513,7 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
 #define elf_backend_begin_write_processing      elf32_arm_begin_write_processing
 #define elf_backend_add_symbol_hook		elf32_arm_add_symbol_hook
 #define elf_backend_count_additional_relocs	elf32_arm_count_additional_relocs
+#define elf_backend_count_output_relocs		elf32_arm_count_output_relocs
 #define elf_backend_symbol_processing		elf32_arm_backend_symbol_processing
 
 #define elf_backend_can_refcount       1
@@ -18527,6 +18680,17 @@ elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
   elf_vxworks_final_write_processing (abfd, linker);
 }
 
+static bfd_boolean
+elf32_arm_vxworks_emit_relocs (bfd *output_bfd,
+			       asection *input_section,
+			       Elf_Internal_Shdr *input_rel_hdr,
+			       Elf_Internal_Rela *internal_relocs,
+			       struct elf_link_hash_entry **rel_hash)
+{
+  return emit_relocs (output_bfd, input_section, input_rel_hdr, internal_relocs,
+		      rel_hash, elf_vxworks_emit_relocs);
+}
+
 #undef  elf32_bed
 #define elf32_bed elf32_arm_vxworks_bed
 
@@ -18535,7 +18699,7 @@ elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
 #undef  elf_backend_final_write_processing
 #define elf_backend_final_write_processing	elf32_arm_vxworks_final_write_processing
 #undef  elf_backend_emit_relocs
-#define elf_backend_emit_relocs			elf_vxworks_emit_relocs
+#define elf_backend_emit_relocs			elf32_arm_vxworks_emit_relocs
 
 #undef  elf_backend_may_use_rel_p
 #define elf_backend_may_use_rel_p	0
@@ -18899,6 +19063,7 @@ elf32_arm_symbian_plt_sym_val (bfd_vma i, const asection *plt,
   (SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED)
 
 #undef elf_backend_emit_relocs
+#define elf_backend_emit_relocs			elf32_arm_emit_relocs
 
 #undef  bfd_elf32_bfd_link_hash_table_create
 #define bfd_elf32_bfd_link_hash_table_create	elf32_arm_symbian_link_hash_table_create
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 3e24940..0f6fae7 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -2447,13 +2447,29 @@ _bfd_elf_link_read_relocs (bfd *abfd,
    section header for a section containing relocations for O.  */
 
 static bfd_boolean
-_bfd_elf_link_size_reloc_section (bfd *abfd,
-				  struct bfd_elf_section_reloc_data *reldata)
+_bfd_elf_link_size_reloc_section (bfd *abfd, struct bfd_link_info *info,
+				  asection *o)
 {
-  Elf_Internal_Shdr *rel_hdr = reldata->hdr;
+  struct bfd_elf_section_data *esdo;
+  const struct elf_backend_data *bed;
+  struct bfd_elf_section_reloc_data *reldata;
+  Elf_Internal_Shdr *rel_hdr;
+  unsigned int count;
+
+  esdo = elf_section_data (o);
+  if (esdo->rel.hdr)
+    reldata = &esdo->rel;
+  else if (esdo->rela.hdr)
+    reldata = &esdo->rela;
+  else
+    return TRUE;
+
+  rel_hdr = reldata->hdr;
 
   /* That allows us to calculate the size of the section.  */
-  rel_hdr->sh_size = rel_hdr->sh_entsize * reldata->count;
+  bed = get_elf_backend_data (abfd);
+  count = (*bed->elf_backend_count_output_relocs) (info, o);
+  rel_hdr->sh_size = count * rel_hdr->sh_entsize;
 
   /* The contents field must last into write_object_contents, so we
      allocate it with bfd_alloc rather than malloc.  Also since we
@@ -2541,6 +2557,24 @@ _bfd_elf_link_output_relocs (bfd *output_bfd,
 
   return TRUE;
 }
+
+unsigned int
+_bfd_elf_default_count_output_relocs (
+  struct bfd_link_info *info ATTRIBUTE_UNUSED, asection *o)
+{
+  struct bfd_elf_section_data *esdo;
+  struct bfd_elf_section_reloc_data *reldata;
+
+  esdo = elf_section_data (o);
+  if (esdo->rel.hdr)
+    reldata = &esdo->rel;
+  else if (esdo->rela.hdr)
+    reldata = &esdo->rela;
+  else
+    return TRUE;
+
+  return reldata->count;
+}
 \f
 /* Make weak undefined symbols in PIE dynamic.  */
 
@@ -11182,12 +11216,12 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   for (o = abfd->sections; o != NULL; o = o->next)
     {
       struct bfd_elf_section_data *esdo = elf_section_data (o);
+      unsigned int additional_reloc_count = 0;
       o->reloc_count = 0;
 
       for (p = o->map_head.link_order; p != NULL; p = p->next)
 	{
 	  unsigned int reloc_count = 0;
-	  unsigned int additional_reloc_count = 0;
 	  struct bfd_elf_section_data *esdi = NULL;
 
 	  if (p->type == bfd_section_reloc_link_order
@@ -11273,21 +11307,14 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 	  if (reloc_count == 0)
 	    continue;
 
-	  reloc_count += additional_reloc_count;
 	  o->reloc_count += reloc_count;
 
 	  if (p->type == bfd_indirect_link_order && emit_relocs)
 	    {
 	      if (esdi->rel.hdr)
-		{
 		  esdo->rel.count += NUM_SHDR_ENTRIES (esdi->rel.hdr);
-		  esdo->rel.count += additional_reloc_count;
-		}
 	      if (esdi->rela.hdr)
-		{
 		  esdo->rela.count += NUM_SHDR_ENTRIES (esdi->rela.hdr);
-		  esdo->rela.count += additional_reloc_count;
-		}
 	    }
 	  else
 	    {
@@ -11298,7 +11325,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 	    }
 	}
 
-      if (o->reloc_count > 0)
+      if (o->reloc_count > 0 || additional_reloc_count > 0)
 	o->flags |= SEC_RELOC;
       else
 	{
@@ -11335,12 +11362,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       struct bfd_elf_section_data *esdo = elf_section_data (o);
       if ((o->flags & SEC_RELOC) != 0)
 	{
-	  if (esdo->rel.hdr
-	      && !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rel)))
-	    goto error_return;
-
-	  if (esdo->rela.hdr
-	      && !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rela)))
+	  if (!(_bfd_elf_link_size_reloc_section (abfd, info, o)))
 	    goto error_return;
 	}
 
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index 97aa5e6..5424cf3 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -551,6 +551,9 @@
 #ifndef elf_backend_count_additional_relocs
 #define elf_backend_count_additional_relocs	NULL
 #endif
+#ifndef elf_backend_count_output_relocs
+#define elf_backend_count_output_relocs		_bfd_elf_default_count_output_relocs
+#endif
 #ifndef elf_backend_sort_relocs_p
 #define elf_backend_sort_relocs_p		NULL
 #endif
@@ -773,6 +776,7 @@ static struct elf_backend_data elfNN_bed =
   elf_backend_emit_relocs,
   elf_backend_count_relocs,
   elf_backend_count_additional_relocs,
+  elf_backend_count_output_relocs,
   elf_backend_sort_relocs_p,
   elf_backend_grok_prstatus,
   elf_backend_grok_psinfo,
-- 
2.9.3

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

* Re: [PATCH] ARM: Fix relocation of EXIDX sections
  2016-09-13  6:48 ` [PATCH] ARM: Fix relocation of EXIDX sections Akihiko Odaki
@ 2016-09-13  7:16   ` Andreas Schwab
  2016-09-13 10:04   ` [PATH v2] " Akihiko Odaki
  2016-09-23  5:46   ` [PATCH] " Akihiko Odaki
  2 siblings, 0 replies; 8+ messages in thread
From: Andreas Schwab @ 2016-09-13  7:16 UTC (permalink / raw)
  To: Akihiko Odaki; +Cc: binutils, Paul Brook, Yury Usishchev

On Sep 13 2016, Akihiko Odaki <akihiko.odaki.4i@stu.hosei.ac.jp> wrote:

> +unsigned int
> +_bfd_elf_default_count_output_relocs (
> +  struct bfd_link_info *info ATTRIBUTE_UNUSED, asection *o)
> +{
> +  struct bfd_elf_section_data *esdo;
> +  struct bfd_elf_section_reloc_data *reldata;
> +
> +  esdo = elf_section_data (o);
> +  if (esdo->rel.hdr)
> +    reldata = &esdo->rel;
> +  else if (esdo->rela.hdr)
> +    reldata = &esdo->rela;
> +  else
> +    return TRUE;

Returning TRUE in a function that returns a number doesn't make sense.

Andreas.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

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

* [PATH v2] ARM: Fix relocation of EXIDX sections
  2016-09-13  6:48 ` [PATCH] ARM: Fix relocation of EXIDX sections Akihiko Odaki
  2016-09-13  7:16   ` Andreas Schwab
@ 2016-09-13 10:04   ` Akihiko Odaki
  2016-09-22 16:04     ` Nick Clifton
  2016-09-23  5:46   ` [PATCH] " Akihiko Odaki
  2 siblings, 1 reply; 8+ messages in thread
From: Akihiko Odaki @ 2016-09-13 10:04 UTC (permalink / raw)
  To: binutils; +Cc: Andreas Schwab, Paul Brook, Yury Usishchev, Akihiko Odaki

As reported in PR binutils/20595, BFD has a bug that it doesn't delete
relocations for deleted exidx. This change fixes the behavior.

bfd * elf-bfd.h: Add callback to count relocations in the final output.
    * elf-arm.c (elf32_arm_add_relocation): Deleted.
    (elf32_arm_write_section): Move additional relocation to emit_relocs.
    (elf32_arm_count_output_relocs): New function.
    (emit_relocs): New function.
    (elf32_arm_emit_relocs): New function.
    (elf32_arm_vxworks_emit_relocs): New function.
    (elf_backend_emit_relocs): Updated to use the new functions.
    (elf_backend_count_output_relocs): New define.
    * bfd/elflink.c (bfd_elf_final_link): Do not add additional_reloc_count
    to the relocation count.
    (_bfd_elf_link_size_reloc_section): Use callback to count the
    relocations which will be in output.
    (_bfd_elf_default_count_output_relocs): New function.
    * bfd/elfxx-target.h (elf_backend_count_output_relocs): New define.
---
 bfd/elf-bfd.h      |   8 ++
 bfd/elf32-arm.c    | 257 +++++++++++++++++++++++++++++++++++++++++++----------
 bfd/elflink.c      |  60 +++++++++----
 bfd/elfxx-target.h |   4 +
 4 files changed, 264 insertions(+), 65 deletions(-)

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 163ef35..1c7aa5a 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1176,6 +1176,11 @@ struct elf_backend_data
   unsigned int (*elf_backend_count_additional_relocs)
     (asection *);
 
+  /* Count relocations to be output. The result may be different if the
+     input relocations are expected to be modified by the backend. */
+  unsigned int (* elf_backend_count_output_relocs)
+    (struct bfd_link_info *info, asection *o);
+
   /* Say whether to sort relocs output by ld -r and ld --emit-relocs,
      by r_offset.  If NULL, default to true.  */
   bfd_boolean (*sort_relocs_p)
@@ -2143,6 +2148,9 @@ extern bfd_boolean _bfd_elf_link_output_relocs
   (bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *,
    struct elf_link_hash_entry **);
 
+extern unsigned int _bfd_elf_default_count_output_relocs
+  (struct bfd_link_info *info ATTRIBUTE_UNUSED, asection *o);
+
 extern bfd_boolean _bfd_elf_adjust_dynamic_copy
   (struct bfd_link_info *, struct elf_link_hash_entry *, asection *);
 
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 3d4a458..bda1c3f 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -17365,39 +17365,6 @@ stm32l4xx_create_replacing_stub (struct elf32_arm_link_hash_table * htab,
 /* End of stm32l4xx work-around.  */
 
 
-static void
-elf32_arm_add_relocation (bfd *output_bfd, struct bfd_link_info *info,
-			  asection *output_sec, Elf_Internal_Rela *rel)
-{
-  BFD_ASSERT (output_sec && rel);
-  struct bfd_elf_section_reloc_data *output_reldata;
-  struct elf32_arm_link_hash_table *htab;
-  struct bfd_elf_section_data *oesd = elf_section_data (output_sec);
-  Elf_Internal_Shdr *rel_hdr;
-
-
-  if (oesd->rel.hdr)
-    {
-      rel_hdr = oesd->rel.hdr;
-      output_reldata = &(oesd->rel);
-    }
-  else if (oesd->rela.hdr)
-    {
-      rel_hdr = oesd->rela.hdr;
-      output_reldata = &(oesd->rela);
-    }
-  else
-    {
-      abort ();
-    }
-
-  bfd_byte *erel = rel_hdr->contents;
-  erel += output_reldata->count * rel_hdr->sh_entsize;
-  htab = elf32_arm_hash_table (info);
-  SWAP_RELOC_OUT (htab) (output_bfd, rel, erel);
-  output_reldata->count++;
-}
-
 /* Do code byteswapping.  Return FALSE afterwards so that the section is
    written out as normal.  */
 
@@ -17649,18 +17616,6 @@ elf32_arm_write_section (bfd *output_bfd,
 			       adjust offset by hand.  */
 			    prel31_offset = text_sec->output_offset
 					    + text_sec->size;
-
-			    /* New relocation entity.  */
-			    asection *text_out = text_sec->output_section;
-			    Elf_Internal_Rela rel;
-			    rel.r_addend = 0;
-			    rel.r_offset = exidx_offset;
-			    rel.r_info = ELF32_R_INFO (text_out->target_index,
-						       R_ARM_PREL31);
-
-			    elf32_arm_add_relocation (output_bfd, link_info,
-						      sec->output_section,
-						      &rel);
 			  }
 
 			/* First address we can't unwind.  */
@@ -18175,6 +18130,69 @@ elf32_arm_count_additional_relocs (asection *sec)
   return arm_data->additional_reloc_count;
 }
 
+static unsigned int
+elf32_arm_count_output_relocs (struct bfd_link_info *info, asection *o)
+{
+  struct bfd_elf_section_data *esdo;
+  struct bfd_link_order *p;
+  bfd_size_type count;
+
+  esdo = elf_section_data (o->output_section);
+  if (esdo->this_hdr.sh_type != SHT_ARM_EXIDX)
+    return _bfd_elf_default_count_output_relocs (info, o);
+
+  count = 0;
+  for (p = o->map_head.link_order; p != NULL; p = p->next)
+    {
+      struct _arm_elf_section_data *arm_data;
+      arm_unwind_table_edit *edit_list;
+      Elf_Internal_Rela *relocs;
+      asection *sec;
+      unsigned int i;
+
+      if (p->type == bfd_section_reloc_link_order
+	  || p->type == bfd_symbol_reloc_link_order)
+	{
+	  count++;
+	  continue;
+	}
+
+      sec = p->u.indirect.section;
+      arm_data = get_arm_elf_section_data (sec);
+
+      if (arm_data->additional_reloc_count)
+	count += arm_data->additional_reloc_count;
+
+      edit_list = arm_data->u.exidx.unwind_edit_list;
+      if (!edit_list)
+	{
+	  count += sec->reloc_count;
+	  continue;
+	}
+
+      relocs = _bfd_elf_link_read_relocs (sec->owner, sec, NULL, NULL,
+					  info->keep_memory);
+
+      for (i = 0; i < sec->reloc_count; i++)
+	{
+	  arm_unwind_table_edit *edit_node;
+	  unsigned int index;
+
+	  index = (relocs[i].r_offset - sec->vma) / 8;
+
+	  for (edit_node = edit_list;
+	       edit_node->next && edit_node->next->index > index;
+	       edit_node++);
+
+	  if (edit_node->type != DELETE_EXIDX_ENTRY ||
+	      edit_node->index != index)
+	    count++;
+	}
+    }
+
+  return count;
+}
+
 /* Called to set the sh_flags, sh_link and sh_info fields of OSECTION which
    has a type >= SHT_LOOS.  Returns TRUE if these fields were initialised 
    FALSE otherwise.  ISECTION is the best guess matching section from the
@@ -18303,6 +18321,139 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
     sym->flags |= BSF_KEEP;
 }
 
+static bfd_boolean
+emit_relocs (bfd *output_bfd,
+	     asection *input_section,
+	     Elf_Internal_Shdr *input_rel_hdr,
+	     Elf_Internal_Rela *internal_relocs,
+	     struct elf_link_hash_entry **rel_hash,
+	     bfd_boolean (*fallback) (bfd *, asection *,
+				      Elf_Internal_Shdr *,
+				      Elf_Internal_Rela *,
+				      struct elf_link_hash_entry **))
+{
+  _arm_elf_section_data *arm_data;
+  struct bfd_elf_section_reloc_data *output_reldata;
+  Elf_Internal_Shdr *output_rel_hdr;
+  Elf_Internal_Rela *irela;
+  Elf_Internal_Rela *irelaend;
+  asection *output_section;
+  const struct elf_backend_data *bed;
+  void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
+  struct bfd_elf_section_data *esdo;
+  arm_unwind_table_edit *edit_list, *edit_tail;
+  bfd_byte *erel;
+  bfd_vma offset;
+
+  arm_data = get_arm_elf_section_data (input_section);
+
+  if (!arm_data || arm_data->elf.this_hdr.sh_type != SHT_ARM_EXIDX)
+    goto fallback_label;
+
+  edit_list = arm_data->u.exidx.unwind_edit_list;
+  edit_tail = arm_data->u.exidx.unwind_edit_tail;
+
+  if (!edit_list)
+    goto fallback_label;
+
+  output_section = input_section->output_section;
+  offset = output_section->vma + input_section->output_offset;
+
+  bed = get_elf_backend_data (output_bfd);
+  esdo = elf_section_data (output_section);
+  if (esdo->rel.hdr && esdo->rel.hdr->sh_entsize == input_rel_hdr->sh_entsize)
+    {
+      output_reldata = &esdo->rel;
+      swap_out = bed->s->swap_reloc_out;
+    }
+  else if (esdo->rela.hdr &&
+	   esdo->rela.hdr->sh_entsize == input_rel_hdr->sh_entsize)
+    {
+      output_reldata = &esdo->rela;
+      swap_out = bed->s->swap_reloca_out;
+    }
+  else
+    {
+      (*_bfd_error_handler)
+	(_("%B: relocation size mismatch in %B section %A"),
+	 output_bfd, input_section->owner, input_section);
+	 bfd_set_error (bfd_error_wrong_format);
+      return FALSE;
+    }
+
+  output_rel_hdr = output_reldata->hdr;
+  erel = output_rel_hdr->contents;
+  erel += output_reldata->count * input_rel_hdr->sh_entsize;
+
+  irela = internal_relocs;
+  irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr)
+		      * bed->s->int_rels_per_ext_rel);
+  while (irela < irelaend)
+    {
+      arm_unwind_table_edit *edit_node, *edit_next;
+      Elf_Internal_Rela rel;
+      bfd_vma bias;
+      bfd_vma index;
+
+      index = (irela->r_offset - offset) / 8;
+
+      bias = 0;
+      edit_node = edit_list;
+      for (edit_next = edit_list;
+	   edit_next && edit_next->index <= index;
+	   edit_next = edit_node->next)
+	{
+	  bias++;
+	  edit_node = edit_next;
+	}
+
+      if (edit_node->type != DELETE_EXIDX_ENTRY || edit_node->index != index)
+	{
+	  rel.r_offset = irela->r_offset - bias * 8;
+	  rel.r_info = irela->r_info;
+	  rel.r_addend = irela->r_addend;
+
+	  (*swap_out) (output_bfd, &rel, erel);
+	  erel += output_rel_hdr->sh_entsize;
+	  output_reldata->count++;
+	}
+
+      irela += bed->s->int_rels_per_ext_rel;
+    }
+
+  if (edit_tail->type == INSERT_EXIDX_CANTUNWIND_AT_END)
+    {
+      /* New relocation entity.  */
+      asection *text_sec = edit_tail->linked_section;
+      asection *text_out = text_sec->output_section;
+      bfd_vma exidx_offset = offset + input_section->size - 8;
+      Elf_Internal_Rela rel;
+
+      rel.r_addend = 0;
+      rel.r_offset = exidx_offset;
+      rel.r_info = ELF32_R_INFO (text_out->target_index, R_ARM_PREL31);
+      (*swap_out) (output_bfd, &rel, erel);
+      output_reldata->count++;
+    }
+
+  return TRUE;
+
+fallback_label:
+  return fallback (output_bfd, input_section, input_rel_hdr,
+		   internal_relocs, rel_hash);
+}
+
+static bfd_boolean
+elf32_arm_emit_relocs (bfd *output_bfd,
+			       asection *input_section,
+			       Elf_Internal_Shdr *input_rel_hdr,
+			       Elf_Internal_Rela *internal_relocs,
+			       struct elf_link_hash_entry **rel_hash)
+{
+  return emit_relocs (output_bfd, input_section, input_rel_hdr, internal_relocs,
+		      rel_hash, _bfd_elf_link_output_relocs);
+}
+
 #undef  elf_backend_copy_special_section_fields
 #define elf_backend_copy_special_section_fields elf32_arm_copy_special_section_fields
 
@@ -18333,6 +18484,7 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
 #define bfd_elf32_bfd_final_link		elf32_arm_final_link
 #define bfd_elf32_get_synthetic_symtab  elf32_arm_get_synthetic_symtab
 
+#define elf_backend_emit_relocs			elf32_arm_emit_relocs
 #define elf_backend_get_symbol_type             elf32_arm_get_symbol_type
 #define elf_backend_gc_mark_hook                elf32_arm_gc_mark_hook
 #define elf_backend_gc_mark_extra_sections	elf32_arm_gc_mark_extra_sections
@@ -18361,6 +18513,7 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
 #define elf_backend_begin_write_processing      elf32_arm_begin_write_processing
 #define elf_backend_add_symbol_hook		elf32_arm_add_symbol_hook
 #define elf_backend_count_additional_relocs	elf32_arm_count_additional_relocs
+#define elf_backend_count_output_relocs		elf32_arm_count_output_relocs
 #define elf_backend_symbol_processing		elf32_arm_backend_symbol_processing
 
 #define elf_backend_can_refcount       1
@@ -18527,6 +18680,17 @@ elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
   elf_vxworks_final_write_processing (abfd, linker);
 }
 
+static bfd_boolean
+elf32_arm_vxworks_emit_relocs (bfd *output_bfd,
+			       asection *input_section,
+			       Elf_Internal_Shdr *input_rel_hdr,
+			       Elf_Internal_Rela *internal_relocs,
+			       struct elf_link_hash_entry **rel_hash)
+{
+  return emit_relocs (output_bfd, input_section, input_rel_hdr, internal_relocs,
+		      rel_hash, elf_vxworks_emit_relocs);
+}
+
 #undef  elf32_bed
 #define elf32_bed elf32_arm_vxworks_bed
 
@@ -18535,7 +18699,7 @@ elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
 #undef  elf_backend_final_write_processing
 #define elf_backend_final_write_processing	elf32_arm_vxworks_final_write_processing
 #undef  elf_backend_emit_relocs
-#define elf_backend_emit_relocs			elf_vxworks_emit_relocs
+#define elf_backend_emit_relocs			elf32_arm_vxworks_emit_relocs
 
 #undef  elf_backend_may_use_rel_p
 #define elf_backend_may_use_rel_p	0
@@ -18899,6 +19063,7 @@ elf32_arm_symbian_plt_sym_val (bfd_vma i, const asection *plt,
   (SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED)
 
 #undef elf_backend_emit_relocs
+#define elf_backend_emit_relocs			elf32_arm_emit_relocs
 
 #undef  bfd_elf32_bfd_link_hash_table_create
 #define bfd_elf32_bfd_link_hash_table_create	elf32_arm_symbian_link_hash_table_create
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 3e24940..1d0e3ab 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -2447,13 +2447,29 @@ _bfd_elf_link_read_relocs (bfd *abfd,
    section header for a section containing relocations for O.  */
 
 static bfd_boolean
-_bfd_elf_link_size_reloc_section (bfd *abfd,
-				  struct bfd_elf_section_reloc_data *reldata)
+_bfd_elf_link_size_reloc_section (bfd *abfd, struct bfd_link_info *info,
+				  asection *o)
 {
-  Elf_Internal_Shdr *rel_hdr = reldata->hdr;
+  struct bfd_elf_section_data *esdo;
+  const struct elf_backend_data *bed;
+  struct bfd_elf_section_reloc_data *reldata;
+  Elf_Internal_Shdr *rel_hdr;
+  unsigned int count;
+
+  esdo = elf_section_data (o);
+  if (esdo->rel.hdr)
+    reldata = &esdo->rel;
+  else if (esdo->rela.hdr)
+    reldata = &esdo->rela;
+  else
+    return TRUE;
+
+  rel_hdr = reldata->hdr;
 
   /* That allows us to calculate the size of the section.  */
-  rel_hdr->sh_size = rel_hdr->sh_entsize * reldata->count;
+  bed = get_elf_backend_data (abfd);
+  count = (*bed->elf_backend_count_output_relocs) (info, o);
+  rel_hdr->sh_size = count * rel_hdr->sh_entsize;
 
   /* The contents field must last into write_object_contents, so we
      allocate it with bfd_alloc rather than malloc.  Also since we
@@ -2541,6 +2557,24 @@ _bfd_elf_link_output_relocs (bfd *output_bfd,
 
   return TRUE;
 }
+
+unsigned int
+_bfd_elf_default_count_output_relocs (
+  struct bfd_link_info *info ATTRIBUTE_UNUSED, asection *o)
+{
+  struct bfd_elf_section_data *esdo;
+  struct bfd_elf_section_reloc_data *reldata;
+
+  esdo = elf_section_data (o);
+  if (esdo->rel.hdr)
+    reldata = &esdo->rel;
+  else if (esdo->rela.hdr)
+    reldata = &esdo->rela;
+  else
+    abort ();
+
+  return reldata->count;
+}
 \f
 /* Make weak undefined symbols in PIE dynamic.  */
 
@@ -11182,12 +11216,12 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   for (o = abfd->sections; o != NULL; o = o->next)
     {
       struct bfd_elf_section_data *esdo = elf_section_data (o);
+      unsigned int additional_reloc_count = 0;
       o->reloc_count = 0;
 
       for (p = o->map_head.link_order; p != NULL; p = p->next)
 	{
 	  unsigned int reloc_count = 0;
-	  unsigned int additional_reloc_count = 0;
 	  struct bfd_elf_section_data *esdi = NULL;
 
 	  if (p->type == bfd_section_reloc_link_order
@@ -11273,21 +11307,14 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 	  if (reloc_count == 0)
 	    continue;
 
-	  reloc_count += additional_reloc_count;
 	  o->reloc_count += reloc_count;
 
 	  if (p->type == bfd_indirect_link_order && emit_relocs)
 	    {
 	      if (esdi->rel.hdr)
-		{
 		  esdo->rel.count += NUM_SHDR_ENTRIES (esdi->rel.hdr);
-		  esdo->rel.count += additional_reloc_count;
-		}
 	      if (esdi->rela.hdr)
-		{
 		  esdo->rela.count += NUM_SHDR_ENTRIES (esdi->rela.hdr);
-		  esdo->rela.count += additional_reloc_count;
-		}
 	    }
 	  else
 	    {
@@ -11298,7 +11325,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 	    }
 	}
 
-      if (o->reloc_count > 0)
+      if (o->reloc_count > 0 || additional_reloc_count > 0)
 	o->flags |= SEC_RELOC;
       else
 	{
@@ -11335,12 +11362,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       struct bfd_elf_section_data *esdo = elf_section_data (o);
       if ((o->flags & SEC_RELOC) != 0)
 	{
-	  if (esdo->rel.hdr
-	      && !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rel)))
-	    goto error_return;
-
-	  if (esdo->rela.hdr
-	      && !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rela)))
+	  if (!(_bfd_elf_link_size_reloc_section (abfd, info, o)))
 	    goto error_return;
 	}
 
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index 97aa5e6..5424cf3 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -551,6 +551,9 @@
 #ifndef elf_backend_count_additional_relocs
 #define elf_backend_count_additional_relocs	NULL
 #endif
+#ifndef elf_backend_count_output_relocs
+#define elf_backend_count_output_relocs		_bfd_elf_default_count_output_relocs
+#endif
 #ifndef elf_backend_sort_relocs_p
 #define elf_backend_sort_relocs_p		NULL
 #endif
@@ -773,6 +776,7 @@ static struct elf_backend_data elfNN_bed =
   elf_backend_emit_relocs,
   elf_backend_count_relocs,
   elf_backend_count_additional_relocs,
+  elf_backend_count_output_relocs,
   elf_backend_sort_relocs_p,
   elf_backend_grok_prstatus,
   elf_backend_grok_psinfo,
-- 
2.9.3

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

* Re: [PATH v2] ARM: Fix relocation of EXIDX sections
  2016-09-13 10:04   ` [PATH v2] " Akihiko Odaki
@ 2016-09-22 16:04     ` Nick Clifton
  0 siblings, 0 replies; 8+ messages in thread
From: Nick Clifton @ 2016-09-22 16:04 UTC (permalink / raw)
  To: Akihiko Odaki, binutils; +Cc: Andreas Schwab, Paul Brook, Yury Usishchev

Hi Akihiko-san,

> As reported in PR binutils/20595, BFD has a bug that it doesn't delete
> relocations for deleted exidx. This change fixes the behavior.

Unfortunately when I tried out this patch, it introduced a segmentation
fault into the linker if you build for the tic6-elf target.  (Try running
the linker testcase ld-tic6x/pcrel-reloc-local to see this happen).  The 
TIC6X target mixes both REL and RELA type relocs, which I presume is part 
of the problem.  Please could you investigate and fix this issue.

Cheers
  Nick

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

* [PATCH] ARM: Fix relocation of EXIDX sections
  2016-09-13  6:48 ` [PATCH] ARM: Fix relocation of EXIDX sections Akihiko Odaki
  2016-09-13  7:16   ` Andreas Schwab
  2016-09-13 10:04   ` [PATH v2] " Akihiko Odaki
@ 2016-09-23  5:46   ` Akihiko Odaki
  2016-09-23  5:49     ` Akihiko Odaki
  2 siblings, 1 reply; 8+ messages in thread
From: Akihiko Odaki @ 2016-09-23  5:46 UTC (permalink / raw)
  To: binutils
  Cc: Nick Clifton, Andreas Schwab, Paul Brook, Yury Usishchev, Akihiko Odaki

As reported in PR binutils/20595, BFD has a bug that it doesn't delete
relocations for deleted exidx. This change fixes the behavior.

bfd * elf-bfd.h: Add callback to count relocations in the final output.
    * elf-arm.c (elf32_arm_add_relocation): Deleted.
    (elf32_arm_write_section): Move additional relocation to emit_relocs.
    (elf32_arm_count_output_relocs): New function.
    (emit_relocs): New function.
    (elf32_arm_emit_relocs): New function.
    (elf32_arm_vxworks_emit_relocs): New function.
    (elf_backend_emit_relocs): Updated to use the new functions.
    (elf_backend_count_output_relocs): New define.
    * bfd/elflink.c (bfd_elf_final_link): Do not add additional_reloc_count
    to the relocation count.
    (_bfd_elf_link_size_reloc_section): Use callback to count the
    relocations which will be in output.
    (_bfd_elf_default_count_output_relocs): New function.
    * bfd/elfxx-target.h (elf_backend_count_output_relocs): New define.
---
 bfd/elf-bfd.h      |   8 ++
 bfd/elf32-arm.c    | 262 +++++++++++++++++++++++++++++++++++++++++++----------
 bfd/elflink.c      |  46 +++++++---
 bfd/elfxx-target.h |   4 +
 4 files changed, 259 insertions(+), 61 deletions(-)

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 163ef35..2f2b42c 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1176,6 +1176,11 @@ struct elf_backend_data
   unsigned int (*elf_backend_count_additional_relocs)
     (asection *);
 
+  /* Count relocations to be output. The result may be different if the
+     input relocations are expected to be modified by the backend. */
+  unsigned int (* elf_backend_count_output_relocs)
+    (struct bfd_link_info *info, asection *o, bfd_boolean rela);
+
   /* Say whether to sort relocs output by ld -r and ld --emit-relocs,
      by r_offset.  If NULL, default to true.  */
   bfd_boolean (*sort_relocs_p)
@@ -2143,6 +2148,9 @@ extern bfd_boolean _bfd_elf_link_output_relocs
   (bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *,
    struct elf_link_hash_entry **);
 
+extern unsigned int _bfd_elf_default_count_output_relocs
+  (struct bfd_link_info *info ATTRIBUTE_UNUSED, asection *o, bfd_boolean rela);
+
 extern bfd_boolean _bfd_elf_adjust_dynamic_copy
   (struct bfd_link_info *, struct elf_link_hash_entry *, asection *);
 
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 3d4a458..28c6fb1 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -17365,39 +17365,6 @@ stm32l4xx_create_replacing_stub (struct elf32_arm_link_hash_table * htab,
 /* End of stm32l4xx work-around.  */
 
 
-static void
-elf32_arm_add_relocation (bfd *output_bfd, struct bfd_link_info *info,
-			  asection *output_sec, Elf_Internal_Rela *rel)
-{
-  BFD_ASSERT (output_sec && rel);
-  struct bfd_elf_section_reloc_data *output_reldata;
-  struct elf32_arm_link_hash_table *htab;
-  struct bfd_elf_section_data *oesd = elf_section_data (output_sec);
-  Elf_Internal_Shdr *rel_hdr;
-
-
-  if (oesd->rel.hdr)
-    {
-      rel_hdr = oesd->rel.hdr;
-      output_reldata = &(oesd->rel);
-    }
-  else if (oesd->rela.hdr)
-    {
-      rel_hdr = oesd->rela.hdr;
-      output_reldata = &(oesd->rela);
-    }
-  else
-    {
-      abort ();
-    }
-
-  bfd_byte *erel = rel_hdr->contents;
-  erel += output_reldata->count * rel_hdr->sh_entsize;
-  htab = elf32_arm_hash_table (info);
-  SWAP_RELOC_OUT (htab) (output_bfd, rel, erel);
-  output_reldata->count++;
-}
-
 /* Do code byteswapping.  Return FALSE afterwards so that the section is
    written out as normal.  */
 
@@ -17649,18 +17616,6 @@ elf32_arm_write_section (bfd *output_bfd,
 			       adjust offset by hand.  */
 			    prel31_offset = text_sec->output_offset
 					    + text_sec->size;
-
-			    /* New relocation entity.  */
-			    asection *text_out = text_sec->output_section;
-			    Elf_Internal_Rela rel;
-			    rel.r_addend = 0;
-			    rel.r_offset = exidx_offset;
-			    rel.r_info = ELF32_R_INFO (text_out->target_index,
-						       R_ARM_PREL31);
-
-			    elf32_arm_add_relocation (output_bfd, link_info,
-						      sec->output_section,
-						      &rel);
 			  }
 
 			/* First address we can't unwind.  */
@@ -18175,6 +18130,74 @@ elf32_arm_count_additional_relocs (asection *sec)
   return arm_data->additional_reloc_count;
 }
 
+static unsigned int
+elf32_arm_count_output_relocs (struct bfd_link_info *info, asection *o,
+			       bfd_boolean rela)
+{
+  struct bfd_elf_section_data *esdo;
+  struct bfd_link_order *p;
+  bfd_size_type count;
+
+  esdo = elf_section_data (o->output_section);
+  if (esdo->this_hdr.sh_type != SHT_ARM_EXIDX)
+    return _bfd_elf_default_count_output_relocs (info, o, rela);
+
+  count = 0;
+  for (p = o->map_head.link_order; p != NULL; p = p->next)
+    {
+      struct _arm_elf_section_data *arm_data;
+      arm_unwind_table_edit *edit_list;
+      Elf_Internal_Rela *relocs;
+      asection *sec;
+      bfd_size_type num_rel;
+      bfd_size_type num_rela;
+      unsigned int i;
+
+      if (p->type == bfd_section_reloc_link_order
+	  || p->type == bfd_symbol_reloc_link_order)
+	{
+	  count++;
+	  continue;
+	}
+
+      sec = p->u.indirect.section;
+      arm_data = get_arm_elf_section_data (sec);
+
+      if (arm_data->additional_reloc_count)
+	count += arm_data->additional_reloc_count;
+
+      edit_list = arm_data->u.exidx.unwind_edit_list;
+      if (!edit_list)
+	{
+	  count += sec->reloc_count;
+	  continue;
+	}
+
+      relocs = _bfd_elf_link_read_relocs (sec->owner, sec, NULL, NULL,
+					  info->keep_memory);
+      num_rel = esdo->rel.hdr ? NUM_SHDR_ENTRIES (esdo->rel.hdr) : 0;
+      num_rela = esdo->rela.hdr ? NUM_SHDR_ENTRIES (esdo->rela.hdr) : 0;
+
+      for (i = rela ? num_rel : 0; i < (rela ? num_rela : num_rel); i++)
+	{
+	  arm_unwind_table_edit *edit_node;
+	  unsigned int index;
+
+	  index = (relocs[i].r_offset - sec->vma) / 8;
+
+	  for (edit_node = edit_list;
+	       edit_node->next && edit_node->next->index > index;
+	       edit_node++);
+
+	  if (edit_node->type != DELETE_EXIDX_ENTRY ||
+	      edit_node->index != index)
+	    count++;
+	}
+    }
+
+  return count;
+}
+
 /* Called to set the sh_flags, sh_link and sh_info fields of OSECTION which
    has a type >= SHT_LOOS.  Returns TRUE if these fields were initialised 
    FALSE otherwise.  ISECTION is the best guess matching section from the
@@ -18303,6 +18326,139 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
     sym->flags |= BSF_KEEP;
 }
 
+static bfd_boolean
+emit_relocs (bfd *output_bfd,
+	     asection *input_section,
+	     Elf_Internal_Shdr *input_rel_hdr,
+	     Elf_Internal_Rela *internal_relocs,
+	     struct elf_link_hash_entry **rel_hash,
+	     bfd_boolean (*fallback) (bfd *, asection *,
+				      Elf_Internal_Shdr *,
+				      Elf_Internal_Rela *,
+				      struct elf_link_hash_entry **))
+{
+  _arm_elf_section_data *arm_data;
+  struct bfd_elf_section_reloc_data *output_reldata;
+  Elf_Internal_Shdr *output_rel_hdr;
+  Elf_Internal_Rela *irela;
+  Elf_Internal_Rela *irelaend;
+  asection *output_section;
+  const struct elf_backend_data *bed;
+  void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
+  struct bfd_elf_section_data *esdo;
+  arm_unwind_table_edit *edit_list, *edit_tail;
+  bfd_byte *erel;
+  bfd_vma offset;
+
+  arm_data = get_arm_elf_section_data (input_section);
+
+  if (!arm_data || arm_data->elf.this_hdr.sh_type != SHT_ARM_EXIDX)
+    goto fallback_label;
+
+  edit_list = arm_data->u.exidx.unwind_edit_list;
+  edit_tail = arm_data->u.exidx.unwind_edit_tail;
+
+  if (!edit_list)
+    goto fallback_label;
+
+  output_section = input_section->output_section;
+  offset = output_section->vma + input_section->output_offset;
+
+  bed = get_elf_backend_data (output_bfd);
+  esdo = elf_section_data (output_section);
+  if (esdo->rel.hdr && esdo->rel.hdr->sh_entsize == input_rel_hdr->sh_entsize)
+    {
+      output_reldata = &esdo->rel;
+      swap_out = bed->s->swap_reloc_out;
+    }
+  else if (esdo->rela.hdr &&
+	   esdo->rela.hdr->sh_entsize == input_rel_hdr->sh_entsize)
+    {
+      output_reldata = &esdo->rela;
+      swap_out = bed->s->swap_reloca_out;
+    }
+  else
+    {
+      (*_bfd_error_handler)
+	(_("%B: relocation size mismatch in %B section %A"),
+	 output_bfd, input_section->owner, input_section);
+	 bfd_set_error (bfd_error_wrong_format);
+      return FALSE;
+    }
+
+  output_rel_hdr = output_reldata->hdr;
+  erel = output_rel_hdr->contents;
+  erel += output_reldata->count * input_rel_hdr->sh_entsize;
+
+  irela = internal_relocs;
+  irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr)
+		      * bed->s->int_rels_per_ext_rel);
+  while (irela < irelaend)
+    {
+      arm_unwind_table_edit *edit_node, *edit_next;
+      Elf_Internal_Rela rel;
+      bfd_vma bias;
+      bfd_vma index;
+
+      index = (irela->r_offset - offset) / 8;
+
+      bias = 0;
+      edit_node = edit_list;
+      for (edit_next = edit_list;
+	   edit_next && edit_next->index <= index;
+	   edit_next = edit_node->next)
+	{
+	  bias++;
+	  edit_node = edit_next;
+	}
+
+      if (edit_node->type != DELETE_EXIDX_ENTRY || edit_node->index != index)
+	{
+	  rel.r_offset = irela->r_offset - bias * 8;
+	  rel.r_info = irela->r_info;
+	  rel.r_addend = irela->r_addend;
+
+	  (*swap_out) (output_bfd, &rel, erel);
+	  erel += output_rel_hdr->sh_entsize;
+	  output_reldata->count++;
+	}
+
+      irela += bed->s->int_rels_per_ext_rel;
+    }
+
+  if (edit_tail->type == INSERT_EXIDX_CANTUNWIND_AT_END)
+    {
+      /* New relocation entity.  */
+      asection *text_sec = edit_tail->linked_section;
+      asection *text_out = text_sec->output_section;
+      bfd_vma exidx_offset = offset + input_section->size - 8;
+      Elf_Internal_Rela rel;
+
+      rel.r_addend = 0;
+      rel.r_offset = exidx_offset;
+      rel.r_info = ELF32_R_INFO (text_out->target_index, R_ARM_PREL31);
+      (*swap_out) (output_bfd, &rel, erel);
+      output_reldata->count++;
+    }
+
+  return TRUE;
+
+fallback_label:
+  return fallback (output_bfd, input_section, input_rel_hdr,
+		   internal_relocs, rel_hash);
+}
+
+static bfd_boolean
+elf32_arm_emit_relocs (bfd *output_bfd,
+			       asection *input_section,
+			       Elf_Internal_Shdr *input_rel_hdr,
+			       Elf_Internal_Rela *internal_relocs,
+			       struct elf_link_hash_entry **rel_hash)
+{
+  return emit_relocs (output_bfd, input_section, input_rel_hdr, internal_relocs,
+		      rel_hash, _bfd_elf_link_output_relocs);
+}
+
 #undef  elf_backend_copy_special_section_fields
 #define elf_backend_copy_special_section_fields elf32_arm_copy_special_section_fields
 
@@ -18333,6 +18489,7 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
 #define bfd_elf32_bfd_final_link		elf32_arm_final_link
 #define bfd_elf32_get_synthetic_symtab  elf32_arm_get_synthetic_symtab
 
+#define elf_backend_emit_relocs			elf32_arm_emit_relocs
 #define elf_backend_get_symbol_type             elf32_arm_get_symbol_type
 #define elf_backend_gc_mark_hook                elf32_arm_gc_mark_hook
 #define elf_backend_gc_mark_extra_sections	elf32_arm_gc_mark_extra_sections
@@ -18361,6 +18518,7 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
 #define elf_backend_begin_write_processing      elf32_arm_begin_write_processing
 #define elf_backend_add_symbol_hook		elf32_arm_add_symbol_hook
 #define elf_backend_count_additional_relocs	elf32_arm_count_additional_relocs
+#define elf_backend_count_output_relocs		elf32_arm_count_output_relocs
 #define elf_backend_symbol_processing		elf32_arm_backend_symbol_processing
 
 #define elf_backend_can_refcount       1
@@ -18527,6 +18685,17 @@ elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
   elf_vxworks_final_write_processing (abfd, linker);
 }
 
+static bfd_boolean
+elf32_arm_vxworks_emit_relocs (bfd *output_bfd,
+			       asection *input_section,
+			       Elf_Internal_Shdr *input_rel_hdr,
+			       Elf_Internal_Rela *internal_relocs,
+			       struct elf_link_hash_entry **rel_hash)
+{
+  return emit_relocs (output_bfd, input_section, input_rel_hdr, internal_relocs,
+		      rel_hash, elf_vxworks_emit_relocs);
+}
+
 #undef  elf32_bed
 #define elf32_bed elf32_arm_vxworks_bed
 
@@ -18535,7 +18704,7 @@ elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
 #undef  elf_backend_final_write_processing
 #define elf_backend_final_write_processing	elf32_arm_vxworks_final_write_processing
 #undef  elf_backend_emit_relocs
-#define elf_backend_emit_relocs			elf_vxworks_emit_relocs
+#define elf_backend_emit_relocs			elf32_arm_vxworks_emit_relocs
 
 #undef  elf_backend_may_use_rel_p
 #define elf_backend_may_use_rel_p	0
@@ -18899,6 +19068,7 @@ elf32_arm_symbian_plt_sym_val (bfd_vma i, const asection *plt,
   (SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED)
 
 #undef elf_backend_emit_relocs
+#define elf_backend_emit_relocs			elf32_arm_emit_relocs
 
 #undef  bfd_elf32_bfd_link_hash_table_create
 #define bfd_elf32_bfd_link_hash_table_create	elf32_arm_symbian_link_hash_table_create
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 3e24940..20e7086 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -2447,13 +2447,23 @@ _bfd_elf_link_read_relocs (bfd *abfd,
    section header for a section containing relocations for O.  */
 
 static bfd_boolean
-_bfd_elf_link_size_reloc_section (bfd *abfd,
-				  struct bfd_elf_section_reloc_data *reldata)
+_bfd_elf_link_size_reloc_section (bfd *abfd, struct bfd_link_info *info,
+				  asection *o, bfd_boolean rela)
 {
-  Elf_Internal_Shdr *rel_hdr = reldata->hdr;
+  struct bfd_elf_section_data *esdo;
+  const struct elf_backend_data *bed;
+  struct bfd_elf_section_reloc_data *reldata;
+  Elf_Internal_Shdr *rel_hdr;
+  unsigned int count;
+
+  esdo = elf_section_data (o);
+  reldata = rela ? &esdo->rela : &esdo->rel;
+  rel_hdr = reldata->hdr;
 
   /* That allows us to calculate the size of the section.  */
-  rel_hdr->sh_size = rel_hdr->sh_entsize * reldata->count;
+  bed = get_elf_backend_data (abfd);
+  count = (*bed->elf_backend_count_output_relocs) (info, o, rela);
+  rel_hdr->sh_size = count * rel_hdr->sh_entsize;
 
   /* The contents field must last into write_object_contents, so we
      allocate it with bfd_alloc rather than malloc.  Also since we
@@ -2541,6 +2551,19 @@ _bfd_elf_link_output_relocs (bfd *output_bfd,
 
   return TRUE;
 }
+
+unsigned int
+_bfd_elf_default_count_output_relocs (
+  struct bfd_link_info *info ATTRIBUTE_UNUSED, asection *o, bfd_boolean rela)
+{
+  struct bfd_elf_section_data *esdo;
+  struct bfd_elf_section_reloc_data *reldata;
+
+  esdo = elf_section_data (o);
+  reldata = rela ? &esdo->rela : &esdo->rel;
+
+  return reldata->count;
+}
 \f
 /* Make weak undefined symbols in PIE dynamic.  */
 
@@ -11182,12 +11205,12 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   for (o = abfd->sections; o != NULL; o = o->next)
     {
       struct bfd_elf_section_data *esdo = elf_section_data (o);
+      unsigned int additional_reloc_count = 0;
       o->reloc_count = 0;
 
       for (p = o->map_head.link_order; p != NULL; p = p->next)
 	{
 	  unsigned int reloc_count = 0;
-	  unsigned int additional_reloc_count = 0;
 	  struct bfd_elf_section_data *esdi = NULL;
 
 	  if (p->type == bfd_section_reloc_link_order
@@ -11273,21 +11296,14 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 	  if (reloc_count == 0)
 	    continue;
 
-	  reloc_count += additional_reloc_count;
 	  o->reloc_count += reloc_count;
 
 	  if (p->type == bfd_indirect_link_order && emit_relocs)
 	    {
 	      if (esdi->rel.hdr)
-		{
 		  esdo->rel.count += NUM_SHDR_ENTRIES (esdi->rel.hdr);
-		  esdo->rel.count += additional_reloc_count;
-		}
 	      if (esdi->rela.hdr)
-		{
 		  esdo->rela.count += NUM_SHDR_ENTRIES (esdi->rela.hdr);
-		  esdo->rela.count += additional_reloc_count;
-		}
 	    }
 	  else
 	    {
@@ -11298,7 +11314,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 	    }
 	}
 
-      if (o->reloc_count > 0)
+      if (o->reloc_count > 0 || additional_reloc_count > 0)
 	o->flags |= SEC_RELOC;
       else
 	{
@@ -11336,11 +11352,11 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       if ((o->flags & SEC_RELOC) != 0)
 	{
 	  if (esdo->rel.hdr
-	      && !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rel)))
+	      && !(_bfd_elf_link_size_reloc_section (abfd, info, o, FALSE)))
 	    goto error_return;
 
 	  if (esdo->rela.hdr
-	      && !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rela)))
+	      && !(_bfd_elf_link_size_reloc_section (abfd, info, o, TRUE)))
 	    goto error_return;
 	}
 
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index 97aa5e6..5424cf3 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -551,6 +551,9 @@
 #ifndef elf_backend_count_additional_relocs
 #define elf_backend_count_additional_relocs	NULL
 #endif
+#ifndef elf_backend_count_output_relocs
+#define elf_backend_count_output_relocs		_bfd_elf_default_count_output_relocs
+#endif
 #ifndef elf_backend_sort_relocs_p
 #define elf_backend_sort_relocs_p		NULL
 #endif
@@ -773,6 +776,7 @@ static struct elf_backend_data elfNN_bed =
   elf_backend_emit_relocs,
   elf_backend_count_relocs,
   elf_backend_count_additional_relocs,
+  elf_backend_count_output_relocs,
   elf_backend_sort_relocs_p,
   elf_backend_grok_prstatus,
   elf_backend_grok_psinfo,
-- 
2.9.3

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

* Re: [PATCH] ARM: Fix relocation of EXIDX sections
  2016-09-23  5:46   ` [PATCH] " Akihiko Odaki
@ 2016-09-23  5:49     ` Akihiko Odaki
  2016-09-23  9:55       ` Nick Clifton
  0 siblings, 1 reply; 8+ messages in thread
From: Akihiko Odaki @ 2016-09-23  5:49 UTC (permalink / raw)
  To: binutils; +Cc: Nick Clifton, Andreas Schwab, Paul Brook, Yury Usishchev

Sorry, I forgot to change the subject prefix. This is v3, fixing the 
issue reported by Nick Clifton:
https://sourceware.org/ml/binutils/2016-09/msg00151.html

On 2016-09-23 14:45, Akihiko Odaki wrote:
> As reported in PR binutils/20595, BFD has a bug that it doesn't delete
> relocations for deleted exidx. This change fixes the behavior.
>
> bfd * elf-bfd.h: Add callback to count relocations in the final output.
>     * elf-arm.c (elf32_arm_add_relocation): Deleted.
>     (elf32_arm_write_section): Move additional relocation to emit_relocs.
>     (elf32_arm_count_output_relocs): New function.
>     (emit_relocs): New function.
>     (elf32_arm_emit_relocs): New function.
>     (elf32_arm_vxworks_emit_relocs): New function.
>     (elf_backend_emit_relocs): Updated to use the new functions.
>     (elf_backend_count_output_relocs): New define.
>     * bfd/elflink.c (bfd_elf_final_link): Do not add additional_reloc_count
>     to the relocation count.
>     (_bfd_elf_link_size_reloc_section): Use callback to count the
>     relocations which will be in output.
>     (_bfd_elf_default_count_output_relocs): New function.
>     * bfd/elfxx-target.h (elf_backend_count_output_relocs): New define.
> ---
>  bfd/elf-bfd.h      |   8 ++
>  bfd/elf32-arm.c    | 262 +++++++++++++++++++++++++++++++++++++++++++----------
>  bfd/elflink.c      |  46 +++++++---
>  bfd/elfxx-target.h |   4 +
>  4 files changed, 259 insertions(+), 61 deletions(-)
>
> diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
> index 163ef35..2f2b42c 100644
> --- a/bfd/elf-bfd.h
> +++ b/bfd/elf-bfd.h
> @@ -1176,6 +1176,11 @@ struct elf_backend_data
>    unsigned int (*elf_backend_count_additional_relocs)
>      (asection *);
>
> +  /* Count relocations to be output. The result may be different if the
> +     input relocations are expected to be modified by the backend. */
> +  unsigned int (* elf_backend_count_output_relocs)
> +    (struct bfd_link_info *info, asection *o, bfd_boolean rela);
> +
>    /* Say whether to sort relocs output by ld -r and ld --emit-relocs,
>       by r_offset.  If NULL, default to true.  */
>    bfd_boolean (*sort_relocs_p)
> @@ -2143,6 +2148,9 @@ extern bfd_boolean _bfd_elf_link_output_relocs
>    (bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *,
>     struct elf_link_hash_entry **);
>
> +extern unsigned int _bfd_elf_default_count_output_relocs
> +  (struct bfd_link_info *info ATTRIBUTE_UNUSED, asection *o, bfd_boolean rela);
> +
>  extern bfd_boolean _bfd_elf_adjust_dynamic_copy
>    (struct bfd_link_info *, struct elf_link_hash_entry *, asection *);
>
> diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
> index 3d4a458..28c6fb1 100644
> --- a/bfd/elf32-arm.c
> +++ b/bfd/elf32-arm.c
> @@ -17365,39 +17365,6 @@ stm32l4xx_create_replacing_stub (struct elf32_arm_link_hash_table * htab,
>  /* End of stm32l4xx work-around.  */
>
>
> -static void
> -elf32_arm_add_relocation (bfd *output_bfd, struct bfd_link_info *info,
> -			  asection *output_sec, Elf_Internal_Rela *rel)
> -{
> -  BFD_ASSERT (output_sec && rel);
> -  struct bfd_elf_section_reloc_data *output_reldata;
> -  struct elf32_arm_link_hash_table *htab;
> -  struct bfd_elf_section_data *oesd = elf_section_data (output_sec);
> -  Elf_Internal_Shdr *rel_hdr;
> -
> -
> -  if (oesd->rel.hdr)
> -    {
> -      rel_hdr = oesd->rel.hdr;
> -      output_reldata = &(oesd->rel);
> -    }
> -  else if (oesd->rela.hdr)
> -    {
> -      rel_hdr = oesd->rela.hdr;
> -      output_reldata = &(oesd->rela);
> -    }
> -  else
> -    {
> -      abort ();
> -    }
> -
> -  bfd_byte *erel = rel_hdr->contents;
> -  erel += output_reldata->count * rel_hdr->sh_entsize;
> -  htab = elf32_arm_hash_table (info);
> -  SWAP_RELOC_OUT (htab) (output_bfd, rel, erel);
> -  output_reldata->count++;
> -}
> -
>  /* Do code byteswapping.  Return FALSE afterwards so that the section is
>     written out as normal.  */
>
> @@ -17649,18 +17616,6 @@ elf32_arm_write_section (bfd *output_bfd,
>  			       adjust offset by hand.  */
>  			    prel31_offset = text_sec->output_offset
>  					    + text_sec->size;
> -
> -			    /* New relocation entity.  */
> -			    asection *text_out = text_sec->output_section;
> -			    Elf_Internal_Rela rel;
> -			    rel.r_addend = 0;
> -			    rel.r_offset = exidx_offset;
> -			    rel.r_info = ELF32_R_INFO (text_out->target_index,
> -						       R_ARM_PREL31);
> -
> -			    elf32_arm_add_relocation (output_bfd, link_info,
> -						      sec->output_section,
> -						      &rel);
>  			  }
>
>  			/* First address we can't unwind.  */
> @@ -18175,6 +18130,74 @@ elf32_arm_count_additional_relocs (asection *sec)
>    return arm_data->additional_reloc_count;
>  }
>
> +static unsigned int
> +elf32_arm_count_output_relocs (struct bfd_link_info *info, asection *o,
> +			       bfd_boolean rela)
> +{
> +  struct bfd_elf_section_data *esdo;
> +  struct bfd_link_order *p;
> +  bfd_size_type count;
> +
> +  esdo = elf_section_data (o->output_section);
> +  if (esdo->this_hdr.sh_type != SHT_ARM_EXIDX)
> +    return _bfd_elf_default_count_output_relocs (info, o, rela);
> +
> +  count = 0;
> +  for (p = o->map_head.link_order; p != NULL; p = p->next)
> +    {
> +      struct _arm_elf_section_data *arm_data;
> +      arm_unwind_table_edit *edit_list;
> +      Elf_Internal_Rela *relocs;
> +      asection *sec;
> +      bfd_size_type num_rel;
> +      bfd_size_type num_rela;
> +      unsigned int i;
> +
> +      if (p->type == bfd_section_reloc_link_order
> +	  || p->type == bfd_symbol_reloc_link_order)
> +	{
> +	  count++;
> +	  continue;
> +	}
> +
> +      sec = p->u.indirect.section;
> +      arm_data = get_arm_elf_section_data (sec);
> +
> +      if (arm_data->additional_reloc_count)
> +	count += arm_data->additional_reloc_count;
> +
> +      edit_list = arm_data->u.exidx.unwind_edit_list;
> +      if (!edit_list)
> +	{
> +	  count += sec->reloc_count;
> +	  continue;
> +	}
> +
> +      relocs = _bfd_elf_link_read_relocs (sec->owner, sec, NULL, NULL,
> +					  info->keep_memory);
> +      num_rel = esdo->rel.hdr ? NUM_SHDR_ENTRIES (esdo->rel.hdr) : 0;
> +      num_rela = esdo->rela.hdr ? NUM_SHDR_ENTRIES (esdo->rela.hdr) : 0;
> +
> +      for (i = rela ? num_rel : 0; i < (rela ? num_rela : num_rel); i++)
> +	{
> +	  arm_unwind_table_edit *edit_node;
> +	  unsigned int index;
> +
> +	  index = (relocs[i].r_offset - sec->vma) / 8;
> +
> +	  for (edit_node = edit_list;
> +	       edit_node->next && edit_node->next->index > index;
> +	       edit_node++);
> +
> +	  if (edit_node->type != DELETE_EXIDX_ENTRY ||
> +	      edit_node->index != index)
> +	    count++;
> +	}
> +    }
> +
> +  return count;
> +}
> +
>  /* Called to set the sh_flags, sh_link and sh_info fields of OSECTION which
>     has a type >= SHT_LOOS.  Returns TRUE if these fields were initialised
>     FALSE otherwise.  ISECTION is the best guess matching section from the
> @@ -18303,6 +18326,139 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
>      sym->flags |= BSF_KEEP;
>  }
>
> +static bfd_boolean
> +emit_relocs (bfd *output_bfd,
> +	     asection *input_section,
> +	     Elf_Internal_Shdr *input_rel_hdr,
> +	     Elf_Internal_Rela *internal_relocs,
> +	     struct elf_link_hash_entry **rel_hash,
> +	     bfd_boolean (*fallback) (bfd *, asection *,
> +				      Elf_Internal_Shdr *,
> +				      Elf_Internal_Rela *,
> +				      struct elf_link_hash_entry **))
> +{
> +  _arm_elf_section_data *arm_data;
> +  struct bfd_elf_section_reloc_data *output_reldata;
> +  Elf_Internal_Shdr *output_rel_hdr;
> +  Elf_Internal_Rela *irela;
> +  Elf_Internal_Rela *irelaend;
> +  asection *output_section;
> +  const struct elf_backend_data *bed;
> +  void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
> +  struct bfd_elf_section_data *esdo;
> +  arm_unwind_table_edit *edit_list, *edit_tail;
> +  bfd_byte *erel;
> +  bfd_vma offset;
> +
> +  arm_data = get_arm_elf_section_data (input_section);
> +
> +  if (!arm_data || arm_data->elf.this_hdr.sh_type != SHT_ARM_EXIDX)
> +    goto fallback_label;
> +
> +  edit_list = arm_data->u.exidx.unwind_edit_list;
> +  edit_tail = arm_data->u.exidx.unwind_edit_tail;
> +
> +  if (!edit_list)
> +    goto fallback_label;
> +
> +  output_section = input_section->output_section;
> +  offset = output_section->vma + input_section->output_offset;
> +
> +  bed = get_elf_backend_data (output_bfd);
> +  esdo = elf_section_data (output_section);
> +  if (esdo->rel.hdr && esdo->rel.hdr->sh_entsize == input_rel_hdr->sh_entsize)
> +    {
> +      output_reldata = &esdo->rel;
> +      swap_out = bed->s->swap_reloc_out;
> +    }
> +  else if (esdo->rela.hdr &&
> +	   esdo->rela.hdr->sh_entsize == input_rel_hdr->sh_entsize)
> +    {
> +      output_reldata = &esdo->rela;
> +      swap_out = bed->s->swap_reloca_out;
> +    }
> +  else
> +    {
> +      (*_bfd_error_handler)
> +	(_("%B: relocation size mismatch in %B section %A"),
> +	 output_bfd, input_section->owner, input_section);
> +	 bfd_set_error (bfd_error_wrong_format);
> +      return FALSE;
> +    }
> +
> +  output_rel_hdr = output_reldata->hdr;
> +  erel = output_rel_hdr->contents;
> +  erel += output_reldata->count * input_rel_hdr->sh_entsize;
> +
> +  irela = internal_relocs;
> +  irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr)
> +		      * bed->s->int_rels_per_ext_rel);
> +  while (irela < irelaend)
> +    {
> +      arm_unwind_table_edit *edit_node, *edit_next;
> +      Elf_Internal_Rela rel;
> +      bfd_vma bias;
> +      bfd_vma index;
> +
> +      index = (irela->r_offset - offset) / 8;
> +
> +      bias = 0;
> +      edit_node = edit_list;
> +      for (edit_next = edit_list;
> +	   edit_next && edit_next->index <= index;
> +	   edit_next = edit_node->next)
> +	{
> +	  bias++;
> +	  edit_node = edit_next;
> +	}
> +
> +      if (edit_node->type != DELETE_EXIDX_ENTRY || edit_node->index != index)
> +	{
> +	  rel.r_offset = irela->r_offset - bias * 8;
> +	  rel.r_info = irela->r_info;
> +	  rel.r_addend = irela->r_addend;
> +
> +	  (*swap_out) (output_bfd, &rel, erel);
> +	  erel += output_rel_hdr->sh_entsize;
> +	  output_reldata->count++;
> +	}
> +
> +      irela += bed->s->int_rels_per_ext_rel;
> +    }
> +
> +  if (edit_tail->type == INSERT_EXIDX_CANTUNWIND_AT_END)
> +    {
> +      /* New relocation entity.  */
> +      asection *text_sec = edit_tail->linked_section;
> +      asection *text_out = text_sec->output_section;
> +      bfd_vma exidx_offset = offset + input_section->size - 8;
> +      Elf_Internal_Rela rel;
> +
> +      rel.r_addend = 0;
> +      rel.r_offset = exidx_offset;
> +      rel.r_info = ELF32_R_INFO (text_out->target_index, R_ARM_PREL31);
> +      (*swap_out) (output_bfd, &rel, erel);
> +      output_reldata->count++;
> +    }
> +
> +  return TRUE;
> +
> +fallback_label:
> +  return fallback (output_bfd, input_section, input_rel_hdr,
> +		   internal_relocs, rel_hash);
> +}
> +
> +static bfd_boolean
> +elf32_arm_emit_relocs (bfd *output_bfd,
> +			       asection *input_section,
> +			       Elf_Internal_Shdr *input_rel_hdr,
> +			       Elf_Internal_Rela *internal_relocs,
> +			       struct elf_link_hash_entry **rel_hash)
> +{
> +  return emit_relocs (output_bfd, input_section, input_rel_hdr, internal_relocs,
> +		      rel_hash, _bfd_elf_link_output_relocs);
> +}
> +
>  #undef  elf_backend_copy_special_section_fields
>  #define elf_backend_copy_special_section_fields elf32_arm_copy_special_section_fields
>
> @@ -18333,6 +18489,7 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
>  #define bfd_elf32_bfd_final_link		elf32_arm_final_link
>  #define bfd_elf32_get_synthetic_symtab  elf32_arm_get_synthetic_symtab
>
> +#define elf_backend_emit_relocs			elf32_arm_emit_relocs
>  #define elf_backend_get_symbol_type             elf32_arm_get_symbol_type
>  #define elf_backend_gc_mark_hook                elf32_arm_gc_mark_hook
>  #define elf_backend_gc_mark_extra_sections	elf32_arm_gc_mark_extra_sections
> @@ -18361,6 +18518,7 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
>  #define elf_backend_begin_write_processing      elf32_arm_begin_write_processing
>  #define elf_backend_add_symbol_hook		elf32_arm_add_symbol_hook
>  #define elf_backend_count_additional_relocs	elf32_arm_count_additional_relocs
> +#define elf_backend_count_output_relocs		elf32_arm_count_output_relocs
>  #define elf_backend_symbol_processing		elf32_arm_backend_symbol_processing
>
>  #define elf_backend_can_refcount       1
> @@ -18527,6 +18685,17 @@ elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
>    elf_vxworks_final_write_processing (abfd, linker);
>  }
>
> +static bfd_boolean
> +elf32_arm_vxworks_emit_relocs (bfd *output_bfd,
> +			       asection *input_section,
> +			       Elf_Internal_Shdr *input_rel_hdr,
> +			       Elf_Internal_Rela *internal_relocs,
> +			       struct elf_link_hash_entry **rel_hash)
> +{
> +  return emit_relocs (output_bfd, input_section, input_rel_hdr, internal_relocs,
> +		      rel_hash, elf_vxworks_emit_relocs);
> +}
> +
>  #undef  elf32_bed
>  #define elf32_bed elf32_arm_vxworks_bed
>
> @@ -18535,7 +18704,7 @@ elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
>  #undef  elf_backend_final_write_processing
>  #define elf_backend_final_write_processing	elf32_arm_vxworks_final_write_processing
>  #undef  elf_backend_emit_relocs
> -#define elf_backend_emit_relocs			elf_vxworks_emit_relocs
> +#define elf_backend_emit_relocs			elf32_arm_vxworks_emit_relocs
>
>  #undef  elf_backend_may_use_rel_p
>  #define elf_backend_may_use_rel_p	0
> @@ -18899,6 +19068,7 @@ elf32_arm_symbian_plt_sym_val (bfd_vma i, const asection *plt,
>    (SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED)
>
>  #undef elf_backend_emit_relocs
> +#define elf_backend_emit_relocs			elf32_arm_emit_relocs
>
>  #undef  bfd_elf32_bfd_link_hash_table_create
>  #define bfd_elf32_bfd_link_hash_table_create	elf32_arm_symbian_link_hash_table_create
> diff --git a/bfd/elflink.c b/bfd/elflink.c
> index 3e24940..20e7086 100644
> --- a/bfd/elflink.c
> +++ b/bfd/elflink.c
> @@ -2447,13 +2447,23 @@ _bfd_elf_link_read_relocs (bfd *abfd,
>     section header for a section containing relocations for O.  */
>
>  static bfd_boolean
> -_bfd_elf_link_size_reloc_section (bfd *abfd,
> -				  struct bfd_elf_section_reloc_data *reldata)
> +_bfd_elf_link_size_reloc_section (bfd *abfd, struct bfd_link_info *info,
> +				  asection *o, bfd_boolean rela)
>  {
> -  Elf_Internal_Shdr *rel_hdr = reldata->hdr;
> +  struct bfd_elf_section_data *esdo;
> +  const struct elf_backend_data *bed;
> +  struct bfd_elf_section_reloc_data *reldata;
> +  Elf_Internal_Shdr *rel_hdr;
> +  unsigned int count;
> +
> +  esdo = elf_section_data (o);
> +  reldata = rela ? &esdo->rela : &esdo->rel;
> +  rel_hdr = reldata->hdr;
>
>    /* That allows us to calculate the size of the section.  */
> -  rel_hdr->sh_size = rel_hdr->sh_entsize * reldata->count;
> +  bed = get_elf_backend_data (abfd);
> +  count = (*bed->elf_backend_count_output_relocs) (info, o, rela);
> +  rel_hdr->sh_size = count * rel_hdr->sh_entsize;
>
>    /* The contents field must last into write_object_contents, so we
>       allocate it with bfd_alloc rather than malloc.  Also since we
> @@ -2541,6 +2551,19 @@ _bfd_elf_link_output_relocs (bfd *output_bfd,
>
>    return TRUE;
>  }
> +
> +unsigned int
> +_bfd_elf_default_count_output_relocs (
> +  struct bfd_link_info *info ATTRIBUTE_UNUSED, asection *o, bfd_boolean rela)
> +{
> +  struct bfd_elf_section_data *esdo;
> +  struct bfd_elf_section_reloc_data *reldata;
> +
> +  esdo = elf_section_data (o);
> +  reldata = rela ? &esdo->rela : &esdo->rel;
> +
> +  return reldata->count;
> +}
>  \f
>  /* Make weak undefined symbols in PIE dynamic.  */
>
> @@ -11182,12 +11205,12 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
>    for (o = abfd->sections; o != NULL; o = o->next)
>      {
>        struct bfd_elf_section_data *esdo = elf_section_data (o);
> +      unsigned int additional_reloc_count = 0;
>        o->reloc_count = 0;
>
>        for (p = o->map_head.link_order; p != NULL; p = p->next)
>  	{
>  	  unsigned int reloc_count = 0;
> -	  unsigned int additional_reloc_count = 0;
>  	  struct bfd_elf_section_data *esdi = NULL;
>
>  	  if (p->type == bfd_section_reloc_link_order
> @@ -11273,21 +11296,14 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
>  	  if (reloc_count == 0)
>  	    continue;
>
> -	  reloc_count += additional_reloc_count;
>  	  o->reloc_count += reloc_count;
>
>  	  if (p->type == bfd_indirect_link_order && emit_relocs)
>  	    {
>  	      if (esdi->rel.hdr)
> -		{
>  		  esdo->rel.count += NUM_SHDR_ENTRIES (esdi->rel.hdr);
> -		  esdo->rel.count += additional_reloc_count;
> -		}
>  	      if (esdi->rela.hdr)
> -		{
>  		  esdo->rela.count += NUM_SHDR_ENTRIES (esdi->rela.hdr);
> -		  esdo->rela.count += additional_reloc_count;
> -		}
>  	    }
>  	  else
>  	    {
> @@ -11298,7 +11314,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
>  	    }
>  	}
>
> -      if (o->reloc_count > 0)
> +      if (o->reloc_count > 0 || additional_reloc_count > 0)
>  	o->flags |= SEC_RELOC;
>        else
>  	{
> @@ -11336,11 +11352,11 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
>        if ((o->flags & SEC_RELOC) != 0)
>  	{
>  	  if (esdo->rel.hdr
> -	      && !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rel)))
> +	      && !(_bfd_elf_link_size_reloc_section (abfd, info, o, FALSE)))
>  	    goto error_return;
>
>  	  if (esdo->rela.hdr
> -	      && !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rela)))
> +	      && !(_bfd_elf_link_size_reloc_section (abfd, info, o, TRUE)))
>  	    goto error_return;
>  	}
>
> diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
> index 97aa5e6..5424cf3 100644
> --- a/bfd/elfxx-target.h
> +++ b/bfd/elfxx-target.h
> @@ -551,6 +551,9 @@
>  #ifndef elf_backend_count_additional_relocs
>  #define elf_backend_count_additional_relocs	NULL
>  #endif
> +#ifndef elf_backend_count_output_relocs
> +#define elf_backend_count_output_relocs		_bfd_elf_default_count_output_relocs
> +#endif
>  #ifndef elf_backend_sort_relocs_p
>  #define elf_backend_sort_relocs_p		NULL
>  #endif
> @@ -773,6 +776,7 @@ static struct elf_backend_data elfNN_bed =
>    elf_backend_emit_relocs,
>    elf_backend_count_relocs,
>    elf_backend_count_additional_relocs,
> +  elf_backend_count_output_relocs,
>    elf_backend_sort_relocs_p,
>    elf_backend_grok_prstatus,
>    elf_backend_grok_psinfo,
>

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

* Re: [PATCH] ARM: Fix relocation of EXIDX sections
  2016-09-23  5:49     ` Akihiko Odaki
@ 2016-09-23  9:55       ` Nick Clifton
  0 siblings, 0 replies; 8+ messages in thread
From: Nick Clifton @ 2016-09-23  9:55 UTC (permalink / raw)
  To: Akihiko Odaki, binutils; +Cc: Andreas Schwab, Paul Brook, Yury Usishchev

Hi Akihiko-san,

> Sorry, I forgot to change the subject prefix. This is v3, fixing the issue reported by Nick Clifton:

Thank you for fixing this problem.  It seems that the new patch however does not work. :-(
Specifically it fails to fix the unwind-4 linker test (with your patch applied to that test)
and it introduces a new linker testsuite regression unwind-rel:

  Running /work/sources/binutils/current/ld/testsuite/ld-arm/arm-elf.exp ...
  [...]
  FAIL: ld-arm/unwind-4
  [...]
  FAIL: unwind-rel
  [...]

This is with any ELF based ARM toolchain.  
 
Please could you have a look at these.

Cheers
  Nick

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

end of thread, other threads:[~2016-09-23  9:55 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-11  9:31 [PATCH] Test also relocations for ARM unwinding section Akihiko Odaki
2016-09-13  6:48 ` [PATCH] ARM: Fix relocation of EXIDX sections Akihiko Odaki
2016-09-13  7:16   ` Andreas Schwab
2016-09-13 10:04   ` [PATH v2] " Akihiko Odaki
2016-09-22 16:04     ` Nick Clifton
2016-09-23  5:46   ` [PATCH] " Akihiko Odaki
2016-09-23  5:49     ` Akihiko Odaki
2016-09-23  9:55       ` Nick Clifton

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