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 V2 3/3] bfd: fix the deletion of relocs in mips64


This patch fixes the deletion of relocations in BFD sections in mips64
targets.

A new field `reloc_count' is added to the `_bfd_mips_elf_section_data'
in order to hold the number of internal relocations that the section
contains.  A specialized `_bfd_set_reloc' function is provided that
updates this internal field, and the logic in the relocation-related
functions in elf64-mips.c is adapted to use this new field.

This patch also removes the safety check recently introduced in
objcopy, to avoid deleting relocations if the count returned by
`bfd_canonicalize_relocs' is bigger than `sec->reloc_count', as it is
no longer necessary.

bfd/ChangeLog:

    2017-05-05  Jose E. Marchesi  <jose.marchesi@oracle.com>

    	* elfxx-mips.h (struct _bfd_mips_elf_section_data): Moved from
    	elfxx-mips.c.  Add a new field `reloc_count'.
    	(mips_elf_section_data): Moved from elfxx-mips.c.
    	(canon_reloc_count): Define.
    	* elf64-mips.c (mips_elf64_set_reloc): New function.
    	(mips_elf64_canonicalize_reloc): Use canon_reloc_count.
    	(mips_elf64_slurp_reloc_table): Likewise.
    	(mips_elf64_slurp_one_reloc_table): Likewise.
    	(mips_elf64_write_relocs): Use `canon_reloc_count'.
    	(mips_elf64_write_rel): Likewise.
    	(mips_elf64_write_rela): Likewise.
    	(mips_elf64_canonicalize_dynamic_reloc): Likewise.
    	(bfd_elf64_set_reloc): Define.

binutils/ChangeLog:

    2017-05-05  Jose E. Marchesi  <jose.marchesi@oracle.com>

    	* objcopy.c (merge_gnu_build_notes): Remove special case for
    	mips64 and sparc64, as it is not needed anymore.
---
 bfd/ChangeLog      | 16 ++++++++++++++++
 bfd/elf64-mips.c   | 47 ++++++++++++++++++++++++++++++++++-------------
 bfd/elfxx-mips.c   | 12 ------------
 bfd/elfxx-mips.h   | 16 ++++++++++++++++
 binutils/ChangeLog |  5 +++++
 binutils/objcopy.c |  7 -------
 6 files changed, 71 insertions(+), 32 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index d8ec8a7..71ad6a8 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,21 @@
 2017-05-05  Jose E. Marchesi  <jose.marchesi@oracle.com>
 
+	* elfxx-mips.h (struct _bfd_mips_elf_section_data): Moved from
+	elfxx-mips.c.  Add a new field `reloc_count'.
+	(mips_elf_section_data): Moved from elfxx-mips.c.
+	(canon_reloc_count): Define.
+	* elf64-mips.c (mips_elf64_set_reloc): New function.
+	(mips_elf64_canonicalize_reloc): Use canon_reloc_count.
+	(mips_elf64_slurp_reloc_table): Likewise.
+	(mips_elf64_slurp_one_reloc_table): Likewise.
+	(mips_elf64_write_relocs): Use `canon_reloc_count'.
+	(mips_elf64_write_rel): Likewise.
+	(mips_elf64_write_rela): Likewise.
+	(mips_elf64_canonicalize_dynamic_reloc): Likewise.
+	(bfd_elf64_set_reloc): Define.
+
+2017-05-05  Jose E. Marchesi  <jose.marchesi@oracle.com>
+
 	* elf64-sparc.c (elf64_sparc_set_reloc): New function.
 	(bfd_elf64_set_reloc): Define.
 	(elf64_sparc_write_relocs): Use `canon_reloc_count'.
diff --git a/bfd/elf64-mips.c b/bfd/elf64-mips.c
index a66c319..63880c6 100644
--- a/bfd/elf64-mips.c
+++ b/bfd/elf64-mips.c
@@ -90,6 +90,8 @@ static long mips_elf64_get_reloc_upper_bound
   (bfd *, asection *);
 static long mips_elf64_canonicalize_reloc
   (bfd *, asection *, arelent **, asymbol **);
+static void mips_elf64_set_reloc
+  (bfd *, asection *, arelent **, unsigned int);
 static long mips_elf64_get_dynamic_reloc_upper_bound
   (bfd *);
 static long mips_elf64_canonicalize_dynamic_reloc
@@ -3680,12 +3682,12 @@ mips_elf64_canonicalize_reloc (bfd *abfd, sec_ptr section,
     return -1;
 
   tblptr = section->relocation;
-  for (i = 0; i < section->reloc_count * 3; i++)
+  for (i = 0; i < canon_reloc_count (section); i++)
     *relptr++ = tblptr++;
 
   *relptr = NULL;
 
-  return section->reloc_count * 3;
+  return canon_reloc_count (section);
 }
 
 static long
@@ -3715,7 +3717,7 @@ mips_elf64_canonicalize_dynamic_reloc (bfd *abfd, arelent **storage,
 
 	  if (! (*slurp_relocs) (abfd, s, syms, TRUE))
 	    return -1;
-	  count = s->size / elf_section_data (s)->this_hdr.sh_entsize * 3;
+	  count = canon_reloc_count (s);
 	  p = s->relocation;
 	  for (i = 0; i < count; i++)
 	    *storage++ = p++;
@@ -3728,6 +3730,22 @@ mips_elf64_canonicalize_dynamic_reloc (bfd *abfd, arelent **storage,
   return ret;
 }
 
+/* A similar problem happens with set_reloc.  This version updates the
+   internal `reloc_count' field in `struct _mips_elf_section_data' in
+   order to hold the new number of internal relocations.  This avoids
+   overwriting `asect->reloc_count' that holds the number of external
+   relocations.  */
+
+static void
+mips_elf64_set_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+                      asection *asect,
+                      arelent **location,
+                      unsigned int count)
+{
+  asect->orelocation = location;
+  canon_reloc_count (asect) = count;
+}
+
 /* Read the relocations from one reloc section.  This is mostly copied
    from elfcode.h, except for the changes to expand one external
    relocation to 3 internal ones.  We must unfortunately set
@@ -3885,7 +3903,7 @@ mips_elf64_slurp_one_reloc_table (bfd *abfd, asection *asect,
 	}
     }
 
-  asect->reloc_count += (relent - relents) / 3;
+  canon_reloc_count (asect) += (relent - relents);
 
   if (allocated != NULL)
     free (allocated);
@@ -3956,8 +3974,9 @@ mips_elf64_slurp_reloc_table (bfd *abfd, asection *asect,
   if (relents == NULL)
     return FALSE;
 
-  /* The slurp_one_reloc_table routine increments reloc_count.  */
-  asect->reloc_count = 0;
+  /* The slurp_one_reloc_table routine increments
+     canon_reloc_count.  */
+  canon_reloc_count (asect) = 0;
 
   if (rel_hdr != NULL
       && ! mips_elf64_slurp_one_reloc_table (abfd, asect,
@@ -3972,6 +3991,7 @@ mips_elf64_slurp_reloc_table (bfd *abfd, asection *asect,
 					     symbols, dynamic))
     return FALSE;
 
+  asect->reloc_count = canon_reloc_count (asect) / 3;
   asect->relocation = relents;
   return TRUE;
 }
@@ -3997,13 +4017,13 @@ mips_elf64_write_relocs (bfd *abfd, asection *sec, void *data)
      reloc_count field to zero to inhibit writing them here.  Also,
      sometimes the SEC_RELOC flag gets set even when there aren't any
      relocs.  */
-  if (sec->reloc_count == 0)
+  if (canon_reloc_count (sec) == 0)
     return;
 
   /* We can combine up to three relocs that refer to the same address
      if the latter relocs have no associated symbol.  */
   count = 0;
-  for (idx = 0; idx < sec->reloc_count; idx++)
+  for (idx = 0; idx < canon_reloc_count (sec); idx++)
     {
       bfd_vma addr;
       unsigned int i;
@@ -4015,7 +4035,7 @@ mips_elf64_write_relocs (bfd *abfd, asection *sec, void *data)
 	{
 	  arelent *r;
 
-	  if (idx + 1 >= sec->reloc_count)
+	  if (idx + 1 >= canon_reloc_count (sec))
 	    break;
 	  r = sec->orelocation[idx + 1];
 	  if (r->address != addr
@@ -4061,7 +4081,7 @@ mips_elf64_write_rel (bfd *abfd, asection *sec,
     }
 
   ext_rel = (Elf64_Mips_External_Rel *) rel_hdr->contents;
-  for (idx = 0; idx < sec->reloc_count; idx++, ext_rel++)
+  for (idx = 0; idx < canon_reloc_count (sec); idx++, ext_rel++)
     {
       arelent *ptr;
       Elf64_Mips_Internal_Rela int_rel;
@@ -4114,7 +4134,7 @@ mips_elf64_write_rel (bfd *abfd, asection *sec,
 	{
 	  arelent *r;
 
-	  if (idx + 1 >= sec->reloc_count)
+	  if (idx + 1 >= canon_reloc_count (sec))
 	    break;
 	  r = sec->orelocation[idx + 1];
 	  if (r->address != ptr->address
@@ -4159,7 +4179,7 @@ mips_elf64_write_rela (bfd *abfd, asection *sec,
     }
 
   ext_rela = (Elf64_Mips_External_Rela *) rela_hdr->contents;
-  for (idx = 0; idx < sec->reloc_count; idx++, ext_rela++)
+  for (idx = 0; idx < canon_reloc_count (sec); idx++, ext_rela++)
     {
       arelent *ptr;
       Elf64_Mips_Internal_Rela int_rela;
@@ -4213,7 +4233,7 @@ mips_elf64_write_rela (bfd *abfd, asection *sec,
 	{
 	  arelent *r;
 
-	  if (idx + 1 >= sec->reloc_count)
+	  if (idx + 1 >= canon_reloc_count (sec))
 	    break;
 	  r = sec->orelocation[idx + 1];
 	  if (r->address != ptr->address
@@ -4505,6 +4525,7 @@ const struct elf_size_info mips_elf64_size_info =
 
 #define bfd_elf64_get_reloc_upper_bound mips_elf64_get_reloc_upper_bound
 #define bfd_elf64_canonicalize_reloc mips_elf64_canonicalize_reloc
+#define bfd_elf64_set_reloc mips_elf64_set_reloc
 #define bfd_elf64_get_dynamic_reloc_upper_bound mips_elf64_get_dynamic_reloc_upper_bound
 #define bfd_elf64_canonicalize_dynamic_reloc mips_elf64_canonicalize_dynamic_reloc
 #define bfd_elf64_mkobject		_bfd_mips_elf_mkobject
diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
index 70c7f1c..8aa979e 100644
--- a/bfd/elfxx-mips.c
+++ b/bfd/elfxx-mips.c
@@ -221,18 +221,6 @@ struct mips_elf_traverse_got_arg
   int value;
 };
 
-struct _mips_elf_section_data
-{
-  struct bfd_elf_section_data elf;
-  union
-  {
-    bfd_byte *tdata;
-  } u;
-};
-
-#define mips_elf_section_data(sec) \
-  ((struct _mips_elf_section_data *) elf_section_data (sec))
-
 #define is_mips_elf(bfd)				\
   (bfd_get_flavour (bfd) == bfd_target_elf_flavour	\
    && elf_tdata (bfd) != NULL				\
diff --git a/bfd/elfxx-mips.h b/bfd/elfxx-mips.h
index 44ad789..5710c61 100644
--- a/bfd/elfxx-mips.h
+++ b/bfd/elfxx-mips.h
@@ -22,6 +22,22 @@
 #include "elf/internal.h"
 #include "elf/mips.h"
 
+struct _mips_elf_section_data
+{
+  struct bfd_elf_section_data elf;
+  union
+  {
+    bfd_byte *tdata;
+  } u;
+  unsigned int reloc_count;
+};
+
+#define mips_elf_section_data(sec) \
+  ((struct _mips_elf_section_data *) elf_section_data (sec))
+
+#define canon_reloc_count(sec) \
+  ((struct _mips_elf_section_data *) elf_section_data (sec))->reloc_count
+
 extern bfd_boolean _bfd_mips_elf_mkobject
   (bfd *);
 extern bfd_boolean _bfd_mips_elf_new_section_hook
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index b3a539a..5a924bc 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,8 @@
+2017-05-05  Jose E. Marchesi  <jose.marchesi@oracle.com>
+
+	* objcopy.c (merge_gnu_build_notes): Remove special case for
+	mips64 and sparc64, as it is not needed anymore.
+
 2017-05-02  H.J. Lu  <hongjiu.lu@intel.com>
 
 	* objcopy.c (merge_gnu_build_notes): Cast relcount to unsigned
diff --git a/binutils/objcopy.c b/binutils/objcopy.c
index ccb5e12..42c7775 100644
--- a/binutils/objcopy.c
+++ b/binutils/objcopy.c
@@ -2137,13 +2137,6 @@ merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte
 	    relcount = 0;
 	}
 
-      /* A few targets (eg MIPS, SPARC) create multiple internal relocs to
-	 represent a single external reloc.  Unfortunately the current BFD
-	 API does not handle deleting relocs in such situations very well
-	 and so it is unsafe to proceed.  */
-      if ((unsigned long) relcount > sec->reloc_count)
-	goto done;
-
       /* Eliminate the duplicates.  */
       new = new_contents = xmalloc (size);
       for (pnote = pnotes, old = contents;
-- 
2.3.4


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