ARM: Fix exidx coverage for relocatable builds.
authorYury Usishchev <y.usishchev@samsung.com>
Tue, 22 Dec 2015 15:50:13 +0000 (15:50 +0000)
committerNick Clifton <nickc@redhat.com>
Tue, 22 Dec 2015 15:50:13 +0000 (15:50 +0000)
bfd  * 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
     * 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.

13 files changed:
bfd/ChangeLog
bfd/elf-bfd.h
bfd/elf32-arm.c
bfd/elflink.c
bfd/elfxx-target.h
ld/ChangeLog
ld/emultempl/armelf.em
ld/testsuite/ChangeLog
ld/testsuite/ld-arm/arm-elf.exp
ld/testsuite/ld-arm/unwind-rel.d [new file with mode: 0644]
ld/testsuite/ld-arm/unwind-rel1.s [new file with mode: 0644]
ld/testsuite/ld-arm/unwind-rel2.s [new file with mode: 0644]
ld/testsuite/ld-arm/unwind-rel3.s [new file with mode: 0644]

index 49baaa1..e5bedae 100644 (file)
@@ -1,3 +1,18 @@
+2015-12-22 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.
+       * elflink.c (bfd_elf_final_link): Use callback and adjust size of
+       .rel section.
+       * elfxx-target.h (elf_backend_count_additional_relocs): New define.
+
 2015-12-22  Yoshinori Sato <ysato@users.sourceforge.jp>
 
        * archures.c: Add bfd_mach_rx_v2.
index 70e3327..129aa64 100644 (file)
@@ -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)
index 5d31ef2..583db4d 100644 (file)
@@ -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;
@@ -16984,6 +16988,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.  */
 
@@ -17228,6 +17265,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,
@@ -17742,6 +17799,14 @@ elf32_arm_lookup_section_flags (char *flag_name)
   return SEC_NO_FLAGS;
 }
 
+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
@@ -17796,6 +17861,7 @@ elf32_arm_lookup_section_flags (char *flag_name)
 #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
index 1b41c79..2eeada2 100644 (file)
@@ -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
            {
index 0acecaf..c5bd7de 100644 (file)
 #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,
index 576e3dc..a7014d5 100644 (file)
@@ -1,3 +1,8 @@
+2015-12-22 Yury Usishchev <y.usishchev@samsung.com>
+
+       * emultempl/armelf.em (gld${EMULATION_NAME}_after_allocation): Call
+       elf32_arm_fix_exidx_coverage for relocatable builds.
+
 2015-12-10  Kwok Cheung Yeung  <kcy@codesourcery.com>
 
        PR ld/18199
index 2931a49..aae45d1 100644 (file)
@@ -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
index d5982b9..d8b2d3c 100644 (file)
@@ -1,14 +1,22 @@
+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.
+
 2015-12-22 Mickael Guene <mickael.guene@st.com>
 
        * ld-arm/arm-elf.exp: New tests.
-       * ld-arm/thumb1-input-section-flag-match.d: New
-       * ld-arm/thumb1-input-section-flag-match.s: New
-       * ld-arm/thumb1-noread-not-present-mixing-two-section.d: New
-       * ld-arm/thumb1-noread-not-present-mixing-two-section.s: New
-       * ld-arm/thumb1-noread-present-one-section.d: New
-       * ld-arm/thumb1-noread-present-one-section.s: New
-       * ld-arm/thumb1-noread-present-two-section.d: New
-       * ld-arm/thumb1-noread-present-two-section.s: New
+       * ld-arm/thumb1-input-section-flag-match.d: New.
+       * ld-arm/thumb1-input-section-flag-match.s: New.
+       * ld-arm/thumb1-noread-not-present-mixing-two-section.d: New.
+       * ld-arm/thumb1-noread-not-present-mixing-two-section.s: New.
+       * ld-arm/thumb1-noread-present-one-section.d: New.
+       * ld-arm/thumb1-noread-present-one-section.s: New.
+       * ld-arm/thumb1-noread-present-two-section.d: New.
+       * ld-arm/thumb1-noread-present-two-section.s: New.
 
 2015-12-16  Mickael Guene <mickael.guene@st.com>
 
index a970dba..ac2abf1 100644 (file)
@@ -941,3 +941,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 (file)
index 0000000..b2aa6e2
--- /dev/null
@@ -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 (file)
index 0000000..9efb78b
--- /dev/null
@@ -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 (file)
index 0000000..1001743
--- /dev/null
@@ -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 (file)
index 0000000..8511339
--- /dev/null
@@ -0,0 +1,9 @@
+       .syntax unified
+       .text
+       .global end
+       .type end, %function
+end:
+       .fnstart
+       .save {r4, lr}
+       bx lr
+       .fnend