This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH 3/3] bfd: fix the deletion of relocs in mips64
- From: "Jose E. Marchesi" <jose dot marchesi at oracle dot com>
- To: binutils at sourceware dot org
- Date: Thu, 4 May 2017 20:08:12 +0200
- Subject: [PATCH 3/3] bfd: fix the deletion of relocs in mips64
- Authentication-results: sourceware.org; auth=none
- References: <1493921292-6251-1-git-send-email-jose.marchesi@oracle.com>
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.
Tested in mips64-unkonwn-openbsd target.
Fixes the currently failing merge-note objcopy test.
No regressions.
A specialized `_bfd_set_reloc" function is provided that upde
bfd/ChangeLog:
2017-05-04 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-04 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 | 45 ++++++++++++++++++++++++++++++++-------------
bfd/elfxx-mips.c | 12 ------------
bfd/elfxx-mips.h | 16 ++++++++++++++++
binutils/ChangeLog | 5 +++++
binutils/objcopy.c | 7 -------
6 files changed, 69 insertions(+), 32 deletions(-)
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index c69a5fb..54d80e5 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,21 @@
2017-05-04 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-04 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..b95bc96 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,20 @@ mips_elf64_canonicalize_dynamic_reloc (bfd *abfd, arelent **storage,
return ret;
}
+/* A similar problem happens with set_reloc. This version divides the
+ internal relocation count by 3 to obtain the external relocation
+ count that is stored in the asection. */
+
+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 +3901,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 +3972,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 +3989,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 +4015,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 +4033,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 +4079,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 +4132,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 +4177,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 +4231,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 +4523,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..b24023a 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,8 @@
+2017-05-04 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