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] ARM: Fix exidx coverage for relocatable builds


Hello all,

This is my first patch proposal of a fix for PR17323.  As already described in
bugzilla, 'ld -r' does not generate cantunwind records. And if we just enable
elf32_arm_fix_exidx_coverage workaround in relocatable builds, appropriate
relocations are not generated.

So I added required functionality to generate correct relocations.
Cantunwind records are now outputed correctly.

Tested for arm-linux-gnueabi target, verified on demo from bugzilla and on new
test.

BR,
Yury Usishchev

Changelogs:
bfd/ChangeLog:

2015-12-21 Yury Usishchev <y.usishchev@samsung.com>

     * elf-bfd.h: Add callback to count additional relocations.
     * elf32-arm.c (_arm_elf_section_data): Add new counter.
     (insert_cantunwind_after): Increment relocations counter.
     (elf32_arm_fix_exidx_coverage): Remove exidx entries and add
     terminating CANTUNWIND entry only in final builds.
     (elf32_arm_add_relocation): New function.
     (elf32_arm_write_section): Add relocations in relocatable builds.
     (elf32_arm_count_additional_relocs): New function.
     (elf_backend_count_additional_relocs): New define.
     * bfd/elflink.c (bfd_elf_final_link): Use callback and adjust size of
     .rel section.
     * bfd/elfxx-target.h (elf_backend_count_additional_relocs): New define.
     * ld/emultempl/armelf.em (gld${EMULATION_NAME}_after_allocation): Call
     elf32_arm_fix_exidx_coverage for relocatable builds.

ld/testsuite/ChangeLog:

2015-12-21 Yury Usishchev <y.usishchev@samsung.com>

     * ld-arm/arm-elf.exp: New test.
     * ld-arm/unwind-rel.d: New file.
     * ld-arm/unwind-rel1.s: New file.
     * ld-arm/unwind-rel2.s: New file.
     * ld-arm/unwind-rel3.s: New file.
     
>From e5dc0a905deab5d491818c449413ec6244b0dbdd Mon Sep 17 00:00:00 2001
From: Yury Usishchev <y.usishchev@samsung.com>
Date: Wed, 2 Dec 2015 13:37:30 +0300
Subject: [PATCH] Fix exidx coverage for relocatable builds

---
 bfd/elf-bfd.h                     |  5 +++
 bfd/elf32-arm.c                   | 70 +++++++++++++++++++++++++++++++++++--
 bfd/elflink.c                     | 22 ++++++++++--
 bfd/elfxx-target.h                |  4 +++
 ld/emultempl/armelf.em            | 73 +++++++++++++++++++--------------------
 ld/testsuite/ld-arm/arm-elf.exp   |  6 ++++
 ld/testsuite/ld-arm/unwind-rel.d  | 31 +++++++++++++++++
 ld/testsuite/ld-arm/unwind-rel1.s |  9 +++++
 ld/testsuite/ld-arm/unwind-rel2.s |  6 ++++
 ld/testsuite/ld-arm/unwind-rel3.s |  9 +++++
 10 files changed, 192 insertions(+), 43 deletions(-)
 create mode 100644 ld/testsuite/ld-arm/unwind-rel.d
 create mode 100644 ld/testsuite/ld-arm/unwind-rel1.s
 create mode 100644 ld/testsuite/ld-arm/unwind-rel2.s
 create mode 100644 ld/testsuite/ld-arm/unwind-rel3.s

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 70e3327..129aa64 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1170,6 +1170,11 @@ struct elf_backend_data
   unsigned int (*elf_backend_count_relocs)
     (struct bfd_link_info *, asection *);
 
+  /* Count additionals relocations.  Called for relocatable links if
+     additional relocations needs to be created.  */
+  unsigned int (*elf_backend_count_additional_relocs)
+    (asection *);
+
   /* 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)
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 49d6469..7d7f92a 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -2802,6 +2802,7 @@ typedef struct _arm_elf_section_data
   elf32_vfp11_erratum_list *erratumlist;
   unsigned int stm32l4xx_erratumcount;
   elf32_stm32l4xx_erratum_list *stm32l4xx_erratumlist;
+  unsigned int additional_reloc_count;
   /* Information about unwind tables.  */
   union
   {
@@ -11619,6 +11620,8 @@ insert_cantunwind_after(asection *text_sec, asection *exidx_sec)
     &exidx_arm_data->u.exidx.unwind_edit_tail,
     INSERT_EXIDX_CANTUNWIND_AT_END, text_sec, UINT_MAX);
 
+  exidx_arm_data->additional_reloc_count++;
+
   adjust_exidx_size(exidx_sec, 8);
 }
 
@@ -11761,7 +11764,7 @@ elf32_arm_fix_exidx_coverage (asection **text_section_order,
 	  else
 	    unwind_type = 2;
 
-	  if (elide)
+	  if (elide && !bfd_link_relocatable (info))
 	    {
 	      add_unwind_table_edit (&unwind_edit_head, &unwind_edit_tail,
 				     DELETE_EXIDX_ENTRY, NULL, j / 8);
@@ -11788,7 +11791,8 @@ elf32_arm_fix_exidx_coverage (asection **text_section_order,
     }
 
   /* Add terminating CANTUNWIND entry.  */
-  if (last_exidx_sec && last_unwind_type != 0)
+  if (!bfd_link_relocatable (info) && last_exidx_sec
+      && last_unwind_type != 0)
     insert_cantunwind_after(last_text_sec, last_exidx_sec);
 
   return TRUE;
@@ -16959,6 +16963,39 @@ 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.  */
 
@@ -17203,6 +17240,26 @@ elf32_arm_write_section (bfd *output_bfd,
 			   usual BFD method.  */
 			prel31_offset = (text_offset - exidx_offset)
 					& 0x7ffffffful;
+			if (bfd_link_relocatable (link_info))
+			  {
+			    /* Here relocation for new EXIDX_CANTUNWIND is
+			       created, so there is no need to
+			       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.  */
 			bfd_put_32 (output_bfd, prel31_offset,
@@ -17690,6 +17747,14 @@ elf32_arm_get_synthetic_symtab (bfd *abfd,
   return n;
 }
 
+static unsigned int
+elf32_arm_count_additional_relocs (asection *sec)
+{
+  struct _arm_elf_section_data *arm_data;
+  arm_data = get_arm_elf_section_data (sec);
+  return arm_data->additional_reloc_count;
+}
+
 #define ELF_ARCH			bfd_arch_arm
 #define ELF_TARGET_ID			ARM_ELF_DATA
 #define ELF_MACHINE_CODE		EM_ARM
@@ -17744,6 +17809,7 @@ elf32_arm_get_synthetic_symtab (bfd *abfd,
 #define elf_backend_output_arch_local_syms      elf32_arm_output_arch_local_syms
 #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_can_refcount       1
 #define elf_backend_can_gc_sections    1
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 1b41c79..2eeada2 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -10988,6 +10988,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       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
@@ -11016,7 +11017,15 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 		   reloc sections themselves can't have relocations.  */
 		reloc_count = 0;
 	      else if (emit_relocs)
-		reloc_count = sec->reloc_count;
+		{
+		  reloc_count = sec->reloc_count;
+		  if (bed->elf_backend_count_additional_relocs)
+		    {
+		      int c;
+		      c = (*bed->elf_backend_count_additional_relocs) (sec);
+		      additional_reloc_count += c;
+		    }
+		}
 	      else if (bed->elf_backend_count_relocs)
 		reloc_count = (*bed->elf_backend_count_relocs) (info, sec);
 
@@ -11065,14 +11074,21 @@ 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 += 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 += NUM_SHDR_ENTRIES (esdi->rela.hdr);
+		  esdo->rela.count += additional_reloc_count;
+		}
 	    }
 	  else
 	    {
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index 0acecaf..c5bd7de 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -538,6 +538,9 @@
 #ifndef elf_backend_count_relocs
 #define elf_backend_count_relocs		NULL
 #endif
+#ifndef elf_backend_count_additional_relocs
+#define elf_backend_count_additional_relocs	NULL
+#endif
 #ifndef elf_backend_sort_relocs_p
 #define elf_backend_sort_relocs_p		NULL
 #endif
@@ -755,6 +758,7 @@ static struct elf_backend_data elfNN_bed =
   elf_backend_ignore_undef_symbol,
   elf_backend_emit_relocs,
   elf_backend_count_relocs,
+  elf_backend_count_additional_relocs,
   elf_backend_sort_relocs_p,
   elf_backend_grok_prstatus,
   elf_backend_grok_psinfo,
diff --git a/ld/emultempl/armelf.em b/ld/emultempl/armelf.em
index 2931a49..aae45d1 100644
--- a/ld/emultempl/armelf.em
+++ b/ld/emultempl/armelf.em
@@ -293,55 +293,52 @@ gld${EMULATION_NAME}_after_allocation (void)
 {
   int ret;
 
-  if (!bfd_link_relocatable (&link_info))
+  /* 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)
     {
-      /* 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;
+      bfd *abfd = is->the_bfd;
+      asection *sec;
 
-      LANG_FOR_EACH_INPUT_STATEMENT (is)
-	{
-	  bfd *abfd = is->the_bfd;
-	  asection *sec;
+      if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
+	continue;
 
-	  if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
-	    continue;
-
-	  for (sec = abfd->sections; sec != NULL; sec = sec->next)
+      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 != SEC_INFO_TYPE_JUST_SYMS
+	      && out_sec != bfd_abs_section_ptr)
 	    {
-	      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 != SEC_INFO_TYPE_JUST_SYMS
-		  && out_sec != bfd_abs_section_ptr)
+	      if (sec_count == list_size)
 		{
-		  if (sec_count == list_size)
-		    {
-		      list_size *= 2;
-		      sec_list = (asection **)
-                          xrealloc (sec_list, list_size * sizeof (asection *));
-		    }
-
-		  sec_list[sec_count++] = sec;
+		  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);
+  qsort (sec_list, sec_count, sizeof (asection *), &compare_output_sec_vma);
 
-      if (elf32_arm_fix_exidx_coverage (sec_list, sec_count, &link_info,
-					   merge_exidx_entries))
-	need_laying_out = 1;
+  if (elf32_arm_fix_exidx_coverage (sec_list, sec_count, &link_info,
+				    merge_exidx_entries))
+    need_laying_out = 1;
 
-      free (sec_list);
-    }
+  free (sec_list);
 
   /* bfd_elf32_discard_info just plays with debugging sections,
      ie. doesn't affect any code, so we can delay resizing the
diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
index 23c9e57..46e8118 100644
--- a/ld/testsuite/ld-arm/arm-elf.exp
+++ b/ld/testsuite/ld-arm/arm-elf.exp
@@ -929,3 +929,9 @@ run_dump_test "gc-hidden-1"
 run_dump_test "protected-data"
 run_dump_test "stm32l4xx-cannot-fix-it-block"
 run_dump_test "stm32l4xx-cannot-fix-far-ldm"
+set arm_unwind_tests {
+    {"unwind-rel" "-r -Tarm.ld" "" "" {unwind-rel1.s unwind-rel2.s unwind-rel3.s}
+     {{readelf -ur unwind-rel.d}}
+     "unwind-rel"}
+}
+run_ld_link_tests $arm_unwind_tests
diff --git a/ld/testsuite/ld-arm/unwind-rel.d b/ld/testsuite/ld-arm/unwind-rel.d
new file mode 100644
index 0000000..b2aa6e2
--- /dev/null
+++ b/ld/testsuite/ld-arm/unwind-rel.d
@@ -0,0 +1,31 @@
+
+Relocation section '\.rel\.text' at offset .* contains 3 entries:
+ Offset     Info    Type            Sym\.Value  Sym\. Name
+00000000  00000028 R_ARM_V4BX       
+00000004  00000028 R_ARM_V4BX       
+00000008  00000028 R_ARM_V4BX       
+
+Relocation section '\.rel\.ARM\.exidx' at offset .* contains 5 entries:
+ Offset     Info    Type            Sym\.Value  Sym\. Name
+00000000  0000012a R_ARM_PREL31      00000000   \.text
+00000000  00000e00 R_ARM_NONE        00000000   __aeabi_unwind_cpp_pr0
+00000008  0000012a R_ARM_PREL31      00000000   \.text
+00000010  0000012a R_ARM_PREL31      00000000   \.text
+00000010  00000e00 R_ARM_NONE        00000000   __aeabi_unwind_cpp_pr0
+
+Unwind table index '\.ARM\.exidx' at offset .* contains 3 entries:
+
+0x0: 0x80a8b0b0
+  Compact model index: 0
+  0xa8      pop {r4, r14}
+  0xb0      finish
+  0xb0      finish
+
+0x4 <test>: 0x1 \[cantunwind\]
+
+0x8 <end>: 0x80a8b0b0
+  Compact model index: 0
+  0xa8      pop {r4, r14}
+  0xb0      finish
+  0xb0      finish
+
diff --git a/ld/testsuite/ld-arm/unwind-rel1.s b/ld/testsuite/ld-arm/unwind-rel1.s
new file mode 100644
index 0000000..9efb78b
--- /dev/null
+++ b/ld/testsuite/ld-arm/unwind-rel1.s
@@ -0,0 +1,9 @@
+	.syntax unified
+	.text
+	.global _start
+	.type _start, %function
+_start:
+	.fnstart
+	.save {r4, lr}
+	bx lr
+	.fnend
diff --git a/ld/testsuite/ld-arm/unwind-rel2.s b/ld/testsuite/ld-arm/unwind-rel2.s
new file mode 100644
index 0000000..1001743
--- /dev/null
+++ b/ld/testsuite/ld-arm/unwind-rel2.s
@@ -0,0 +1,6 @@
+	.syntax unified
+	.text
+	.global test
+	.type test, %function
+test:
+	bx lr
diff --git a/ld/testsuite/ld-arm/unwind-rel3.s b/ld/testsuite/ld-arm/unwind-rel3.s
new file mode 100644
index 0000000..8511339
--- /dev/null
+++ b/ld/testsuite/ld-arm/unwind-rel3.s
@@ -0,0 +1,9 @@
+	.syntax unified
+	.text
+	.global end
+	.type end, %function
+end:
+	.fnstart
+	.save {r4, lr}
+	bx lr
+	.fnend
-- 
2.6.4


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