public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* mips hi16/lo16 reloc handling
@ 2023-12-19  9:35 Alan Modra
  2023-12-19  9:35 ` Move mips_hi16_list to mips_elf_section_data Alan Modra
  2023-12-19  9:35 ` coff-mips refhi list Alan Modra
  0 siblings, 2 replies; 3+ messages in thread
From: Alan Modra @ 2023-12-19  9:35 UTC (permalink / raw)
  To: binutils; +Cc: Maciej W . Rozycki, Chenghua Xu, Alan Modra

In May this year I posted a patch to move the list of hi16 relocs from
per-file data to per-section data, where it makes more sense and is
not vunerable to fuzzed object file attacks.
https://sourceware.org/pipermail/binutils/2023-May/127534.html and
https://sourceware.org/pipermail/binutils/2023-May/127535.html
These incorporated the results of an earlier discussion in February.

A lot was going on in May with mips, so I'm not at all surprised that
no one reviewed the patch.  Or perhaps a review only went so far as
finding a segfault in gas..  That is fixed in this version.  We do
need to keep struct mips_hi16 "data" field to cope with gas frags.  A
lo16 reloc might apply to a different frag than the corresponding hi16
reloc.  Also, some other infrastructure changes meant that the posted
patches no longer apply cleanly.

The patches have been tested by running the binutils testsuite, and
building and regression testing a current gcc cross from x86_64-linux
to mips-linux (no sim installed).

Alan Modra (2):
  Move mips_hi16_list to mips_elf_section_data
  coff-mips refhi list

 bfd/coff-alpha.c |   6 +-
 bfd/coff-mips.c  | 121 +++++++++++-----------------
 bfd/ecoff.c      |  34 ++++++--
 bfd/elfxx-mips.c | 206 ++++++++++++++++++++++++-----------------------
 bfd/libecoff.h   |  30 +++----
 5 files changed, 201 insertions(+), 196 deletions(-)


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

* Move mips_hi16_list to mips_elf_section_data
  2023-12-19  9:35 mips hi16/lo16 reloc handling Alan Modra
@ 2023-12-19  9:35 ` Alan Modra
  2023-12-19  9:35 ` coff-mips refhi list Alan Modra
  1 sibling, 0 replies; 3+ messages in thread
From: Alan Modra @ 2023-12-19  9:35 UTC (permalink / raw)
  To: binutils; +Cc: Maciej W . Rozycki, Chenghua Xu, Alan Modra

This patch is in response to fuzzing testcases that manage to cause
segfaults due to stale references to freed memory via mips_hi16.data.

A number of the error/warning handlers in ldmain.c use %C.  This can
cause debug info to be parsed for the first time in order to print
file/function/line.  If one of those warnings is triggered after some
hi16 relocs have been processed but before the matching lo16 reloc is
handled, *and* the debug info is corrupted with a lo16 reloc, then the
mips_hi16_list will be flushed with the result that printing a warning
changes linker output.  It is also possible that corrupted debug info
adds to the hi16 list, with the result that when the linker handles a
later lo16 reloc in a text section, ld will segfault accessing
mips_hi16.data after the debug buffers have be freed.  Both of these
problems are fixed by keeping a per-section mips_hi16_list rather than
a per-file list.

	* elfxx-mips.c (struct mips_hi16): Move earlier, deleting
	input_section field.
	(struct _mips_elf_section_data): Add mips_hi16_list.
	(struct mips_elf_obj_tdata): Delete mips_hi16_list.
	(free_mips_hi16_list): New function.
	(_bfd_mips_elf_free_cached_info): Adjust to suit new location
	of mips_hi16_list.
	(_bfd_mips_elf_hi16_reloc, _bfd_mips_elf_lo16_reloc): Likewise.
	(_bfd_elf_mips_get_relocated_section_contents): Likewise.

diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
index bae8622fd34..00111553c30 100644
--- a/bfd/elfxx-mips.c
+++ b/bfd/elfxx-mips.c
@@ -222,6 +222,19 @@ struct mips_elf_traverse_got_arg
   int value;
 };
 
+/* Used to store a REL high-part relocation such as R_MIPS_HI16 or
+   R_MIPS_GOT16.  DATA nominally points to the start of the section
+   contents, but note that gas may use multiple chunks of memory for a
+   section (with DATA + [offset,offset+frag_size) addressing a given
+   frag).  A hi16 reloc might need a different "data" to a lo16.  */
+
+struct mips_hi16
+{
+  struct mips_hi16 *next;
+  bfd_byte *data;
+  arelent rel;
+};
+
 struct _mips_elf_section_data
 {
   struct bfd_elf_section_data elf;
@@ -229,6 +242,8 @@ struct _mips_elf_section_data
   {
     bfd_byte *tdata;
   } u;
+
+  struct mips_hi16 *mips_hi16_list;
 };
 
 #define mips_elf_section_data(sec) \
@@ -549,19 +564,6 @@ struct mips_htab_traverse_info
   bool error;
 };
 
-/* Used to store a REL high-part relocation such as R_MIPS_HI16 or
-   R_MIPS_GOT16.  REL is the relocation, INPUT_SECTION is the section
-   that contains the relocation field and DATA points to the start of
-   INPUT_SECTION.  */
-
-struct mips_hi16
-{
-  struct mips_hi16 *next;
-  bfd_byte *data;
-  asection *input_section;
-  arelent rel;
-};
-
 /* MIPS ELF private object data.  */
 
 struct mips_elf_obj_tdata
@@ -597,8 +599,6 @@ struct mips_elf_obj_tdata
   asymbol *elf_text_symbol;
   asection *elf_data_section;
   asection *elf_text_section;
-
-  struct mips_hi16 *mips_hi16_list;
 };
 
 /* Get MIPS ELF private object data from BFD's tdata.  */
@@ -1389,6 +1389,30 @@ struct mips_elf_find_line
   struct ecoff_find_line i;
 };
 
+/* Free the mips_hi16_list attached to S.  Return true if there were
+   unmatched hi16 relocs.  */
+
+static bool
+free_mips_hi16_list (asection *s)
+{
+  struct mips_hi16 *hi;
+  struct mips_hi16 **hip = &mips_elf_section_data (s)->mips_hi16_list;
+  bool ret = false;
+
+  while ((hi = *hip) != NULL)
+    {
+      *hip = hi->next;
+      /* See gas/config/tc-mips.c reloc_needs_lo_p.  Not all hi16
+	 relocs need lo16 relocs.  */
+      if (hi->rel.howto->type == R_MIPS_HI16
+	  || hi->rel.howto->type == R_MIPS16_HI16
+	  || hi->rel.howto->type == R_MICROMIPS_HI16)
+	ret = true;
+      free (hi);
+    }
+  return ret;
+}
+
 bool
 _bfd_mips_elf_free_cached_info (bfd *abfd)
 {
@@ -1399,14 +1423,12 @@ _bfd_mips_elf_free_cached_info (bfd *abfd)
       && (tdata = mips_elf_tdata (abfd)) != NULL)
     {
       BFD_ASSERT (tdata->root.object_id == MIPS_ELF_DATA);
-      while (tdata->mips_hi16_list != NULL)
-	{
-	  struct mips_hi16 *hi = tdata->mips_hi16_list;
-	  tdata->mips_hi16_list = hi->next;
-	  free (hi);
-	}
       if (tdata->find_line_info != NULL)
 	_bfd_ecoff_free_ecoff_debug_info (&tdata->find_line_info->d);
+      for (asection *s = abfd->sections; s; s = s->next)
+	if (free_mips_hi16_list (s))
+	  _bfd_error_handler
+	    (_("%pB(%pA): unmatched hi16 reloc"), abfd, s);
     }
   return _bfd_elf_free_cached_info (abfd);
 }
@@ -2537,22 +2559,18 @@ _bfd_mips_elf_hi16_reloc (bfd *abfd, arelent *reloc_entry,
 			  asection *input_section, bfd *output_bfd,
 			  char **error_message ATTRIBUTE_UNUSED)
 {
-  struct mips_hi16 *n;
-  struct mips_elf_obj_tdata *tdata;
-
   if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
     return bfd_reloc_outofrange;
 
-  n = bfd_malloc (sizeof *n);
+  struct mips_hi16 *n = bfd_malloc (sizeof (*n));
   if (n == NULL)
     return bfd_reloc_outofrange;
 
-  tdata = mips_elf_tdata (abfd);
-  n->next = tdata->mips_hi16_list;
+  struct _mips_elf_section_data *sdata = mips_elf_section_data (input_section);
+  n->next = sdata->mips_hi16_list;
   n->data = data;
-  n->input_section = input_section;
   n->rel = *reloc_entry;
-  tdata->mips_hi16_list = n;
+  sdata->mips_hi16_list = n;
 
   if (output_bfd != NULL)
     reloc_entry->address += input_section->output_offset;
@@ -2590,64 +2608,66 @@ _bfd_mips_elf_lo16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
 			  void *data, asection *input_section,
 			  bfd *output_bfd, char **error_message)
 {
-  bfd_vma vallo;
-  bfd_byte *location = (bfd_byte *) data + reloc_entry->address;
-  struct mips_elf_obj_tdata *tdata;
+  struct _mips_elf_section_data *sdata = mips_elf_section_data (input_section);
 
-  if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd, input_section,
-				  reloc_entry->address))
-    return bfd_reloc_outofrange;
+  if (sdata->mips_hi16_list != NULL)
+    {
+      if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd, input_section,
+				      reloc_entry->address))
+	return bfd_reloc_outofrange;
 
-  _bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, false,
-				 location);
-  /* The high 16 bits of the addend are stored in the high insn, the
-     low 16 bits in the low insn, but there is a catch:  You can't
-     just concatenate the high and low parts.  The high part of the
-     addend is adjusted for the fact that the low part is sign
-     extended.  For example, an addend of 0x38000 would have 0x0004 in
-     the high part and 0x8000 (=0xff..f8000) in the low part.
-     To extract the actual addend, calculate (a)
-     ((hi & 0xffff) << 16) + ((lo & 0xffff) ^ 0x8000) - 0x8000.
-     We will be applying (symbol + addend) & 0xffff to the low insn,
-     and we want to apply (b) (symbol + addend + 0x8000) >> 16 to the
-     high insn (the +0x8000 adjusting for when the applied low part is
-     negative).  Substituting (a) into (b) and recognising that
-     (hi & 0xffff) is already in the high insn gives a high part
-     addend adjustment of (lo & 0xffff) ^ 0x8000.  */
-  vallo = (bfd_get_32 (abfd, location) & 0xffff) ^ 0x8000;
-  _bfd_mips_elf_reloc_shuffle (abfd, reloc_entry->howto->type, false,
-			       location);
+      bfd_byte *location = (bfd_byte *) data + reloc_entry->address;
+      _bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, false,
+				     location);
+      /* The high 16 bits of the addend are stored in the high insn, the
+	 low 16 bits in the low insn, but there is a catch:  You can't
+	 just concatenate the high and low parts.  The high part of the
+	 addend is adjusted for the fact that the low part is sign
+	 extended.  For example, an addend of 0x38000 would have 0x0004 in
+	 the high part and 0x8000 (=0xff..f8000) in the low part.
+	 To extract the actual addend, calculate (a)
+	 ((hi & 0xffff) << 16) + ((lo & 0xffff) ^ 0x8000) - 0x8000.
+	 We will be applying (symbol + addend) & 0xffff to the low insn,
+	 and we want to apply (b) (symbol + addend + 0x8000) >> 16 to the
+	 high insn (the +0x8000 adjusting for when the applied low part is
+	 negative).  Substituting (a) into (b) and recognising that
+	 (hi & 0xffff) is already in the high insn gives a high part
+	 addend adjustment of (lo & 0xffff) ^ 0x8000.  */
+      bfd_vma vallo = (bfd_get_32 (abfd, location) & 0xffff) ^ 0x8000;
+      _bfd_mips_elf_reloc_shuffle (abfd, reloc_entry->howto->type, false,
+				   location);
 
-  tdata = mips_elf_tdata (abfd);
-  while (tdata->mips_hi16_list != NULL)
-    {
-      bfd_reloc_status_type ret;
-      struct mips_hi16 *hi;
-
-      hi = tdata->mips_hi16_list;
-
-      /* R_MIPS*_GOT16 relocations are something of a special case.  We
-	 want to install the addend in the same way as for a R_MIPS*_HI16
-	 relocation (with a rightshift of 16).  However, since GOT16
-	 relocations can also be used with global symbols, their howto
-	 has a rightshift of 0.  */
-      if (hi->rel.howto->type == R_MIPS_GOT16)
-	hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MIPS_HI16, false);
-      else if (hi->rel.howto->type == R_MIPS16_GOT16)
-	hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MIPS16_HI16, false);
-      else if (hi->rel.howto->type == R_MICROMIPS_GOT16)
-	hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MICROMIPS_HI16, false);
-
-      hi->rel.addend += vallo;
-
-      ret = _bfd_mips_elf_generic_reloc (abfd, &hi->rel, symbol, hi->data,
-					 hi->input_section, output_bfd,
-					 error_message);
-      if (ret != bfd_reloc_ok)
-	return ret;
-
-      tdata->mips_hi16_list = hi->next;
-      free (hi);
+      while (sdata->mips_hi16_list != NULL)
+	{
+	  bfd_reloc_status_type ret;
+	  struct mips_hi16 *hi = sdata->mips_hi16_list;
+
+	  /* R_MIPS*_GOT16 relocations are something of a special case.
+	     We want to install the addend in the same way as for a
+	     R_MIPS*_HI16 relocation (with a rightshift of 16).
+	     However, since GOT16 relocations can also be used with
+	     global symbols, their howto has a rightshift of 0.  */
+	  if (hi->rel.howto->type == R_MIPS_GOT16)
+	    hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MIPS_HI16,
+						     false);
+	  else if (hi->rel.howto->type == R_MIPS16_GOT16)
+	    hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MIPS16_HI16,
+						     false);
+	  else if (hi->rel.howto->type == R_MICROMIPS_GOT16)
+	    hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MICROMIPS_HI16,
+						     false);
+
+	  hi->rel.addend += vallo;
+
+	  ret = _bfd_mips_elf_generic_reloc (abfd, &hi->rel, symbol, hi->data,
+					     input_section, output_bfd,
+					     error_message);
+	  if (ret != bfd_reloc_ok)
+	    return ret;
+
+	  sdata->mips_hi16_list = hi->next;
+	  free (hi);
+	}
     }
 
   return _bfd_mips_elf_generic_reloc (abfd, reloc_entry, symbol, data,
@@ -13333,24 +13353,8 @@ _bfd_elf_mips_get_relocated_section_contents
   reloc_vector = (arelent **) bfd_malloc (reloc_size);
   if (reloc_vector == NULL)
     {
-      struct mips_elf_obj_tdata *tdata;
-      struct mips_hi16 **hip, *hi;
     error_return:
-      /* If we are going to return an error, remove entries on
-	 mips_hi16_list that point into this section's data.  Data
-	 will typically be freed on return from this function.  */
-      tdata = mips_elf_tdata (abfd);
-      hip = &tdata->mips_hi16_list;
-      while ((hi = *hip) != NULL)
-	{
-	  if (hi->input_section == input_section)
-	    {
-	      *hip = hi->next;
-	      free (hi);
-	    }
-	  else
-	    hip = &hi->next;
-	}
+      free_mips_hi16_list (input_section);
       if (orig_data == NULL)
 	free (data);
       data = NULL;

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

* coff-mips refhi list
  2023-12-19  9:35 mips hi16/lo16 reloc handling Alan Modra
  2023-12-19  9:35 ` Move mips_hi16_list to mips_elf_section_data Alan Modra
@ 2023-12-19  9:35 ` Alan Modra
  1 sibling, 0 replies; 3+ messages in thread
From: Alan Modra @ 2023-12-19  9:35 UTC (permalink / raw)
  To: binutils; +Cc: Maciej W . Rozycki, Chenghua Xu, Alan Modra

Like "Move mips_hi16_list to mips_elf_section_data" but for coff.
Also makes mips_refhi_reloc and mips_reflo_reloc a little more elegant
in that they now make use of the generic reloc machinery in order to
apply the relocations.

	* libecoff.h (struct mips_hi): Delete
	(struct mips_h16): New.
	(struct ecoff_tdata): Delete mips_refhi_list.
	(struct ecoff_section_tdata): Put existing gp into a union.
	Add mips_hi16_list.
	* coff-alpha.c (alpha_relocate_section): Adjust section data access.
	* coff-mips.c (mips_refhi_reloc): Delete dead code.  Stash hi reloc
	on ecoff_section_tdata.
	(mips_reflo_reloc): Use new hi16 list.  Apply hi reloc using
	bfd_perform_relocation.
	* ecoff.c (free_mips_hi16_list): New function.
	(_bfd_ecoff_bfd_free_cached_info): Clear new hi16 list attached to
	sections rather than bfd tdata.

diff --git a/bfd/coff-alpha.c b/bfd/coff-alpha.c
index 3403e13ef1b..0ccc377a950 100644
--- a/bfd/coff-alpha.c
+++ b/bfd/coff-alpha.c
@@ -1461,11 +1461,11 @@ alpha_relocate_section (bfd *output_bfd,
 	  lita_sec->used_by_bfd = lita_sec_data;
 	}
 
-      if (lita_sec_data->gp != 0)
+      if (lita_sec_data->u.gp != 0)
 	{
 	  /* If we already assigned a gp to this section, we better
 	     stick with that value.  */
-	  gp = lita_sec_data->gp;
+	  gp = lita_sec_data->u.gp;
 	}
       else
 	{
@@ -1498,7 +1498,7 @@ alpha_relocate_section (bfd *output_bfd,
 
 	    }
 
-	  lita_sec_data->gp = gp;
+	  lita_sec_data->u.gp = gp;
 	}
 
       _bfd_set_gp_value (output_bfd, gp);
diff --git a/bfd/coff-mips.c b/bfd/coff-mips.c
index fdc0771979d..1b5cc6ae10c 100644
--- a/bfd/coff-mips.c
+++ b/bfd/coff-mips.c
@@ -427,17 +427,11 @@ static bfd_reloc_status_type
 mips_refhi_reloc (bfd *abfd,
 		  arelent *reloc_entry,
 		  asymbol *symbol,
-		  void * data,
+		  void *data,
 		  asection *input_section,
 		  bfd *output_bfd,
 		  char **error_message ATTRIBUTE_UNUSED)
 {
-  bfd_reloc_status_type ret;
-  bfd_vma relocation;
-  struct mips_hi *n;
-
-  /* If we're relocating, and this an external symbol, we don't want
-     to change anything.  */
   if (output_bfd != (bfd *) NULL
       && (symbol->flags & BSF_SECTION_SYM) == 0
       && reloc_entry->addend == 0)
@@ -446,36 +440,34 @@ mips_refhi_reloc (bfd *abfd,
       return bfd_reloc_ok;
     }
 
-  ret = bfd_reloc_ok;
-  if (bfd_is_und_section (symbol->section)
-      && output_bfd == (bfd *) NULL)
-    ret = bfd_reloc_undefined;
-
-  if (bfd_is_com_section (symbol->section))
-    relocation = 0;
-  else
-    relocation = symbol->value;
-
-  relocation += symbol->section->output_section->vma;
-  relocation += symbol->section->output_offset;
-  relocation += reloc_entry->addend;
-
-  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
-    return bfd_reloc_outofrange;
+  /* Is this the call via bfd_perform_relocation in mips_reflo_reloc?
+     If so, continue and apply the reloc.  */
+  struct ecoff_section_tdata *sdata = input_section->used_by_bfd;
+  if (sdata != NULL
+      && sdata->u.mips_hi16_list != NULL
+      && reloc_entry == &sdata->u.mips_hi16_list->rel)
+    return bfd_reloc_continue;
 
+  if (sdata == NULL)
+    {
+      sdata = bfd_zalloc (abfd, sizeof (*sdata));
+      input_section->used_by_bfd = sdata;
+      if (sdata == NULL)
+	return bfd_reloc_outofrange;
+    }
   /* Save the information, and let REFLO do the actual relocation.  */
-  n = (struct mips_hi *) bfd_malloc ((bfd_size_type) sizeof *n);
+  struct mips_hi16 *n = bfd_malloc (sizeof (*n));
   if (n == NULL)
     return bfd_reloc_outofrange;
-  n->addr = (bfd_byte *) data + reloc_entry->address;
-  n->addend = relocation;
-  n->next = ecoff_data (abfd)->mips_refhi_list;
-  ecoff_data (abfd)->mips_refhi_list = n;
+  n->data = data;
+  n->rel = *reloc_entry;
+  n->next = sdata->u.mips_hi16_list;
+  sdata->u.mips_hi16_list = n;
 
   if (output_bfd != (bfd *) NULL)
     reloc_entry->address += input_section->output_offset;
 
-  return ret;
+  return bfd_reloc_ok;
 }
 
 /* Do a REFLO relocation.  This is a straightforward 16 bit inplace
@@ -491,54 +483,37 @@ mips_reflo_reloc (bfd *abfd,
 		  bfd *output_bfd,
 		  char **error_message)
 {
-  if (ecoff_data (abfd)->mips_refhi_list != NULL)
+  bfd_size_type octets = (reloc_entry->address
+			  * OCTETS_PER_BYTE (abfd, input_section));
+
+  if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
+				  input_section, octets))
+    return bfd_reloc_outofrange;
+
+  struct ecoff_section_tdata* sdata = input_section->used_by_bfd;
+  if (sdata != NULL && sdata->u.mips_hi16_list != NULL)
     {
-      struct mips_hi *l;
+      struct mips_hi16 *hi;
+      bfd_byte *loc = (bfd_byte *) data + octets;
+      /* Adjustment for the high part addend.  See longer explanation
+	 in elfxx-mips.c _bfd_mips_elf_lo16_reloc.  */
+      bfd_vma vallo = (bfd_get_32 (abfd, loc) & 0x8000) ^ 0x8000;
 
-      l = ecoff_data (abfd)->mips_refhi_list;
-      while (l != NULL)
+      while ((hi = sdata->u.mips_hi16_list) != NULL)
 	{
-	  unsigned long insn;
-	  unsigned long val;
-	  unsigned long vallo;
-	  struct mips_hi *next;
-	  bfd_size_type octets = (reloc_entry->address
-				  * OCTETS_PER_BYTE (abfd, input_section));
-	  bfd_byte *loc = (bfd_byte *) data + octets;
-
-	  if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
-					  input_section, octets))
-	    return bfd_reloc_outofrange;
-
-	  /* Do the REFHI relocation.  Note that we actually don't
-	     need to know anything about the REFLO itself, except
-	     where to find the low 16 bits of the addend needed by the
-	     REFHI.  */
-	  insn = bfd_get_32 (abfd, l->addr);
-	  vallo = bfd_get_32 (abfd, loc) & 0xffff;
-	  val = ((insn & 0xffff) << 16) + vallo;
-	  val += l->addend;
-
-	  /* The low order 16 bits are always treated as a signed
-	     value.  Therefore, a negative value in the low order bits
-	     requires an adjustment in the high order bits.  We need
-	     to make this adjustment in two ways: once for the bits we
-	     took from the data, and once for the bits we are putting
-	     back in to the data.  */
-	  if ((vallo & 0x8000) != 0)
-	    val -= 0x10000;
-	  if ((val & 0x8000) != 0)
-	    val += 0x10000;
-
-	  insn = (insn &~ (unsigned) 0xffff) | ((val >> 16) & 0xffff);
-	  bfd_put_32 (abfd, (bfd_vma) insn, l->addr);
-
-	  next = l->next;
-	  free (l);
-	  l = next;
+	  bfd_reloc_status_type ret;
+
+	  /* Apply the REFHI relocation.  */
+	  hi->rel.addend += vallo;
+	  ret = bfd_perform_relocation (abfd, &hi->rel, hi->data,
+					input_section, output_bfd,
+					error_message);
+	  if (ret != bfd_reloc_ok)
+	    return ret;
+
+	  sdata->u.mips_hi16_list = hi->next;
+	  free (hi);
 	}
-
-      ecoff_data (abfd)->mips_refhi_list = NULL;
     }
 
   /* Now do the REFLO reloc in the usual way.  */
diff --git a/bfd/ecoff.c b/bfd/ecoff.c
index 844f1a5247d..c8af3032e40 100644
--- a/bfd/ecoff.c
+++ b/bfd/ecoff.c
@@ -109,6 +109,29 @@ _bfd_ecoff_mkobject_hook (bfd *abfd, void * filehdr, void * aouthdr)
   return (void *) ecoff;
 }
 
+/* Free the mips_hi16_list attached to S.  Return true if there were
+   unmatched hi16 relocs.  */
+
+static bool
+free_mips_hi16_list (asection *s)
+{
+  struct ecoff_section_tdata* sdata = s->used_by_bfd;
+  if (sdata != NULL)
+    {
+      struct mips_hi16 *hi;
+      struct mips_hi16 **hip = &sdata->u.mips_hi16_list;
+      bool ret = *hip != NULL;
+
+      while ((hi = *hip) != NULL)
+	{
+	  *hip = hi->next;
+	  free (hi);
+	}
+      return ret;
+    }
+  return false;
+}
+
 bool
 _bfd_ecoff_bfd_free_cached_info (bfd *abfd)
 {
@@ -118,13 +141,14 @@ _bfd_ecoff_bfd_free_cached_info (bfd *abfd)
        || bfd_get_format (abfd) == bfd_core)
       && (tdata = ecoff_data (abfd)) != NULL)
     {
-      while (tdata->mips_refhi_list != NULL)
+      _bfd_ecoff_free_ecoff_debug_info (&tdata->debug_info);
+      if (ecoff_backend (abfd)->arch == bfd_arch_mips)
 	{
-	  struct mips_hi *ref = tdata->mips_refhi_list;
-	  tdata->mips_refhi_list = ref->next;
-	  free (ref);
+	  for (asection *s = abfd->sections; s; s = s->next)
+	    if (free_mips_hi16_list (s))
+	      _bfd_error_handler
+		(_("%pB(%pA): unmatched hi16 reloc"), abfd, s);
 	}
-      _bfd_ecoff_free_ecoff_debug_info (&tdata->debug_info);
     }
   return _bfd_generic_bfd_free_cached_info (abfd);
 }
diff --git a/bfd/libecoff.h b/bfd/libecoff.h
index 2267c7bc53b..96b8a9a4547 100644
--- a/bfd/libecoff.h
+++ b/bfd/libecoff.h
@@ -80,11 +80,11 @@ struct ecoff_backend_data
   members of the embedded bfd_coff_backend_data struct.  */
 #define ECOFF_NO_LONG_SECTION_NAMES (false), _bfd_ecoff_no_long_sections
 
-struct mips_hi
+struct mips_hi16
 {
-  struct mips_hi *next;
-  bfd_byte *addr;
-  bfd_vma addend;
+  struct mips_hi16 *next;
+  bfd_byte *data;
+  arelent rel;
 };
 
 /* This is the target specific information kept for ECOFF files.  */
@@ -151,9 +151,6 @@ typedef struct ecoff_tdata
      particular ECOFF file.  This is not valid until
      ecoff_compute_section_file_positions is called.  */
   bool rdata_in_text;
-
-  /* Used by coff-mips.c to track REFHI relocs for pairing with REFLO.  */
-  struct mips_hi *mips_refhi_list;
 } ecoff_data_type;
 
 /* Each canonical asymbol really looks like this.  */
@@ -192,13 +189,18 @@ typedef struct ecoff_symbol_struct
 
 struct ecoff_section_tdata
 {
-  /* When producing an executable (i.e., final, non-relocatable link)
-     on the Alpha, we may need to use multiple global pointer values
-     to span the entire .lita section.  In essence, we allow each
-     input .lita section to have its own gp value.  To support this,
-     we need to keep track of the gp values that we picked for each
-     input .lita section . */
-  bfd_vma gp;
+  union
+  {
+    /* When producing an executable (i.e., final, non-relocatable link)
+       on the Alpha, we may need to use multiple global pointer values
+       to span the entire .lita section.  In essence, we allow each
+       input .lita section to have its own gp value.  To support this,
+       we need to keep track of the gp values that we picked for each
+       input .lita section . */
+    bfd_vma gp;
+    /* Used by coff-mips.c to track hi16 relocs.  */
+    struct mips_hi16 *mips_hi16_list;
+  } u;
 };
 
 /* An accessor macro for the ecoff_section_tdata structure.  */

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

end of thread, other threads:[~2023-12-19  9:36 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-12-19  9:35 mips hi16/lo16 reloc handling Alan Modra
2023-12-19  9:35 ` Move mips_hi16_list to mips_elf_section_data Alan Modra
2023-12-19  9:35 ` coff-mips refhi list Alan Modra

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