as_bad_subtract

Message ID YPfyMQHD3eWmbZ+e@squeak.grove.modra.org
State New
Headers show
Series
  • as_bad_subtract
Related show

Commit Message

Florian Weimer via Binutils July 21, 2021, 10:08 a.m.
Many places report errors of the nature "can't resolve a - b".
This provides a utility function to report such errors consistently.
I removed the section reporting and quotes around symbol names while I
was at it.  Compare
ifunc-2.s:4: Error: can't resolve `bar1' {.text.1 section} - `foo1' {.text.1 section}
with
ifunc-2.s:4: Error: can't resolve bar1 - foo1

In many cases the section names don't help the user very much in
figuring out what went wrong, and the quotes if present arguably ought
to be placed around the entire expression:
can't resolve `bar1 - foo1'

The patch also tidies some tc_get_reloc functions that leak memory on
error paths.

	* write.h (as_bad_subtract): Declare.
	* write.c (as_bad_subtract): New function.
	(fixup_segment): Use as_bad_subtract.
	* config/tc-arc.c (md_apply_fix): Likewise.
	* config/tc-avr.c (md_apply_fix, tc_gen_reloc): Likewise.
	* config/tc-cris.c (md_apply_fix): Likewise.
	* config/tc-d10v.c (md_apply_fix): Likewise.
	* config/tc-d30v.c (md_apply_fix): Likewise.
	* config/tc-ft32.c (md_apply_fix): Likewise.
	* config/tc-h8300.c (tc_gen_reloc): Likewise.
	* config/tc-m68hc11.c (md_apply_fix): Likewise.
	* config/tc-mmix.c (mmix_frob_file): Likewise.
	* config/tc-mn10200.c (tc_gen_reloc): Likewise.
	* config/tc-nds32.c (nds32_apply_fix): Likewise.
	* config/tc-pru.c (md_apply_fix): Likewise.
	* config/tc-riscv.c (md_apply_fix): Likewise.
	* config/tc-s12z.c (md_apply_fix): Likewise.
	* config/tc-s390.c (md_apply_fix): Likewise.
	* config/tc-tilegx.c (md_apply_fix): Likewise.
	* config/tc-tilepro.c (md_apply_fix): Likewise.
	* config/tc-v850.c (md_apply_fix): Likewise.
	* config/tc-vax.c (md_apply_fix): Likewise.
	* config/tc-xc16x.c (tc_gen_reloc): Likewise.
	* config/tc-xgate.c (md_apply_fix): Likewise.
	* config/tc-xstormy16.c (xstormy16_md_apply_fix): Likewise.
	* config/tc-xtensa.c (md_apply_fix): Likewise.
	* config/tc-z80.c (tc_gen_reloc): Likewise.
	* config/tc-spu.c (md_apply_fix): Likewise.
	(tc_gen_reloc): Delete dead code.  Free memory on error.
	* config/tc-cr16.c (tc_gen_reloc): Use as_bad_subtract.  Free
	on error.
	* config/tc-crx.c (tc_gen_reloc): Likewise.
	* config/tc-ppc.c (tc_gen_reloc): Likewise.
	* testsuite/gas/i386/ifunc-2.l: Adjust to suit changed error message.
	* testsuite/gas/mips/lui-2.l: Likewise.
	* testsuite/gas/tic6x/reloc-bad-1.l: Likewise.


-- 
Alan Modra
Australia Development Lab, IBM

Comments

Florian Weimer via Binutils July 21, 2021, 10:17 a.m. | #1
On 21.07.2021 12:08, Alan Modra via Binutils wrote:
> Many places report errors of the nature "can't resolve a - b".

> This provides a utility function to report such errors consistently.

> I removed the section reporting and quotes around symbol names while I

> was at it.  Compare

> ifunc-2.s:4: Error: can't resolve `bar1' {.text.1 section} - `foo1' {.text.1 section}

> with

> ifunc-2.s:4: Error: can't resolve bar1 - foo1

> 

> In many cases the section names don't help the user very much in

> figuring out what went wrong,


To be honest, I find the mentioning of the sections quite useful
when they're different, because this then is an immediate hint at
why the expression cannot be resolved.

Jan
Florian Weimer via Binutils July 22, 2021, 12:47 p.m. | #2
On Wed, Jul 21, 2021 at 12:17:52PM +0200, Jan Beulich wrote:
> On 21.07.2021 12:08, Alan Modra via Binutils wrote:

> > Many places report errors of the nature "can't resolve a - b".

> > This provides a utility function to report such errors consistently.

> > I removed the section reporting and quotes around symbol names while I

> > was at it.  Compare

> > ifunc-2.s:4: Error: can't resolve `bar1' {.text.1 section} - `foo1' {.text.1 section}

> > with

> > ifunc-2.s:4: Error: can't resolve bar1 - foo1

> > 

> > In many cases the section names don't help the user very much in

> > figuring out what went wrong,

> 

> To be honest, I find the mentioning of the sections quite useful

> when they're different, because this then is an immediate hint at

> why the expression cannot be resolved.


I don't deny that the section might help a little in some cases, but
in many I think it's just a distraction.  Something like 28 places in
the gas sources now using as_bad_subtract didn't report the section
compared to 5 places that did.

-- 
Alan Modra
Australia Development Lab, IBM

Patch

diff --git a/gas/config/tc-arc.c b/gas/config/tc-arc.c
index 3cd33dace48..d03dc72b401 100644
--- a/gas/config/tc-arc.c
+++ b/gas/config/tc-arc.c
@@ -2936,12 +2936,7 @@  md_apply_fix (fixS *fixP,
 	}
       else
 	{
-	  as_bad_where (fixP->fx_file, fixP->fx_line,
-			_("can't resolve `%s' {%s section} - `%s' {%s section}"),
-			fx_addsy ? S_GET_NAME (fx_addsy) : "0",
-			segment_name (add_symbol_segment),
-			S_GET_NAME (fx_subsy),
-			segment_name (sub_symbol_segment));
+	  as_bad_subtract (fixP);
 	  return;
 	}
     }
diff --git a/gas/config/tc-avr.c b/gas/config/tc-avr.c
index 397f22d5502..40dcce7dca5 100644
--- a/gas/config/tc-avr.c
+++ b/gas/config/tc-avr.c
@@ -1548,7 +1548,7 @@  md_apply_fix (fixS *fixP, valueT * valP, segT seg)
              fixP->fx_r_type = BFD_RELOC_AVR_DIFF32;
              break;
            default:
-             as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
+             as_bad_subtract (fixP);
              break;
          }
 
@@ -1560,7 +1560,7 @@  md_apply_fix (fixS *fixP, valueT * valP, segT seg)
   }
   /* We don't actually support subtracting a symbol.  */
   if (fixP->fx_subsy != (symbolS *) NULL)
-    as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
+    as_bad_subtract (fixP);
 
   /* For the DIFF relocs, write the value into the object file while still
      keeping fx_done FALSE, as both the difference (recorded in the object file)
@@ -1824,7 +1824,7 @@  tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED,
 
   if (fixp->fx_subsy != NULL)
     {
-      as_bad_where (fixp->fx_file, fixp->fx_line, _("expression too complex"));
+      as_bad_subtract (fixp);
       return NULL;
     }
 
diff --git a/gas/config/tc-cr16.c b/gas/config/tc-cr16.c
index cbe113ef093..8925650b592 100644
--- a/gas/config/tc-cr16.c
+++ b/gas/config/tc-cr16.c
@@ -573,14 +573,10 @@  tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS * fixP)
       else
 	{
 	  /* We only resolve difference expressions in the same section.  */
-	  as_bad_where (fixP->fx_file, fixP->fx_line,
-			_("can't resolve `%s' {%s section} - `%s' {%s section}"),
-			fixP->fx_addsy ? S_GET_NAME (fixP->fx_addsy) : "0",
-			segment_name (fixP->fx_addsy
-				      ? S_GET_SEGMENT (fixP->fx_addsy)
-				      : absolute_section),
-			S_GET_NAME (fixP->fx_subsy),
-			segment_name (S_GET_SEGMENT (fixP->fx_addsy)));
+	  as_bad_subtract (fixP);
+	  free (reloc->sym_ptr_ptr);
+	  free (reloc);
+	  return NULL;
 	}
     }
 #ifdef OBJ_ELF
diff --git a/gas/config/tc-cris.c b/gas/config/tc-cris.c
index 94a32e3340d..02ce2acfe00 100644
--- a/gas/config/tc-cris.c
+++ b/gas/config/tc-cris.c
@@ -4050,8 +4050,7 @@  md_apply_fix (fixS *fixP, valueT *valP, segT seg)
 
   /* We can't actually support subtracting a symbol.  */
   if (fixP->fx_subsy != (symbolS *) NULL)
-    as_bad_where (fixP->fx_file, fixP->fx_line,
-		  _("expression too complex"));
+    as_bad_subtract (fixP);
 
   /* This operand-type is scaled.  */
   if (fixP->fx_r_type == BFD_RELOC_CRIS_LAPCQ_OFFSET)
diff --git a/gas/config/tc-crx.c b/gas/config/tc-crx.c
index d33a0bf0766..ebf38f69538 100644
--- a/gas/config/tc-crx.c
+++ b/gas/config/tc-crx.c
@@ -317,14 +317,10 @@  tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS * fixP)
       else
 	{
 	  /* We only resolve difference expressions in the same section.  */
-	  as_bad_where (fixP->fx_file, fixP->fx_line,
-			_("can't resolve `%s' {%s section} - `%s' {%s section}"),
-			fixP->fx_addsy ? S_GET_NAME (fixP->fx_addsy) : "0",
-			segment_name (fixP->fx_addsy
-				      ? S_GET_SEGMENT (fixP->fx_addsy)
-				      : absolute_section),
-			S_GET_NAME (fixP->fx_subsy),
-			segment_name (S_GET_SEGMENT (fixP->fx_addsy)));
+	  as_bad_subtract (fixP);
+	  free (reloc->sym_ptr_ptr);
+	  free (reloc);
+	  return NULL;
 	}
     }
 
diff --git a/gas/config/tc-d10v.c b/gas/config/tc-d10v.c
index 1d92f34c43c..b6437b11352 100644
--- a/gas/config/tc-d10v.c
+++ b/gas/config/tc-d10v.c
@@ -1503,7 +1503,7 @@  md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 
   /* We don't actually support subtracting a symbol.  */
   if (fixP->fx_subsy != (symbolS *) NULL)
-    as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
+    as_bad_subtract (fixP);
 
   op_type = fixP->fx_r_type;
   if (op_type & 2048)
diff --git a/gas/config/tc-d30v.c b/gas/config/tc-d30v.c
index 957182ac2aa..c48e4a3bba3 100644
--- a/gas/config/tc-d30v.c
+++ b/gas/config/tc-d30v.c
@@ -1906,7 +1906,7 @@  md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 
   /* We don't support subtracting a symbol.  */
   if (fixP->fx_subsy != (symbolS *) NULL)
-    as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
+    as_bad_subtract (fixP);
 
   /* Fetch the instruction, insert the fully resolved operand
      value, and stuff the instruction back again.  */
diff --git a/gas/config/tc-ft32.c b/gas/config/tc-ft32.c
index 91b8c36ec18..928920f82e7 100644
--- a/gas/config/tc-ft32.c
+++ b/gas/config/tc-ft32.c
@@ -570,8 +570,7 @@  md_apply_fix (fixS *fixP ATTRIBUTE_UNUSED,
              fixP->fx_r_type = BFD_RELOC_FT32_DIFF32;
              break;
            default:
-             as_bad_where (fixP->fx_file, fixP->fx_line,
-                           _("expression too complex"));
+             as_bad_subtract (fixP);
              break;
          }
 
@@ -584,7 +583,7 @@  md_apply_fix (fixS *fixP ATTRIBUTE_UNUSED,
 
   /* We don't actually support subtracting a symbol.  */
   if (fixP->fx_subsy != (symbolS *) NULL)
-    as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
+    as_bad_subtract (fixP);
 
   switch (fixP->fx_r_type)
     {
diff --git a/gas/config/tc-h8300.c b/gas/config/tc-h8300.c
index e1f359aec01..545c15e6ac6 100644
--- a/gas/config/tc-h8300.c
+++ b/gas/config/tc-h8300.c
@@ -2298,8 +2298,7 @@  tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
       if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy))
 	  || S_GET_SEGMENT (fixp->fx_addsy) == undefined_section)
 	{
-	  as_bad_where (fixp->fx_file, fixp->fx_line,
-			_("Difference of symbols in different sections is not supported"));
+	  as_bad_subtract (fixp);
 	  return NULL;
 	}
     }
diff --git a/gas/config/tc-m68hc11.c b/gas/config/tc-m68hc11.c
index b31f5cade67..a6e876c3f91 100644
--- a/gas/config/tc-m68hc11.c
+++ b/gas/config/tc-m68hc11.c
@@ -4334,7 +4334,7 @@  md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 
   /* We don't actually support subtracting a symbol.  */
   if (fixP->fx_subsy != (symbolS *) NULL)
-    as_bad_where (fixP->fx_file, fixP->fx_line, _("Expression too complex."));
+    as_bad_subtract (fixP);
 
   /* Patch the instruction with the resolved operand.  Elf relocation
      info will also be generated to take care of linker/loader fixups.
diff --git a/gas/config/tc-mmix.c b/gas/config/tc-mmix.c
index d51a0198619..04a799a5a69 100644
--- a/gas/config/tc-mmix.c
+++ b/gas/config/tc-mmix.c
@@ -3742,8 +3742,7 @@  mmix_frob_file (void)
       /* This case isn't doable in general anyway, methinks.  */
       if (fixP->fx_subsy != NULL)
 	{
-	  as_bad_where (fixP->fx_file, fixP->fx_line,
-			_("GREG expression too complicated"));
+	  as_bad_subtract (fixP);
 	  continue;
 	}
 
diff --git a/gas/config/tc-mn10200.c b/gas/config/tc-mn10200.c
index 6323e54dc27..cbec5652dfa 100644
--- a/gas/config/tc-mn10200.c
+++ b/gas/config/tc-mn10200.c
@@ -762,14 +762,7 @@  tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
 	/* FIXME: We should try more ways to resolve difference expressions
 	   here.  At least this is better than silently ignoring the
 	   subtrahend.  */
-	as_bad_where (fixp->fx_file, fixp->fx_line,
-		      _("can't resolve `%s' {%s section} - `%s' {%s section}"),
-		      fixp->fx_addsy ? S_GET_NAME (fixp->fx_addsy) : "0",
-		      segment_name (fixp->fx_addsy
-				    ? S_GET_SEGMENT (fixp->fx_addsy)
-				    : absolute_section),
-		      S_GET_NAME (fixp->fx_subsy),
-		      segment_name (S_GET_SEGMENT (fixp->fx_addsy)));
+	as_bad_subtract (fixp);
     }
 
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
diff --git a/gas/config/tc-nds32.c b/gas/config/tc-nds32.c
index 4ff667caf61..0ab436c5f19 100644
--- a/gas/config/tc-nds32.c
+++ b/gas/config/tc-nds32.c
@@ -7825,8 +7825,7 @@  nds32_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 	  /* cvt_frag_to_fill () has called output_leb128 () for us.  */
 	  break;
 	default:
-	  as_bad_where (fixP->fx_file, fixP->fx_line,
-			_("expression too complex"));
+	  as_bad_subtract (fixP);
 	  return;
 	}
     }
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index 567f8011a5f..3eaeb892387 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -7476,7 +7476,7 @@  tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
     }
   reloc->addend = fixp->fx_addnumber;
 
-  if (fixp->fx_subsy && fixp->fx_addsy)
+  if (fixp->fx_subsy != NULL)
     {
       relocs[1] = reloc = XNEW (arelent);
       relocs[2] = NULL;
@@ -7490,9 +7490,11 @@  tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
 
       if (reloc->howto == (reloc_howto_type *) NULL)
         {
-          as_bad_where (fixp->fx_file, fixp->fx_line,
-            _("reloc %d not supported by object file format"),
-            BFD_RELOC_PPC_NEG);
+	  as_bad_subtract (fixp);
+	  free (relocs[1]->sym_ptr_ptr);
+	  free (relocs[1]);
+	  free (relocs[0]->sym_ptr_ptr);
+	  free (relocs[0]);
 	  relocs[0] = NULL;
         }
     }
diff --git a/gas/config/tc-pru.c b/gas/config/tc-pru.c
index 14876f4fe4f..16678b13333 100644
--- a/gas/config/tc-pru.c
+++ b/gas/config/tc-pru.c
@@ -742,8 +742,7 @@  md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 	  diffval /= 4;
 	  break;
 	default:
-	  as_bad_where (fixP->fx_file, fixP->fx_line,
-			_("expression too complex"));
+	  as_bad_subtract (fixP);
 	  break;
 	}
 
@@ -753,7 +752,7 @@  md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
   }
   /* We don't actually support subtracting a symbol.  */
   if (fixP->fx_subsy != (symbolS *) NULL)
-    as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
+    as_bad_subtract (fixP);
 
   /* For the DIFF relocs, write the value into the object file while still
      keeping fx_done FALSE, as both the difference (recorded in the object file)
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index df37579c843..460667e4349 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -3201,8 +3201,7 @@  md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     }
 
   if (fixP->fx_subsy != NULL)
-    as_bad_where (fixP->fx_file, fixP->fx_line,
-		  _("unsupported symbol subtraction"));
+    as_bad_subtract (fixP);
 
   /* Add an R_RISCV_RELAX reloc if the reloc is relaxable.  */
   if (relaxable && fixP->fx_tcbit && fixP->fx_addsy != NULL)
diff --git a/gas/config/tc-s12z.c b/gas/config/tc-s12z.c
index 6ec4d5c63b8..11a412d33ca 100644
--- a/gas/config/tc-s12z.c
+++ b/gas/config/tc-s12z.c
@@ -3933,7 +3933,7 @@  md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 
   /* We don't actually support subtracting a symbol.  */
   if (fixP->fx_subsy != (symbolS *) NULL)
-    as_bad_where (fixP->fx_file, fixP->fx_line, _("Expression too complex."));
+    as_bad_subtract (fixP);
 
   /*
     Patch the instruction with the resolved operand.  Elf relocation
diff --git a/gas/config/tc-s390.c b/gas/config/tc-s390.c
index 064dd33ad4e..a203436878d 100644
--- a/gas/config/tc-s390.c
+++ b/gas/config/tc-s390.c
@@ -2254,10 +2254,7 @@  md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
   where = fixP->fx_frag->fr_literal + fixP->fx_where;
 
   if (fixP->fx_subsy != NULL)
-    as_bad_where (fixP->fx_file, fixP->fx_line,
-		  _("cannot emit relocation %s against subsy symbol %s"),
-		  bfd_get_reloc_code_name (fixP->fx_r_type),
-		  S_GET_NAME (fixP->fx_subsy));
+    as_bad_subtract (fixP);
 
   if (fixP->fx_addsy != NULL)
     {
diff --git a/gas/config/tc-spu.c b/gas/config/tc-spu.c
index f9055a55d2d..11fafa1a390 100644
--- a/gas/config/tc-spu.c
+++ b/gas/config/tc-spu.c
@@ -868,12 +868,7 @@  tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
   arelent *reloc;
   reloc = XNEW (arelent);
   reloc->sym_ptr_ptr = XNEW (asymbol *);
-  if (fixp->fx_addsy)
-    *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
-  else if (fixp->fx_subsy)
-    *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
-  else
-    abort ();
+  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
   if (reloc->howto == (reloc_howto_type *) NULL)
@@ -881,6 +876,8 @@  tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
       as_bad_where (fixp->fx_file, fixp->fx_line,
 		    _("reloc %d not supported by object file format"),
 		    (int) fixp->fx_r_type);
+      free (reloc->sym_ptr_ptr);
+      free (reloc);
       return NULL;
     }
   reloc->addend = fixp->fx_addnumber;
@@ -957,7 +954,7 @@  md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
   if (fixP->fx_subsy != (symbolS *) NULL)
     {
       /* We can't actually support subtracting a symbol.  */
-      as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
+      as_bad_subtract (fixP);
     }
 
   if (fixP->fx_addsy != NULL)
diff --git a/gas/config/tc-tilegx.c b/gas/config/tc-tilegx.c
index e041b4a64d7..97062c0d365 100644
--- a/gas/config/tc-tilegx.c
+++ b/gas/config/tc-tilegx.c
@@ -1476,7 +1476,7 @@  md_apply_fix (fixS *fixP, valueT * valP, segT seg ATTRIBUTE_UNUSED)
   if (fixP->fx_subsy != (symbolS *) NULL)
     {
       /* We can't actually support subtracting a symbol.  */
-      as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
+      as_bad_subtract (fixP);
     }
 
   /* Correct relocation types for pc-relativeness.  */
diff --git a/gas/config/tc-tilepro.c b/gas/config/tc-tilepro.c
index 365b621ccdd..11893bc34ca 100644
--- a/gas/config/tc-tilepro.c
+++ b/gas/config/tc-tilepro.c
@@ -1334,7 +1334,7 @@  md_apply_fix (fixS *fixP, valueT * valP, segT seg ATTRIBUTE_UNUSED)
   if (fixP->fx_subsy != (symbolS *) NULL)
     {
       /* We can't actually support subtracting a symbol.  */
-      as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
+      as_bad_subtract (fixP);
     }
 
   /* Correct relocation types for pc-relativeness.  */
diff --git a/gas/config/tc-v850.c b/gas/config/tc-v850.c
index 5bfebba5643..81449d05741 100644
--- a/gas/config/tc-v850.c
+++ b/gas/config/tc-v850.c
@@ -3447,8 +3447,7 @@  md_apply_fix (fixS *fixP, valueT *valueP, segT seg ATTRIBUTE_UNUSED)
 	    value -= S_GET_VALUE (fixP->fx_subsy);
 	  else
 	    /* We don't actually support subtracting a symbol.  */
-	    as_bad_where (fixP->fx_file, fixP->fx_line,
-			  _("expression too complex"));
+	    as_bad_subtract (fixP);
 	}
       fixP->fx_addnumber = value;
     }
diff --git a/gas/config/tc-vax.c b/gas/config/tc-vax.c
index f439f1b52dc..efffc7d1fd2 100644
--- a/gas/config/tc-vax.c
+++ b/gas/config/tc-vax.c
@@ -279,7 +279,7 @@  md_apply_fix (fixS *fixP, valueT *valueP, segT seg ATTRIBUTE_UNUSED)
   valueT value = * valueP;
 
   if (fixP->fx_subsy != (symbolS *) NULL)
-    as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
+    as_bad_subtract (fixP);
 
   if (fixP->fx_addsy == NULL)
     fixP->fx_done = 1;
diff --git a/gas/config/tc-xc16x.c b/gas/config/tc-xc16x.c
index 7d89a37166d..12d90703153 100644
--- a/gas/config/tc-xc16x.c
+++ b/gas/config/tc-xc16x.c
@@ -283,13 +283,12 @@  tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
   arelent *rel;
   bfd_reloc_code_real_type r_type;
 
-  if (fixp->fx_addsy && fixp->fx_subsy)
+  if (fixp->fx_subsy)
     {
       if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy))
 	  || S_GET_SEGMENT (fixp->fx_addsy) == undefined_section)
 	{
-	  as_bad_where (fixp->fx_file, fixp->fx_line,
-			_("Difference of symbols in different sections is not supported"));
+	  as_bad_subtract (fixp);
 	  return NULL;
 	}
     }
diff --git a/gas/config/tc-xgate.c b/gas/config/tc-xgate.c
index 5f5d1652191..f97540a32dc 100644
--- a/gas/config/tc-xgate.c
+++ b/gas/config/tc-xgate.c
@@ -660,7 +660,7 @@  md_apply_fix (fixS * fixP, valueT * valP, segT seg ATTRIBUTE_UNUSED)
 
   /* We don't actually support subtracting a symbol.  */
   if (fixP->fx_subsy != (symbolS *) NULL)
-    as_bad_where (fixP->fx_file, fixP->fx_line, _("Expression too complex."));
+    as_bad_subtract (fixP);
 
   where = fixP->fx_frag->fr_literal + fixP->fx_where;
   opcode = bfd_getl16 (where);
diff --git a/gas/config/tc-xstormy16.c b/gas/config/tc-xstormy16.c
index 3edf384350a..deb10810b06 100644
--- a/gas/config/tc-xstormy16.c
+++ b/gas/config/tc-xstormy16.c
@@ -479,7 +479,7 @@  xstormy16_md_apply_fix (fixS *   fixP,
 
   /* We don't actually support subtracting a symbol.  */
   if (fixP->fx_subsy != (symbolS *) NULL)
-    as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
+    as_bad_subtract (fixP);
 
   if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
     {
diff --git a/gas/config/tc-xtensa.c b/gas/config/tc-xtensa.c
index 452d4a757e9..b8634f782f8 100644
--- a/gas/config/tc-xtensa.c
+++ b/gas/config/tc-xtensa.c
@@ -6006,7 +6006,7 @@  md_apply_fix (fixS *fixP, valueT *valP, segT seg)
   if (fixP->fx_subsy && !(linkrelax && (fixP->fx_r_type == BFD_RELOC_32
 					|| fixP->fx_r_type == BFD_RELOC_16
 					|| fixP->fx_r_type == BFD_RELOC_8)))
-    as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
+    as_bad_subtract (fixP);
 
   switch (fixP->fx_r_type)
     {
diff --git a/gas/config/tc-z80.c b/gas/config/tc-z80.c
index 303296b7dab..052982fc65e 100644
--- a/gas/config/tc-z80.c
+++ b/gas/config/tc-z80.c
@@ -3853,7 +3853,7 @@  tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED , fixS *fixp)
 
   if (fixp->fx_subsy != NULL)
     {
-      as_bad_where (fixp->fx_file, fixp->fx_line, _("expression too complex"));
+      as_bad_subtract (fixp);
       return NULL;
     }
 
diff --git a/gas/testsuite/gas/i386/ifunc-2.l b/gas/testsuite/gas/i386/ifunc-2.l
index 0ed314b0ec5..280a0c60d1b 100644
--- a/gas/testsuite/gas/i386/ifunc-2.l
+++ b/gas/testsuite/gas/i386/ifunc-2.l
@@ -1,61 +1,61 @@ 
 .*/ifunc-2\.s: Assembler messages:
-.*/ifunc-2\.s:4: Error: can't resolve `bar1' {\.text\.1 section} - `foo1' {\.text\.1 section}
-.*/ifunc-2\.s:5: Error: can't resolve `bar2' {\.text\.2 section} - `foo2' {\.text\.2 section}
-.*/ifunc-2\.s:6: Error: can't resolve `bar1' {\.text\.1 section} - `bar2' {\.text\.2 section}
-.*/ifunc-2\.s:7: Error: can't resolve `bar2' {\.text\.2 section} - `bar1' {\.text\.1 section}
-.*/ifunc-2\.s:8: Error: can't resolve `\.text\.1' {\.text\.1 section} - `bar1' {\.text\.1 section}
-.*/ifunc-2\.s:9: Error: can't resolve `\.text\.1' {\.text\.1 section} - `bar2' {\.text\.2 section}
-.*/ifunc-2\.s:10: Error: can't resolve `bar1' {\.text\.1 section} - `abs1' {\*ABS\* section}
-.*/ifunc-2\.s:11: Error: can't resolve `abs1' {\*ABS\* section} - `bar1' {\.text\.1 section}
-.*/ifunc-2\.s:12: Error: can't resolve `\.text\.1' {\.text\.1 section} - `bar1' {\.text\.1 section}
-.*/ifunc-2\.s:19: Error: can't resolve `bar1' {\.text\.1 section} - `foo1' {\.text\.1 section}
-.*/ifunc-2\.s:20: Error: can't resolve `bar2' {\.text\.2 section} - `foo2' {\.text\.2 section}
-.*/ifunc-2\.s:21: Error: can't resolve `bar1' {\.text\.1 section} - `bar2' {\.text\.2 section}
-.*/ifunc-2\.s:22: Error: can't resolve `bar2' {\.text\.2 section} - `bar1' {\.text\.1 section}
-.*/ifunc-2\.s:23: Error: can't resolve `\.text\.1' {\.text\.1 section} - `bar1' {\.text\.1 section}
-.*/ifunc-2\.s:24: Error: can't resolve `\.text\.1' {\.text\.1 section} - `bar2' {\.text\.2 section}
-.*/ifunc-2\.s:25: Error: can't resolve `bar1' {\.text\.1 section} - `abs1' {\*ABS\* section}
-.*/ifunc-2\.s:26: Error: can't resolve `abs1' {\*ABS\* section} - `bar1' {\.text\.1 section}
-.*/ifunc-2\.s:27: Error: can't resolve `\.text\.1' {\.text\.1 section} - `bar1' {\.text\.1 section}
-.*/ifunc-2\.s:34: Error: can't resolve `bar1' {\.text\.1 section} - `foo1' {\.text\.1 section}
-.*/ifunc-2\.s:35: Error: can't resolve `bar2' {\.text\.2 section} - `foo2' {\.text\.2 section}
-.*/ifunc-2\.s:36: Error: can't resolve `bar1' {\.text\.1 section} - `bar2' {\.text\.2 section}
-.*/ifunc-2\.s:37: Error: can't resolve `bar2' {\.text\.2 section} - `bar1' {\.text\.1 section}
-.*/ifunc-2\.s:38: Error: can't resolve `\.text\.1' {\.text\.1 section} - `bar1' {\.text\.1 section}
-.*/ifunc-2\.s:39: Error: can't resolve `\.text\.1' {\.text\.1 section} - `bar2' {\.text\.2 section}
-.*/ifunc-2\.s:40: Error: can't resolve `bar1' {\.text\.1 section} - `abs1' {\*ABS\* section}
-.*/ifunc-2\.s:41: Error: can't resolve `abs1' {\*ABS\* section} - `bar1' {\.text\.1 section}
-.*/ifunc-2\.s:42: Error: can't resolve `\.text\.1' {\.text\.1 section} - `bar1' {\.text\.1 section}
-.*/ifunc-2\.s:44: Error: can't resolve `abs1' {\*ABS\* section} - `abs2' {\*ABS\* section}
-.*/ifunc-2\.s:45: Error: can't resolve `abs2' {\*ABS\* section} - `abs1' {\*ABS\* section}
-.*/ifunc-2\.s:50: Error: can't resolve `abs1' {\*ABS\* section} - `abs2' {\*ABS\* section}
-.*/ifunc-2\.s:51: Error: can't resolve `abs2' {\*ABS\* section} - `abs1' {\*ABS\* section}
-.*/ifunc-2\.s:56: Error: can't resolve `abs1' {\*ABS\* section} - `abs2' {\*ABS\* section}
-.*/ifunc-2\.s:57: Error: can't resolve `abs2' {\*ABS\* section} - `abs1' {\*ABS\* section}
-.*/ifunc-2\.s:62: Error: can't resolve `bar1' {\.text\.1 section} - `foo1' {\.text\.1 section}
-.*/ifunc-2\.s:63: Error: can't resolve `bar2' {\.text\.2 section} - `foo2' {\.text\.2 section}
-.*/ifunc-2\.s:64: Error: can't resolve `bar1' {\.text\.1 section} - `bar2' {\.text\.2 section}
-.*/ifunc-2\.s:65: Error: can't resolve `bar2' {\.text\.2 section} - `bar1' {\.text\.1 section}
-.*/ifunc-2\.s:66: Error: can't resolve `\.text\.2' {\.text\.2 section} - `bar1' {\.text\.1 section}
-.*/ifunc-2\.s:67: Error: can't resolve `\.text\.2' {\.text\.2 section} - `bar2' {\.text\.2 section}
-.*/ifunc-2\.s:68: Error: can't resolve `bar2' {\.text\.2 section} - `abs1' {\*ABS\* section}
-.*/ifunc-2\.s:69: Error: can't resolve `abs1' {\*ABS\* section} - `bar2' {\.text\.2 section}
-.*/ifunc-2\.s:70: Error: can't resolve `\.text\.2' {\.text\.2 section} - `bar2' {\.text\.2 section}
-.*/ifunc-2\.s:77: Error: can't resolve `bar1' {\.text\.1 section} - `foo1' {\.text\.1 section}
-.*/ifunc-2\.s:78: Error: can't resolve `bar2' {\.text\.2 section} - `foo2' {\.text\.2 section}
-.*/ifunc-2\.s:79: Error: can't resolve `bar1' {\.text\.1 section} - `bar2' {\.text\.2 section}
-.*/ifunc-2\.s:80: Error: can't resolve `bar2' {\.text\.2 section} - `bar1' {\.text\.1 section}
-.*/ifunc-2\.s:81: Error: can't resolve `\.text\.2' {\.text\.2 section} - `bar1' {\.text\.1 section}
-.*/ifunc-2\.s:82: Error: can't resolve `\.text\.2' {\.text\.2 section} - `bar2' {\.text\.2 section}
-.*/ifunc-2\.s:83: Error: can't resolve `bar2' {\.text\.2 section} - `abs1' {\*ABS\* section}
-.*/ifunc-2\.s:84: Error: can't resolve `abs1' {\*ABS\* section} - `bar2' {\.text\.2 section}
-.*/ifunc-2\.s:85: Error: can't resolve `\.text\.2' {\.text\.2 section} - `bar2' {\.text\.2 section}
-.*/ifunc-2\.s:92: Error: can't resolve `bar1' {\.text\.1 section} - `foo1' {\.text\.1 section}
-.*/ifunc-2\.s:93: Error: can't resolve `bar2' {\.text\.2 section} - `foo2' {\.text\.2 section}
-.*/ifunc-2\.s:94: Error: can't resolve `bar1' {\.text\.1 section} - `bar2' {\.text\.2 section}
-.*/ifunc-2\.s:95: Error: can't resolve `bar2' {\.text\.2 section} - `bar1' {\.text\.1 section}
-.*/ifunc-2\.s:96: Error: can't resolve `\.text\.2' {\.text\.2 section} - `bar1' {\.text\.1 section}
-.*/ifunc-2\.s:97: Error: can't resolve `\.text\.2' {\.text\.2 section} - `bar2' {\.text\.2 section}
-.*/ifunc-2\.s:98: Error: can't resolve `bar2' {\.text\.2 section} - `abs1' {\*ABS\* section}
-.*/ifunc-2\.s:99: Error: can't resolve `abs1' {\*ABS\* section} - `bar2' {\.text\.2 section}
-.*/ifunc-2\.s:100: Error: can't resolve `\.text\.2' {\.text\.2 section} - `bar2' {\.text\.2 section}
+.*/ifunc-2\.s:4: Error: can't resolve bar1 - foo1
+.*/ifunc-2\.s:5: Error: can't resolve bar2 - foo2
+.*/ifunc-2\.s:6: Error: can't resolve bar1 - bar2
+.*/ifunc-2\.s:7: Error: can't resolve bar2 - bar1
+.*/ifunc-2\.s:8: Error: can't resolve \.text\.1 - bar1
+.*/ifunc-2\.s:9: Error: can't resolve \.text\.1 - bar2
+.*/ifunc-2\.s:10: Error: can't resolve bar1 - abs1
+.*/ifunc-2\.s:11: Error: can't resolve abs1 - bar1
+.*/ifunc-2\.s:12: Error: can't resolve \.text\.1 - bar1
+.*/ifunc-2\.s:19: Error: can't resolve bar1 - foo1
+.*/ifunc-2\.s:20: Error: can't resolve bar2 - foo2
+.*/ifunc-2\.s:21: Error: can't resolve bar1 - bar2
+.*/ifunc-2\.s:22: Error: can't resolve bar2 - bar1
+.*/ifunc-2\.s:23: Error: can't resolve \.text\.1 - bar1
+.*/ifunc-2\.s:24: Error: can't resolve \.text\.1 - bar2
+.*/ifunc-2\.s:25: Error: can't resolve bar1 - abs1
+.*/ifunc-2\.s:26: Error: can't resolve abs1 - bar1
+.*/ifunc-2\.s:27: Error: can't resolve \.text\.1 - bar1
+.*/ifunc-2\.s:34: Error: can't resolve bar1 - foo1
+.*/ifunc-2\.s:35: Error: can't resolve bar2 - foo2
+.*/ifunc-2\.s:36: Error: can't resolve bar1 - bar2
+.*/ifunc-2\.s:37: Error: can't resolve bar2 - bar1
+.*/ifunc-2\.s:38: Error: can't resolve \.text\.1 - bar1
+.*/ifunc-2\.s:39: Error: can't resolve \.text\.1 - bar2
+.*/ifunc-2\.s:40: Error: can't resolve bar1 - abs1
+.*/ifunc-2\.s:41: Error: can't resolve abs1 - bar1
+.*/ifunc-2\.s:42: Error: can't resolve \.text\.1 - bar1
+.*/ifunc-2\.s:44: Error: can't resolve abs1 - abs2
+.*/ifunc-2\.s:45: Error: can't resolve abs2 - abs1
+.*/ifunc-2\.s:50: Error: can't resolve abs1 - abs2
+.*/ifunc-2\.s:51: Error: can't resolve abs2 - abs1
+.*/ifunc-2\.s:56: Error: can't resolve abs1 - abs2
+.*/ifunc-2\.s:57: Error: can't resolve abs2 - abs1
+.*/ifunc-2\.s:62: Error: can't resolve bar1 - foo1
+.*/ifunc-2\.s:63: Error: can't resolve bar2 - foo2
+.*/ifunc-2\.s:64: Error: can't resolve bar1 - bar2
+.*/ifunc-2\.s:65: Error: can't resolve bar2 - bar1
+.*/ifunc-2\.s:66: Error: can't resolve \.text\.2 - bar1
+.*/ifunc-2\.s:67: Error: can't resolve \.text\.2 - bar2
+.*/ifunc-2\.s:68: Error: can't resolve bar2 - abs1
+.*/ifunc-2\.s:69: Error: can't resolve abs1 - bar2
+.*/ifunc-2\.s:70: Error: can't resolve \.text\.2 - bar2
+.*/ifunc-2\.s:77: Error: can't resolve bar1 - foo1
+.*/ifunc-2\.s:78: Error: can't resolve bar2 - foo2
+.*/ifunc-2\.s:79: Error: can't resolve bar1 - bar2
+.*/ifunc-2\.s:80: Error: can't resolve bar2 - bar1
+.*/ifunc-2\.s:81: Error: can't resolve \.text\.2 - bar1
+.*/ifunc-2\.s:82: Error: can't resolve \.text\.2 - bar2
+.*/ifunc-2\.s:83: Error: can't resolve bar2 - abs1
+.*/ifunc-2\.s:84: Error: can't resolve abs1 - bar2
+.*/ifunc-2\.s:85: Error: can't resolve \.text\.2 - bar2
+.*/ifunc-2\.s:92: Error: can't resolve bar1 - foo1
+.*/ifunc-2\.s:93: Error: can't resolve bar2 - foo2
+.*/ifunc-2\.s:94: Error: can't resolve bar1 - bar2
+.*/ifunc-2\.s:95: Error: can't resolve bar2 - bar1
+.*/ifunc-2\.s:96: Error: can't resolve \.text\.2 - bar1
+.*/ifunc-2\.s:97: Error: can't resolve \.text\.2 - bar2
+.*/ifunc-2\.s:98: Error: can't resolve bar2 - abs1
+.*/ifunc-2\.s:99: Error: can't resolve abs1 - bar2
+.*/ifunc-2\.s:100: Error: can't resolve \.text\.2 - bar2
diff --git a/gas/testsuite/gas/mips/lui-2.l b/gas/testsuite/gas/mips/lui-2.l
index 635f97d2a8c..713bd798048 100644
--- a/gas/testsuite/gas/mips/lui-2.l
+++ b/gas/testsuite/gas/mips/lui-2.l
@@ -1,5 +1,5 @@ 
 .*\.s: Assembler messages:
 .*\.s:10: Error: invalid operands \(\*UND\* and \*UND\* sections\) for `/'
 .*\.s:7: Error: PC-relative reference to a different section
-.*\.s:8: Error: can't resolve `baz' {\*UND\* section} - `bar' {\*UND\* section}
-.*\.s:9: Error: can't resolve `\.text' {\.text section} - `baz' {\*UND\* section}
+.*\.s:8: Error: can't resolve baz - bar
+.*\.s:9: Error: can't resolve \.text - baz
diff --git a/gas/testsuite/gas/tic6x/reloc-bad-1.l b/gas/testsuite/gas/tic6x/reloc-bad-1.l
index 9a94d3e72b0..29272121cc2 100644
--- a/gas/testsuite/gas/tic6x/reloc-bad-1.l
+++ b/gas/testsuite/gas/tic6x/reloc-bad-1.l
@@ -1,2 +1,2 @@ 
 [^:]*: Assembler messages:
-[^:]*:8: Error: can't resolve `a' \{\*UND\* section\} - `b' \{\*UND\* section\}
+[^:]*:8: Error: can't resolve a - b
diff --git a/gas/write.c b/gas/write.c
index 2d67f167ff0..253dfc476f8 100644
--- a/gas/write.c
+++ b/gas/write.c
@@ -899,6 +899,15 @@  adjust_reloc_syms (bfd *abfd ATTRIBUTE_UNUSED,
   dump_section_relocs (abfd, sec, stderr);
 }
 
+void
+as_bad_subtract (fixS *fixp)
+{
+  as_bad_where (fixp->fx_file, fixp->fx_line,
+		_("can't resolve %s - %s"),
+		fixp->fx_addsy ? S_GET_NAME (fixp->fx_addsy) : "0",
+		S_GET_NAME (fixp->fx_subsy));
+}
+
 /* fixup_segment()
 
    Go through all the fixS's in a segment and see which ones can be
@@ -1021,12 +1030,7 @@  fixup_segment (fixS *fixP, segT this_segment)
 		as_bad_where (fixP->fx_file, fixP->fx_line,
 			      _("register value used as expression"));
 	      else
-		as_bad_where (fixP->fx_file, fixP->fx_line,
-			      _("can't resolve `%s' {%s section} - `%s' {%s section}"),
-			      fixP->fx_addsy ? S_GET_NAME (fixP->fx_addsy) : "0",
-			      segment_name (add_symbol_segment),
-			      S_GET_NAME (fixP->fx_subsy),
-			      segment_name (sub_symbol_segment));
+		as_bad_subtract (fixP);
 	    }
 	  else if (sub_symbol_segment != undefined_section
 		   && ! bfd_is_com_section (sub_symbol_segment)
diff --git a/gas/write.h b/gas/write.h
index dc61c888fab..74d07bff0ea 100644
--- a/gas/write.h
+++ b/gas/write.h
@@ -184,5 +184,6 @@  extern fixS *fix_at_start (fragS *, unsigned long, symbolS *,
 extern fixS *fix_new_exp (fragS *, unsigned long, unsigned long,
 			  expressionS *, int, bfd_reloc_code_real_type);
 extern void write_print_statistics (FILE *);
+extern void as_bad_subtract (fixS *);
 
 #endif /* __write_h__ */