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]

gas TC_PARSE_CONS_EXPRESSION communication with TC_CONS_FIX_NEW


A number of targets pass extra information from TC_PARSE_CONS_EXPRESSION
to TC_CONS_FIX_NEW via static variables.  That's OK, but not best
practice.  tc-ppc.c is worse, implementing its own replacement for
cons() because the generic one doesn't allow relocation modifiers
on constants.  This patch fixes both of these warts.

I've also changed ppc and v850 over from using BFD_RELOC_UNUSED to
mean "no relocation" to BFD_RELOC_NONE.  The former made sense when
the fixup reloc field, fx_r_type, was being used for both relocation
types and an operand type encoded as BFD_RELOC_UNUSED+op_index.

    	* gas/config/tc-alpha.h (TC_CONS_FIX_NEW): Add RELOC parameter.
    	* gas/config/tc-arc.c (arc_cons_fix_new): Add reloc parameter.
    	* gas/config/tc-arc.h (arc_cons_fix_new): Update prototype.
    	(TC_CONS_FIX_NEW): Add RELOC parameter.
    	* gas/config/tc-arm.c (cons_fix_new_arm): Similarly
    	* gas/config/tc-arm.h (cons_fix_new_arm, TC_CONS_FIX_NEW): Similarly.
    	* gas/config/tc-cr16.c (cr16_cons_fix_new): Similarly.
    	* gas/config/tc-cr16.h (cr16_cons_fix_new, TC_CONS_FIX_NEW): Similarly.
    	* gas/config/tc-crx.h (TC_CONS_FIX_NEW): Similarly.
    	* gas/config/tc-m32c.c (m32c_cons_fix_new): Similarly.
    	* gas/config/tc-m32c.h (m32c_cons_fix_new, TC_CONS_FIX_NEW): Similarly.
    	* gas/config/tc-mn10300.c (mn10300_cons_fix_new): Similarly.
    	* gas/config/tc-mn10300.h (mn10300_cons_fix_new, TC_CONS_FIX_NEW):
    	Similarly.
    	* gas/config/tc-ns32k.c (cons_fix_new_ns32k): Similarly.
    	* gas/config/tc-ns32k.h (cons_fix_new_ns32k): Similarly.
    	* gas/config/tc-pj.c (pj_cons_fix_new_pj): Similarly.
    	* gas/config/tc-pj.h (pj_cons_fix_new_pj, TC_CONS_FIX_NEW): Similarly.
    	* gas/config/tc-rx.c (rx_cons_fix_new): Similarly.
    	* gas/config/tc-rx.h (rx_cons_fix_new, TC_CONS_FIX_NEW): Similarly.
    	* gas/config/tc-sh.c (sh_cons_fix_new): Similarly.
    	* gas/config/tc-sh.h (sh_cons_fix_new, TC_CONS_FIX_NEW): Similarly.
    	* gas/config/tc-tic54x.c (tic54x_cons_fix_new): Similarly.
    	* gas/config/tc-tic54x.h (tic54x_cons_fix_new, TC_CONS_FIX_NEW):
    	Similarly.
    	* gas/config/tc-tic6x.c (tic6x_cons_fix_new): Similarly.
    	* gas/config/tc-tic6x.h (tic6x_cons_fix_new, TC_CONS_FIX_NEW):
    	Similarly.
    	* gas/config/tc-arc.c (arc_parse_cons_expression): Return reloc.
    	* gas/config/tc-arc.h (arc_parse_cons_expression): Update proto.
    	* gas/config/tc-avr.c (exp_mod_data): Make global.
    	(pexp_mod_data): Delete.
    	(avr_parse_cons_expression): Return exp_mod_data pointer.
    	(avr_cons_fix_new): Add exp_mod_data_t pointer param.
    	(exp_mod_data_t): Move typedef..
    	* gas/config/tc-avr.h: ..to here.
    	(exp_mod_data): Declare.
    	(TC_PARSE_CONS_RETURN_TYPE, TC_PARSE_CONS_RETURN_NONE): Define.
    	(avr_parse_cons_expression, avr_cons_fix_new): Update prototype.
    	(TC_CONS_FIX_NEW): Update.
    	* gas/config/tc-hppa.c (hppa_field_selector): Delete static var.
    	(cons_fix_new_hppa): Add hppa_field_selector param.
    	(fix_new_hppa): Adjust.
    	(parse_cons_expression_hppa): Return field selector.
    	* gas/config/tc-hppa.h (parse_cons_expression_hppa): Update proto.
    	(cons_fix_new_hppa): Likewise.
    	(TC_PARSE_CONS_RETURN_TYPE, TC_PARSE_CONS_RETURN_NONE): Define.
    	* gas/config/tc-i386.c (got_reloc): Delete static var.
    	(x86_cons_fix_new): Add reloc param.
    	(x86_cons): Return got reloc.
    	* gas/config/tc-i386.h (x86_cons, x86_cons_fix_new): Update proto.
    	(TC_CONS_FIX_NEW): Add RELOC param.
    	* gas/config/tc-ia64.c (ia64_cons_fix_new): Add reloc param.  Adjust
    	calls.
    	* gas/config/tc-ia64.h (ia64_cons_fix_new): Update prototype.
    	(TC_CONS_FIX_NEW): Add reloc param.
    	* gas/config/tc-microblaze.c (parse_cons_expression_microblaze):
    	Return reloc.
    	(cons_fix_new_microblaze): Add reloc param.
    	* gas/config/tc-microblaze.h: Formatting.
    	(parse_cons_expression_microblaze): Update proto.
    	(cons_fix_new_microblaze): Likewise.
    	* gas/config/tc-nios2.c (nios2_tls_ldo_reloc): Delete static var.
    	(nios2_cons): Return ldo reloc.
    	(nios2_cons_fix_new): Delete.
    	* gas/config/tc-nios2.h (nios2_cons): Update prototype.
    	(nios2_cons_fix_new, TC_CONS_FIX_NEW): Delete.
    	* gas/config/tc-ppc.c (md_pseudo_table): Remove quad, long, word,
    	short.  Make llong use cons.
    	(ppc_elf_suffix): Return BFD_RELOC_NONE rather than BFD_RELOC_UNUSED.
    	(ppc_elf_cons): Delete.
    	(ppc_elf_parse_cons): New function.
    	(ppc_elf_validate_fix): Don't check for BFD_RELOC_UNUSED.
    	(md_assemble): Use BFD_RELOC_NONE rather than BFD_RELOC_UNUSED.
    	* gas/config/tc-ppc.h (TC_PARSE_CONS_EXPRESSION): Define
    	(ppc_elf_parse_cons): Declare.
    	* gas/config/tc-sparc.c (sparc_cons_special_reloc): Delete static var.
    	(sparc_cons): Return reloc specifier.
    	(cons_fix_new_sparc): Add reloc specifier param.
    	(sparc_cfi_emit_pcrel_expr): Use emit_expr_with_reloc.
    	* gas/config/tc-sparc.h (TC_PARSE_CONS_RETURN_TYPE): Define.
    	(TC_PARSE_CONS_RETURN_NONE): Define.
    	(sparc_cons, cons_fix_new_sparc): Update prototype.
    	* gas/config/tc-v850.c (hold_cons_reloc): Delete static var.
    	(v850_reloc_prefix): Use BFD_RELOC_NONE rather than BFD_RELOC_UNUSED.
    	(md_assemble): Likewise.
    	(parse_cons_expression_v850): Return reloc.
    	(cons_fix_new_v850): Add reloc parameter.
    	* gas/config/tc-v850.h (parse_cons_expression_v850): Update proto.
    	(cons_fix_new_v850): Likewise.
    	* gas/config/tc-vax.c (vax_cons_special_reloc): Delete static var.
    	(vax_cons): Return reloc.
    	(vax_cons_fix_new): Add reloc parameter.
    	* gas/config/tc-vax.h (vax_cons, vax_cons_fix_new): Update proto.
    	* gas/config/tc-xstormy16.c (xstormy16_cons_fix_new): Add reloc param.
    	* gas/config/tc-xstormy16.h (xstormy16_cons_fix_new): Update proto.
    	* gas/dwarf2dbg.c (TC_PARSE_CONS_RETURN_NONE): Provide default.
    	(emit_fixed_inc_line_addr): Adjust exmit_expr_fix calls.
    	* gas/read.c (TC_PARSE_CONS_EXPRESSION): Return value.
    	(do_parse_cons_expression): Adjust.
    	(cons_worker): Pass return value from TC_PARSE_CONS_EXPRESSION
    	to emit_expr_with_reloc.
    	(emit_expr_with_reloc): New function handling reloc, mostly
    	extracted from..
    	(emit_expr): ..here.
    	(emit_expr_fix): Add reloc param.  Adjust TC_CONS_FIX_NEW invocation.
    	Handle reloc.
    	(parse_mri_cons): Convert to ISO.
    	* gas/read.h (TC_PARSE_CONS_RETURN_TYPE): Define.
    	(TC_PARSE_CONS_RETURN_NONE): Define.
    	(emit_expr_with_reloc): Declare.
    	(emit_expr_fix): Update prototype.
    	* gas/write.c (write_object_file): Update TC_CONS_FIX_NEW invocation.

diff --git a/gas/config/tc-alpha.h b/gas/config/tc-alpha.h
index 443eff4..98f81f5 100644
--- a/gas/config/tc-alpha.h
+++ b/gas/config/tc-alpha.h
@@ -71,7 +71,8 @@ extern valueT alpha_gp_value;
 
 #define tc_canonicalize_symbol_name evax_shorten_name
 
-#define TC_CONS_FIX_NEW(FRAG,OFF,LEN,EXP) \
+#define TC_CONS_FIX_NEW(FRAG,OFF,LEN,EXP,RELOC)	\
+      (void) RELOC,				\
       fix_new_exp (FRAG, OFF, (int)LEN, EXP, 0, \
 	LEN == 2 ? BFD_RELOC_16 \
 	: LEN == 4 ? BFD_RELOC_32 \
diff --git a/gas/config/tc-arc.c b/gas/config/tc-arc.c
index e8de1bb..5499d88 100644
--- a/gas/config/tc-arc.c
+++ b/gas/config/tc-arc.c
@@ -1160,7 +1160,7 @@ md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
    Values for the status register are specified with %st(label).
    `label' will be right shifted by 2.  */
 
-void
+bfd_reloc_code_real_type
 arc_parse_cons_expression (expressionS *exp,
 			   unsigned int nbytes ATTRIBUTE_UNUSED)
 {
@@ -1179,6 +1179,7 @@ arc_parse_cons_expression (expressionS *exp,
       arc_code_symbol (exp);
       input_line_pointer = p;
     }
+  return BFD_RELOC_NONE;
 }
 
 /* Record a fixup for a cons expression.  */
@@ -1187,7 +1188,8 @@ void
 arc_cons_fix_new (fragS *frag,
 		  int where,
 		  int nbytes,
-		  expressionS *exp)
+		  expressionS *exp,
+		  bfd_reloc_code_real_type r ATTRIBUTE_UNUSED)
 {
   if (nbytes == 4)
     {
diff --git a/gas/config/tc-arc.h b/gas/config/tc-arc.h
index 63cf826..a2789e6 100644
--- a/gas/config/tc-arc.h
+++ b/gas/config/tc-arc.h
@@ -54,13 +54,15 @@ extern const char * arc_target_format;
 
 /* The ARC needs to parse reloc specifiers in .word.  */
 
-extern void arc_parse_cons_expression (struct expressionS *, unsigned);
+extern bfd_reloc_code_real_type arc_parse_cons_expression (struct expressionS *,
+							   unsigned);
 #define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) \
   arc_parse_cons_expression (EXP, NBYTES)
 
-extern void arc_cons_fix_new (struct frag *, int, int, struct expressionS *);
-#define TC_CONS_FIX_NEW(FRAG, WHERE, NBYTES, EXP) \
-  arc_cons_fix_new (FRAG, WHERE, NBYTES, EXP)
+extern void arc_cons_fix_new (struct frag *, int, int, struct expressionS *,
+			      bfd_reloc_code_real_type);
+#define TC_CONS_FIX_NEW(FRAG, WHERE, NBYTES, EXP, RELOC)	\
+  arc_cons_fix_new (FRAG, WHERE, NBYTES, EXP, RELOC)
 
 #define DWARF2_LINE_MIN_INSN_LENGTH 4
 
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index 1795d37..9ccacbc 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -23159,9 +23159,9 @@ void
 cons_fix_new_arm (fragS *	frag,
 		  int		where,
 		  int		size,
-		  expressionS * exp)
+		  expressionS * exp,
+		  bfd_reloc_code_real_type reloc)
 {
-  bfd_reloc_code_real_type type;
   int pcrel = 0;
 
   /* Pick a reloc.
@@ -23169,17 +23169,17 @@ cons_fix_new_arm (fragS *	frag,
   switch (size)
     {
     case 1:
-      type = BFD_RELOC_8;
+      reloc = BFD_RELOC_8;
       break;
     case 2:
-      type = BFD_RELOC_16;
+      reloc = BFD_RELOC_16;
       break;
     case 4:
     default:
-      type = BFD_RELOC_32;
+      reloc = BFD_RELOC_32;
       break;
     case 8:
-      type = BFD_RELOC_64;
+      reloc = BFD_RELOC_64;
       break;
     }
 
@@ -23187,11 +23187,11 @@ cons_fix_new_arm (fragS *	frag,
   if (exp->X_op == O_secrel)
   {
     exp->X_op = O_symbol;
-    type = BFD_RELOC_32_SECREL;
+    reloc = BFD_RELOC_32_SECREL;
   }
 #endif
 
-  fix_new_exp (frag, where, (int) size, exp, pcrel, type);
+  fix_new_exp (frag, where, size, exp, pcrel, reloc);
 }
 
 #if defined (OBJ_COFF)
diff --git a/gas/config/tc-arm.h b/gas/config/tc-arm.h
index f88fa29..a7a0cd0 100644
--- a/gas/config/tc-arm.h
+++ b/gas/config/tc-arm.h
@@ -348,7 +348,8 @@ extern int arm_data_in_code (void);
 extern char * arm_canonicalize_symbol_name (char *);
 extern void arm_adjust_symtab (void);
 extern void armelf_frob_symbol (symbolS *, int *);
-extern void cons_fix_new_arm (fragS *, int, int, expressionS *);
+extern void cons_fix_new_arm (fragS *, int, int, expressionS *,
+			      bfd_reloc_code_real_type);
 extern void arm_init_frag (struct frag *, int);
 extern void arm_handle_align (struct frag *);
 extern bfd_boolean arm_fix_adjustable (struct fix *);
diff --git a/gas/config/tc-avr.c b/gas/config/tc-avr.c
index 5049d11..ce9708e 100644
--- a/gas/config/tc-avr.c
+++ b/gas/config/tc-avr.c
@@ -1521,22 +1521,7 @@ md_assemble (char *str)
   }
 }
 
-typedef struct
-{
-  /* Name of the expression modifier allowed with .byte, .word, etc.  */
-  const char *name;
-
-  /* Only allowed with n bytes of data.  */
-  int nbytes;
-
-  /* Associated RELOC.  */
-  bfd_reloc_code_real_type reloc;
-
-  /* Part of the error message.  */
-  const char *error;
-} exp_mod_data_t;
-
-static const exp_mod_data_t exp_mod_data[] =
+const exp_mod_data_t exp_mod_data[] =
 {
   /* Default, must be first.  */
   { "", 0, BFD_RELOC_16, "" },
@@ -1557,21 +1542,16 @@ static const exp_mod_data_t exp_mod_data[] =
   { NULL, 0, 0, NULL }
 };
 
-/* Data to pass between `avr_parse_cons_expression' and `avr_cons_fix_new'.  */
-static const exp_mod_data_t *pexp_mod_data = &exp_mod_data[0];
-
 /* Parse special CONS expression: pm (expression) or alternatively
    gs (expression).  These are used for addressing program memory.  Moreover,
    define lo8 (expression), hi8 (expression) and hlo8 (expression).  */
 
-void
+const exp_mod_data_t *
 avr_parse_cons_expression (expressionS *exp, int nbytes)
 {
   const exp_mod_data_t *pexp = &exp_mod_data[0];
   char *tmp;
 
-  pexp_mod_data = pexp;
-
   tmp = input_line_pointer = skip_space (input_line_pointer);
 
   /* The first entry of exp_mod_data[] contains an entry if no
@@ -1589,18 +1569,18 @@ avr_parse_cons_expression (expressionS *exp, int nbytes)
 	  if (*input_line_pointer == '(')
 	    {
 	      input_line_pointer = skip_space (input_line_pointer + 1);
-	      pexp_mod_data = pexp;
 	      expression (exp);
 
 	      if (*input_line_pointer == ')')
-		++input_line_pointer;
+		{
+		  ++input_line_pointer;
+		  return pexp;
+		}
 	      else
 		{
 		  as_bad (_("`)' required"));
-		  pexp_mod_data = &exp_mod_data[0];
+		  return &exp_mod_data[0];
 		}
-
-	      return;
 	    }
 
 	  input_line_pointer = tmp;
@@ -1610,13 +1590,15 @@ avr_parse_cons_expression (expressionS *exp, int nbytes)
     }
 
   expression (exp);
+  return &exp_mod_data[0];
 }
 
 void
 avr_cons_fix_new (fragS *frag,
 		  int where,
 		  int nbytes,
-		  expressionS *exp)
+		  expressionS *exp,
+		  const exp_mod_data_t *pexp_mod_data)
 {
   int bad = 0;
 
@@ -1646,8 +1628,6 @@ avr_cons_fix_new (fragS *frag,
 
   if (bad)
     as_bad (_("illegal %srelocation size: %d"), pexp_mod_data->error, nbytes);
-
-  pexp_mod_data = &exp_mod_data[0];
 }
 
 static bfd_boolean
diff --git a/gas/config/tc-avr.h b/gas/config/tc-avr.h
index caa058f..df75ac7 100644
--- a/gas/config/tc-avr.h
+++ b/gas/config/tc-avr.h
@@ -50,16 +50,36 @@
    will point to the start of the expression.  */
 #define md_operand(x)
 
+typedef struct
+{
+  /* Name of the expression modifier allowed with .byte, .word, etc.  */
+  const char *name;
+
+  /* Only allowed with n bytes of data.  */
+  int nbytes;
+
+  /* Associated RELOC.  */
+  bfd_reloc_code_real_type reloc;
+
+  /* Part of the error message.  */
+  const char *error;
+} exp_mod_data_t;
+
+extern const exp_mod_data_t exp_mod_data[];
+#define TC_PARSE_CONS_RETURN_TYPE const exp_mod_data_t *
+#define TC_PARSE_CONS_RETURN_NONE exp_mod_data
+
 /* You may define this macro to parse an expression used in a data
    allocation pseudo-op such as `.word'.  You can use this to
    recognize relocation directives that may appear in such directives.  */
 #define TC_PARSE_CONS_EXPRESSION(EXPR,N) avr_parse_cons_expression (EXPR, N)
-extern void avr_parse_cons_expression (expressionS *, int);
+extern const exp_mod_data_t *avr_parse_cons_expression (expressionS *, int);
 
 /* You may define this macro to generate a fixup for a data
    allocation pseudo-op.  */
-#define TC_CONS_FIX_NEW(FRAG,WHERE,N,EXP) avr_cons_fix_new (FRAG, WHERE, N, EXP)
-extern void avr_cons_fix_new (fragS *,int, int, expressionS *);
+#define TC_CONS_FIX_NEW avr_cons_fix_new
+extern void avr_cons_fix_new (fragS *,int, int, expressionS *,
+			      const exp_mod_data_t *);
 
 /* This should just call either `number_to_chars_bigendian' or
    `number_to_chars_littleendian', whichever is appropriate.  On
diff --git a/gas/config/tc-cr16.c b/gas/config/tc-cr16.c
index 4aed8a7..bcdf978 100644
--- a/gas/config/tc-cr16.c
+++ b/gas/config/tc-cr16.c
@@ -492,10 +492,9 @@ cr16_force_relocation (fixS *fix)
 /* Record a fixup for a cons expression.  */
 
 void
-cr16_cons_fix_new (fragS *frag, int offset, int len, expressionS *exp)
+cr16_cons_fix_new (fragS *frag, int offset, int len, expressionS *exp,
+		   bfd_reloc_code_real_type rtype)
 {
-  int rtype = BFD_RELOC_UNUSED;
-
   switch (len)
     {
     default: rtype = BFD_RELOC_NONE; break;
diff --git a/gas/config/tc-cr16.h b/gas/config/tc-cr16.h
index 6867191..9da8cb7 100644
--- a/gas/config/tc-cr16.h
+++ b/gas/config/tc-cr16.h
@@ -57,12 +57,13 @@ extern int cr16_force_relocation (struct fix *);
    of two bytes long.  */
 #define DWARF2_LINE_MIN_INSN_LENGTH 2
 
-extern void cr16_cons_fix_new (struct frag *, int, int, struct expressionS *);
+extern void cr16_cons_fix_new (struct frag *, int, int, struct expressionS *,
+			       bfd_reloc_code_real_type);
 /* This is called by emit_expr when creating a reloc for a cons.
    We could use the definition there, except that we want to handle 
    the CR16 reloc type specially, rather than the BFD_RELOC type.  */
-#define TC_CONS_FIX_NEW(FRAG, OFF, LEN, EXP) \
-  cr16_cons_fix_new (FRAG, OFF, LEN, EXP) 
+#define TC_CONS_FIX_NEW(FRAG, OFF, LEN, EXP, RELOC)	\
+  cr16_cons_fix_new (FRAG, OFF, LEN, EXP, RELOC)
 
 /* Give an error if a frag containing code is not aligned to a 2-byte 
    boundary.  */
diff --git a/gas/config/tc-crx.h b/gas/config/tc-crx.h
index 1777ab0..da6d710 100644
--- a/gas/config/tc-crx.h
+++ b/gas/config/tc-crx.h
@@ -60,7 +60,8 @@ extern int crx_force_relocation (struct fix *);
 /* This is called by emit_expr when creating a reloc for a cons.
    We could use the definition there, except that we want to handle 
    the CRX reloc type specially, rather than the BFD_RELOC type.  */
-#define TC_CONS_FIX_NEW(FRAG, OFF, LEN, EXP) \
+#define TC_CONS_FIX_NEW(FRAG, OFF, LEN, EXP, RELOC) \
+      (void) RELOC, \
       fix_new_exp (FRAG, OFF, (int) LEN, EXP, 0, \
 	LEN == 1 ? BFD_RELOC_CRX_NUM8 \
 	: LEN == 2 ? BFD_RELOC_CRX_NUM16 \
diff --git a/gas/config/tc-hppa.c b/gas/config/tc-hppa.c
index cc5ea9a..5ee7f72 100644
--- a/gas/config/tc-hppa.c
+++ b/gas/config/tc-hppa.c
@@ -606,9 +606,6 @@ static int within_procedure;
    seen in each subspace.  */
 static label_symbol_struct *label_symbols_rootp = NULL;
 
-/* Holds the last field selector.  */
-static int hppa_field_selector;
-
 /* Nonzero when strict matching is enabled.  Zero otherwise.
 
    Each opcode in the table has a flag which indicates whether or
@@ -1263,7 +1260,8 @@ fix_new_hppa (fragS *frag,
    hppa_field_selector is set by the parse_cons_expression_hppa.  */
 
 void
-cons_fix_new_hppa (fragS *frag, int where, int size, expressionS *exp)
+cons_fix_new_hppa (fragS *frag, int where, int size, expressionS *exp,
+		   int hppa_field_selector)
 {
   unsigned int rel_type;
 
@@ -1300,9 +1298,6 @@ cons_fix_new_hppa (fragS *frag, int where, int size, expressionS *exp)
   fix_new_hppa (frag, where, size,
 		(symbolS *) NULL, (offsetT) 0, exp, 0, rel_type,
 		hppa_field_selector, size * 8, 0, 0);
-
-  /* Reset field selector to its default state.  */
-  hppa_field_selector = 0;
 }
 
 /* Mark (via expr_end) the end of an expression (I think).  FIXME.  */
@@ -2517,11 +2512,12 @@ pa_chk_field_selector (char **str)
 /* Parse a .byte, .word, .long expression for the HPPA.  Called by
    cons via the TC_PARSE_CONS_EXPRESSION macro.  */
 
-void
+int
 parse_cons_expression_hppa (expressionS *exp)
 {
-  hppa_field_selector = pa_chk_field_selector (&input_line_pointer);
+  int hppa_field_selector = pa_chk_field_selector (&input_line_pointer);
   expression (exp);
+  return hppa_field_selector;
 }
 
 /* Evaluate an absolute expression EXP which may be modified by
diff --git a/gas/config/tc-hppa.h b/gas/config/tc-hppa.h
index a31ebf8..4277e10 100644
--- a/gas/config/tc-hppa.h
+++ b/gas/config/tc-hppa.h
@@ -90,8 +90,8 @@
 
 /* pa_define_label gets used outside of tc-hppa.c via tc_frob_label.  */
 extern void pa_define_label (symbolS *);
-extern void parse_cons_expression_hppa (expressionS *);
-extern void cons_fix_new_hppa (fragS *, int, int, expressionS *);
+extern int parse_cons_expression_hppa (expressionS *);
+extern void cons_fix_new_hppa (fragS *, int, int, expressionS *, int);
 extern int hppa_force_relocation (struct fix *);
 
 /* This gets called before writing the object file to make sure
@@ -112,6 +112,8 @@ extern const char	hppa_symbol_chars[];
 #define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) \
   parse_cons_expression_hppa (EXP)
 #define TC_CONS_FIX_NEW cons_fix_new_hppa
+#define TC_PARSE_CONS_RETURN_TYPE int
+#define TC_PARSE_CONS_RETURN_NONE e_fsel
 
 /* On the PA, an exclamation point can appear in an instruction.  It is
    used in FP comparison instructions and as an end of line marker.
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 38857cc..cb62cf5 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -7334,16 +7334,13 @@ output_imm (fragS *insn_start_frag, offsetT insn_start_off)
 
 /* x86_cons_fix_new is called via the expression parsing code when a
    reloc is needed.  We use this hook to get the correct .got reloc.  */
-static enum bfd_reloc_code_real got_reloc = NO_RELOC;
 static int cons_sign = -1;
 
 void
 x86_cons_fix_new (fragS *frag, unsigned int off, unsigned int len,
-		  expressionS *exp)
+		  expressionS *exp, bfd_reloc_code_real_type r)
 {
-  enum bfd_reloc_code_real r = reloc (len, 0, cons_sign, 0, got_reloc);
-
-  got_reloc = NO_RELOC;
+  r = reloc (len, 0, cons_sign, 0, r);
 
 #ifdef TE_PE
   if (exp->X_op == O_secrel)
@@ -7639,9 +7636,11 @@ lex_got (enum bfd_reloc_code_real *rel ATTRIBUTE_UNUSED,
 
 #endif /* TE_PE */
 
-void
+bfd_reloc_code_real_type
 x86_cons (expressionS *exp, int size)
 {
+  bfd_reloc_code_real_type got_reloc = NO_RELOC;
+
   intel_syntax = -intel_syntax;
 
   exp->X_md = 0;
@@ -7688,6 +7687,8 @@ x86_cons (expressionS *exp, int size)
 
   if (intel_syntax)
     i386_intel_simplify (exp);
+
+  return got_reloc;
 }
 
 static void
diff --git a/gas/config/tc-i386.h b/gas/config/tc-i386.h
index 17be268..8b5c7d7 100644
--- a/gas/config/tc-i386.h
+++ b/gas/config/tc-i386.h
@@ -132,11 +132,12 @@ extern const char *i386_comment_chars;
 #if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) && !defined (LEX_AT)
 #define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) x86_cons (EXP, NBYTES)
 #endif
-extern void x86_cons (expressionS *, int);
+extern bfd_reloc_code_real_type x86_cons (expressionS *, int);
 
-#define TC_CONS_FIX_NEW(FRAG,OFF,LEN,EXP) x86_cons_fix_new(FRAG, OFF, LEN, EXP)
+#define TC_CONS_FIX_NEW(FRAG, OFF, LEN, EXP, RELOC)	\
+  x86_cons_fix_new(FRAG, OFF, LEN, EXP, RELOC)
 extern void x86_cons_fix_new
-  (fragS *, unsigned int, unsigned int, expressionS *);
+(fragS *, unsigned int, unsigned int, expressionS *, bfd_reloc_code_real_type);
 
 #define TC_ADDRESS_BYTES x86_address_bytes
 extern int x86_address_bytes (void);
diff --git a/gas/config/tc-ia64.c b/gas/config/tc-ia64.c
index e6da535..38b6b67 100644
--- a/gas/config/tc-ia64.c
+++ b/gas/config/tc-ia64.c
@@ -4466,14 +4466,15 @@ dot_endp (int dummy ATTRIBUTE_UNUSED)
 					  symbol_get_frag (unwind.proc_pending.sym));
       else
 	e.X_add_symbol = unwind.proc_pending.sym;
-      ia64_cons_fix_new (frag_now, where, bytes_per_address, &e);
+      ia64_cons_fix_new (frag_now, where, bytes_per_address, &e,
+			 BFD_RELOC_NONE);
 
       e.X_op = O_pseudo_fixup;
       e.X_op_symbol = pseudo_func[FUNC_SEG_RELATIVE].u.sym;
       e.X_add_number = 0;
       e.X_add_symbol = proc_end;
       ia64_cons_fix_new (frag_now, where + bytes_per_address,
-			 bytes_per_address, &e);
+			 bytes_per_address, &e, BFD_RELOC_NONE);
 
       if (unwind.info)
 	{
@@ -4482,7 +4483,7 @@ dot_endp (int dummy ATTRIBUTE_UNUSED)
 	  e.X_add_number = 0;
 	  e.X_add_symbol = unwind.info;
 	  ia64_cons_fix_new (frag_now, where + (bytes_per_address * 2),
-			     bytes_per_address, &e);
+			     bytes_per_address, &e, BFD_RELOC_NONE);
 	}
     }
   subseg_set (saved_seg, saved_subseg);
@@ -11056,9 +11057,9 @@ ia64_dwarf2_emit_offset (symbolS *symbol, unsigned int size)
    fixup.  We pick the right reloc code depending on the byteorder
    currently in effect.  */
 void
-ia64_cons_fix_new (fragS *f, int where, int nbytes, expressionS *exp)
+ia64_cons_fix_new (fragS *f, int where, int nbytes, expressionS *exp,
+		   bfd_reloc_code_real_type code)
 {
-  bfd_reloc_code_real_type code;
   fixS *fix;
 
   switch (nbytes)
diff --git a/gas/config/tc-ia64.h b/gas/config/tc-ia64.h
index c6cc29f..6884c59 100644
--- a/gas/config/tc-ia64.h
+++ b/gas/config/tc-ia64.h
@@ -106,7 +106,8 @@ extern void ia64_cons_align (int);
 extern void ia64_flush_insns (void);
 extern int ia64_fix_adjustable (struct fix *);
 extern int ia64_force_relocation (struct fix *);
-extern void ia64_cons_fix_new (fragS *, int, int, expressionS *);
+extern void ia64_cons_fix_new (fragS *, int, int, expressionS *,
+			       bfd_reloc_code_real_type);
 extern void ia64_validate_fix (struct fix *);
 extern char * ia64_canonicalize_symbol_name (char *);
 extern bfd_vma ia64_elf_section_letter (int, char **);
@@ -148,7 +149,7 @@ extern void ia64_convert_frag (fragS *);
 #define md_elf_section_flags		ia64_elf_section_flags
 #define TC_FIX_TYPE			struct ia64_fix
 #define TC_INIT_FIX_DATA(f)		{ f->tc_fix_data.opnd = 0; }
-#define TC_CONS_FIX_NEW(f,o,l,e)	ia64_cons_fix_new (f, o, l, e)
+#define TC_CONS_FIX_NEW(f,o,l,e,r)	ia64_cons_fix_new (f, o, l, e, r)
 #define TC_VALIDATE_FIX(fix,seg,skip)	ia64_validate_fix (fix)
 #define MD_PCREL_FROM_SECTION(fix,sec)	ia64_pcrel_from_section (fix, sec)
 #define md_section_align(seg,size)	(size)
diff --git a/gas/config/tc-m32c.c b/gas/config/tc-m32c.c
index 664b167..8e24edb 100644
--- a/gas/config/tc-m32c.c
+++ b/gas/config/tc-m32c.c
@@ -1019,10 +1019,9 @@ void
 m32c_cons_fix_new (fragS *	frag,
 		   int		where,
 		   int		size,
-		   expressionS *exp)
+		   expressionS *exp,
+		   bfd_reloc_code_real_type type)
 {
-  bfd_reloc_code_real_type type;
-
   switch (size)
     {
     case 1:
diff --git a/gas/config/tc-m32c.h b/gas/config/tc-m32c.h
index 0534603..3af0092 100644
--- a/gas/config/tc-m32c.h
+++ b/gas/config/tc-m32c.h
@@ -57,9 +57,10 @@ extern bfd_boolean m32c_fix_adjustable (struct fix *);
 #define TC_FORCE_RELOCATION(fix) m32c_force_relocation (fix)
 extern int m32c_force_relocation (struct fix *);
 
-#define TC_CONS_FIX_NEW(FRAG, WHERE, NBYTES, EXP) \
-  m32c_cons_fix_new (FRAG, WHERE, NBYTES, EXP)
-extern void m32c_cons_fix_new (fragS *, int, int, expressionS *);
+#define TC_CONS_FIX_NEW(FRAG, WHERE, NBYTES, EXP, RELOC)	\
+  m32c_cons_fix_new (FRAG, WHERE, NBYTES, EXP, RELOC)
+extern void m32c_cons_fix_new (fragS *, int, int, expressionS *,
+			       bfd_reloc_code_real_type);
 
 extern const struct relax_type md_relax_table[];
 #define TC_GENERIC_RELAX_TABLE md_relax_table
diff --git a/gas/config/tc-microblaze.c b/gas/config/tc-microblaze.c
index 13f9f84..cf4ee44 100644
--- a/gas/config/tc-microblaze.c
+++ b/gas/config/tc-microblaze.c
@@ -802,7 +802,7 @@ check_got (int * got_type, int * got_len)
   return tmpbuf;
 }
 
-extern void
+extern bfd_reloc_code_real_type
 parse_cons_expression_microblaze (expressionS *exp, int size)
 {
   if (size == 4)
@@ -828,6 +828,7 @@ parse_cons_expression_microblaze (expressionS *exp, int size)
     }
   else
     expression (exp);
+  return BFD_RELOC_NONE;
 }
 
 /* This is the guts of the machine-dependent assembler.  STR points to a
@@ -2485,11 +2486,9 @@ void
 cons_fix_new_microblaze (fragS * frag,
 			 int where,
 			 int size,
-			 expressionS *exp)
+			 expressionS *exp,
+			 bfd_reloc_code_real_type r)
 {
-
-  bfd_reloc_code_real_type r;
-
   if ((exp->X_op == O_subtract) && (exp->X_add_symbol) &&
       (exp->X_op_symbol) && (now_seg != absolute_section) && (size == 4)
       && (!S_IS_LOCAL (exp->X_op_symbol)))
diff --git a/gas/config/tc-microblaze.h b/gas/config/tc-microblaze.h
index 91a9a21..d44f2fa 100644
--- a/gas/config/tc-microblaze.h
+++ b/gas/config/tc-microblaze.h
@@ -36,8 +36,10 @@
    relocs for such expressions as -relax in linker can change the value
    of such expressions */
 #define TC_CONS_FIX_NEW cons_fix_new_microblaze
-#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_cons_expression_microblaze (EXP, NBYTES)
-extern void parse_cons_expression_microblaze (expressionS *, int);
+#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) \
+  parse_cons_expression_microblaze (EXP, NBYTES)
+extern bfd_reloc_code_real_type parse_cons_expression_microblaze
+  (expressionS *, int);
 
 #define TC_FORCE_RELOCATION_SECTION(FIXP,SEG) 1
 #define UNDEFINED_DIFFERENCE_OK 1
@@ -108,7 +110,9 @@ extern void      md_number_to_chars            (char *, valueT, int);
 extern valueT    md_section_align              (segT, valueT);
 extern long      md_pcrel_from_section         (fixS *, segT);
 extern arelent * tc_gen_reloc                  (asection *, fixS *);
-extern void 	 cons_fix_new_microblaze       (fragS *, int, int, expressionS *);
+extern void 	 cons_fix_new_microblaze       (fragS *, int, int,
+						expressionS *,
+						bfd_reloc_code_real_type);
 extern void 	 md_apply_fix3 		       (fixS *, valueT *, segT);
 
 #define EXTERN_FORCE_RELOC -1
diff --git a/gas/config/tc-mn10300.c b/gas/config/tc-mn10300.c
index 2fce19c..3d159b1 100644
--- a/gas/config/tc-mn10300.c
+++ b/gas/config/tc-mn10300.c
@@ -1013,7 +1013,8 @@ mn10300_check_fixup (struct mn10300_fixup *fixup)
 }
 
 void
-mn10300_cons_fix_new (fragS *frag, int off, int size, expressionS *exp)
+mn10300_cons_fix_new (fragS *frag, int off, int size, expressionS *exp,
+		      bfd_reloc_code_real_type r ATTRIBUTE_UNUSED)
 {
   struct mn10300_fixup fixup;
 
diff --git a/gas/config/tc-mn10300.h b/gas/config/tc-mn10300.h
index 4a89f74..d502430 100644
--- a/gas/config/tc-mn10300.h
+++ b/gas/config/tc-mn10300.h
@@ -39,9 +39,10 @@ extern bfd_boolean mn10300_force_relocation (struct fix *);
     mn10300_parse_name ((NAME), (EXPRP), (MODE), (NEXTCHARP))
 int mn10300_parse_name (char const *, expressionS *, enum expr_mode, char *);
 
-#define TC_CONS_FIX_NEW(FRAG, OFF, LEN, EXP) \
-     mn10300_cons_fix_new ((FRAG), (OFF), (LEN), (EXP))
-void mn10300_cons_fix_new (fragS *, int, int, expressionS *);
+#define TC_CONS_FIX_NEW(FRAG, OFF, LEN, EXP, RELOC)	\
+  mn10300_cons_fix_new ((FRAG), (OFF), (LEN), (EXP), (RELOC))
+void mn10300_cons_fix_new (fragS *, int, int, expressionS *,
+			   bfd_reloc_code_real_type);
 
 /* This is used to construct expressions out of @GOTOFF, @PLT and @GOT
    symbols.  The relocation type is stored in X_md.  */
diff --git a/gas/config/tc-nios2.c b/gas/config/tc-nios2.c
index 9cb290d..754947c 100644
--- a/gas/config/tc-nios2.c
+++ b/gas/config/tc-nios2.c
@@ -3003,12 +3003,10 @@ nios2_elf_section_flags (flagword flags, int attr, int type ATTRIBUTE_UNUSED)
 }
 
 /* Implement TC_PARSE_CONS_EXPRESSION to handle %tls_ldo(...) */
-static int nios2_tls_ldo_reloc;
-
-void
+bfd_reloc_code_real_type
 nios2_cons (expressionS *exp, int size)
 {
-  nios2_tls_ldo_reloc = 0;
+  bfd_reloc_code_real_type nios2_tls_ldo_reloc = BFD_RELOC_NONE;
 
   SKIP_WHITESPACE ();
   if (input_line_pointer[0] == '%')
@@ -3021,10 +3019,10 @@ nios2_cons (expressionS *exp, int size)
 	  else
 	    {
 	      input_line_pointer += 8;
-	      nios2_tls_ldo_reloc = 1;
+	      nios2_tls_ldo_reloc = BFD_RELOC_NIOS2_TLS_DTPREL;
 	    }
 	}
-      if (nios2_tls_ldo_reloc)
+      if (nios2_tls_ldo_reloc != BFD_RELOC_NONE)
 	{
 	  SKIP_WHITESPACE ();
 	  if (input_line_pointer[0] != '(')
@@ -3066,26 +3064,9 @@ nios2_cons (expressionS *exp, int size)
 	    }
 	}
     }
-  if (!nios2_tls_ldo_reloc)
+  if (nios2_tls_ldo_reloc == BFD_RELOC_NONE)
     expression (exp);
-}
-
-/* Implement TC_CONS_FIX_NEW.  */
-void
-nios2_cons_fix_new (fragS *frag, int where, unsigned int nbytes,
-		    expressionS *exp)
-{
-  bfd_reloc_code_real_type r;
-
-  r = (nbytes == 1 ? BFD_RELOC_8
-       : (nbytes == 2 ? BFD_RELOC_16
-	  : (nbytes == 4 ? BFD_RELOC_32 : BFD_RELOC_64)));
-
-  if (nios2_tls_ldo_reloc)
-    r = BFD_RELOC_NIOS2_TLS_DTPREL;
-
-  fix_new_exp (frag, where, (int) nbytes, exp, 0, r);
-  nios2_tls_ldo_reloc = 0;
+  return nios2_tls_ldo_reloc;
 }
 
 /* Implement HANDLE_ALIGN.  */
diff --git a/gas/config/tc-nios2.h b/gas/config/tc-nios2.h
index 4332649..82bb624 100644
--- a/gas/config/tc-nios2.h
+++ b/gas/config/tc-nios2.h
@@ -107,11 +107,7 @@ extern flagword nios2_elf_section_flags (flagword, int, int);
 #define CFI_DIFF_EXPR_OK 0
 
 #define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) nios2_cons (EXP, NBYTES)
-extern void nios2_cons (expressionS *exp, int size);
-
-#define TC_CONS_FIX_NEW nios2_cons_fix_new
-extern void nios2_cons_fix_new (struct frag *frag, int where,
-				unsigned int nbytes, struct expressionS *exp);
+extern bfd_reloc_code_real_type nios2_cons (expressionS *exp, int size);
 
 /* We want .cfi_* pseudo-ops for generating unwind info.  */
 #define TARGET_USE_CFIPOP 1
diff --git a/gas/config/tc-ns32k.c b/gas/config/tc-ns32k.c
index d66a062..1c97d43 100644
--- a/gas/config/tc-ns32k.c
+++ b/gas/config/tc-ns32k.c
@@ -2181,7 +2181,8 @@ void
 cons_fix_new_ns32k (fragS *frag,	/* Which frag? */
 		    int where,		/* Where in that frag? */
 		    int size,		/* 1, 2  or 4 usually.  */
-		    expressionS *exp)	/* Expression.  */
+		    expressionS *exp,	/* Expression.  */
+		    bfd_reloc_code_real_type r ATTRIBUTE_UNUSED)
 {
   fix_new_ns32k_exp (frag, where, size, exp,
 		     0, 2, 0, 0, 0, 0);
diff --git a/gas/config/tc-ns32k.h b/gas/config/tc-ns32k.h
index 7b093ec..02d7196 100644
--- a/gas/config/tc-ns32k.h
+++ b/gas/config/tc-ns32k.h
@@ -54,7 +54,8 @@ extern int md_pcrel_adjust (fragS *);
 #define ARG_LEN 50
 
 #define TC_CONS_FIX_NEW cons_fix_new_ns32k
-extern void cons_fix_new_ns32k (fragS *, int, int, expressionS *);
+extern void cons_fix_new_ns32k (fragS *, int, int, expressionS *,
+				bfd_reloc_code_real_type);
 
 /* The NS32x32 has a non 0 nop instruction which should be used in aligns.  */
 #define NOP_OPCODE 0xa2
diff --git a/gas/config/tc-pj.c b/gas/config/tc-pj.c
index 408dde6..dba4cbc 100644
--- a/gas/config/tc-pj.c
+++ b/gas/config/tc-pj.c
@@ -96,7 +96,8 @@ parse_exp_save_ilp (char *s, expressionS *op)
    we want to handle magic pending reloc expressions specially.  */
 
 void
-pj_cons_fix_new_pj (fragS *frag, int where, int nbytes, expressionS *exp)
+pj_cons_fix_new_pj (fragS *frag, int where, int nbytes, expressionS *exp,
+		    bfd_reloc_code_real_type r ATTRIBUTE_UNUSED)
 {
   static int rv[5][2] =
   { { 0, 0 },
diff --git a/gas/config/tc-pj.h b/gas/config/tc-pj.h
index 522db5b..eda1792 100644
--- a/gas/config/tc-pj.h
+++ b/gas/config/tc-pj.h
@@ -31,7 +31,8 @@
    ? "Pico Java GAS Big Endian"           				\
    : "Pico Java GAS Little Endian")
 
-void pj_cons_fix_new_pj (struct frag *, int, int, expressionS *);
+void pj_cons_fix_new_pj (struct frag *, int, int, expressionS *,
+			 bfd_reloc_code_real_type);
 arelent *tc_gen_reloc (asection *, struct fix *);
 
 #define md_section_align(SEGMENT, SIZE)     (SIZE)
@@ -45,8 +46,8 @@ arelent *tc_gen_reloc (asection *, struct fix *);
 #define md_pcrel_from(FIX) 						\
 	((FIX)->fx_where + (FIX)->fx_frag->fr_address - 1)
 
-#define TC_CONS_FIX_NEW(FRAG, WHERE, NBYTES, EXP) \
-	pj_cons_fix_new_pj (FRAG, WHERE, NBYTES, EXP)
+#define TC_CONS_FIX_NEW(FRAG, WHERE, NBYTES, EXP, RELOC)	\
+	pj_cons_fix_new_pj (FRAG, WHERE, NBYTES, EXP, RELOC)
 
 /* No shared lib support, so we don't need to ensure externally
    visible symbols can be overridden.  */
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index 9f24f3f..5cfe1db 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -129,7 +129,6 @@ static void ppc_vbyte (int);
 #endif
 
 #ifdef OBJ_ELF
-static void ppc_elf_cons (int);
 static void ppc_elf_rdata (int);
 static void ppc_elf_lcomm (int);
 static void ppc_elf_localentry (int);
@@ -257,11 +256,7 @@ const pseudo_typeS md_pseudo_table[] =
 #endif
 
 #ifdef OBJ_ELF
-  { "llong",	ppc_elf_cons,	8 },
-  { "quad",	ppc_elf_cons,	8 },
-  { "long",	ppc_elf_cons,	4 },
-  { "word",	ppc_elf_cons,	2 },
-  { "short",	ppc_elf_cons,	2 },
+  { "llong",	cons,		8 },
   { "rdata",	ppc_elf_rdata,	0 },
   { "rodata",	ppc_elf_rdata,	0 },
   { "lcomm",	ppc_elf_lcomm,	0 },
@@ -1957,11 +1952,11 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p)
     MAP64 ("tprel@highera",	BFD_RELOC_PPC64_TPREL16_HIGHERA),
     MAP64 ("tprel@highest",	BFD_RELOC_PPC64_TPREL16_HIGHEST),
     MAP64 ("tprel@highesta",	BFD_RELOC_PPC64_TPREL16_HIGHESTA),
-    { (char *) 0, 0, 0, 0,	BFD_RELOC_UNUSED }
+    { (char *) 0, 0, 0, 0,	BFD_RELOC_NONE }
   };
 
   if (*str++ != '@')
-    return BFD_RELOC_UNUSED;
+    return BFD_RELOC_NONE;
 
   for (ch = *str, str2 = ident;
        (str2 < ident + sizeof (ident) - 1
@@ -2047,63 +2042,18 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p)
 	return (bfd_reloc_code_real_type) reloc;
       }
 
-  return BFD_RELOC_UNUSED;
+  return BFD_RELOC_NONE;
 }
 
-/* Like normal .long/.short/.word, except support @got, etc.
-   Clobbers input_line_pointer, checks end-of-line.  */
-static void
-ppc_elf_cons (int nbytes /* 1=.byte, 2=.word, 4=.long, 8=.llong */)
-{
-  expressionS exp;
-  bfd_reloc_code_real_type reloc;
-
-  if (is_it_end_of_statement ())
-    {
-      demand_empty_rest_of_line ();
-      return;
-    }
-
-  do
-    {
-      expression (&exp);
-      if (*input_line_pointer == '@'
-	  && (reloc = ppc_elf_suffix (&input_line_pointer,
-				      &exp)) != BFD_RELOC_UNUSED)
-	{
-	  reloc_howto_type *reloc_howto;
-	  int size;
+/* Support @got, etc. on constants emitted via .short, .int etc.  */
 
-	  reloc_howto = bfd_reloc_type_lookup (stdoutput, reloc);
-	  size = bfd_get_reloc_size (reloc_howto);
-
-	  if (size > nbytes)
-	    {
-	      as_bad (_("%s relocations do not fit in %d bytes\n"),
-		      reloc_howto->name, nbytes);
-	    }
-	  else
-	    {
-	      char *p;
-	      int offset;
-
-	      p = frag_more (nbytes);
-	      memset (p, 0, nbytes);
-	      offset = 0;
-	      if (target_big_endian)
-		offset = nbytes - size;
-	      fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size,
-			   &exp, 0, reloc);
-	    }
-	}
-      else
-	emit_expr (&exp, (unsigned int) nbytes);
-    }
-  while (*input_line_pointer++ == ',');
-
-  /* Put terminator back into stream.  */
-  input_line_pointer--;
-  demand_empty_rest_of_line ();
+bfd_reloc_code_real_type
+ppc_elf_parse_cons (expressionS *exp, unsigned int nbytes)
+{
+  expression (exp);
+  if (nbytes >= 2 && *input_line_pointer == '@')
+    return ppc_elf_suffix (&input_line_pointer, exp);
+  return BFD_RELOC_NONE;
 }
 
 /* Solaris pseduo op to change to the .rodata section.  */
@@ -2338,8 +2288,7 @@ ppc_elf_validate_fix (fixS *fixp, segT seg)
       return;
 
     case SHLIB_MRELOCATABLE:
-      if (fixp->fx_r_type <= BFD_RELOC_UNUSED
-	  && fixp->fx_r_type != BFD_RELOC_16_GOTOFF
+      if (fixp->fx_r_type != BFD_RELOC_16_GOTOFF
 	  && fixp->fx_r_type != BFD_RELOC_HI16_GOTOFF
 	  && fixp->fx_r_type != BFD_RELOC_LO16_GOTOFF
 	  && fixp->fx_r_type != BFD_RELOC_HI16_S_GOTOFF
@@ -2839,12 +2788,12 @@ md_assemble (char *str)
 	      /* FIXME: these next two specifically specify 32/64 bit
 		 toc entries.  We don't support them today.  Is this
 		 the right way to say that?  */
-	      toc_reloc = BFD_RELOC_UNUSED;
+	      toc_reloc = BFD_RELOC_NONE;
 	      as_bad (_("unimplemented toc32 expression modifier"));
 	      break;
 	    case must_be_64:
 	      /* FIXME: see above.  */
-	      toc_reloc = BFD_RELOC_UNUSED;
+	      toc_reloc = BFD_RELOC_NONE;
 	      as_bad (_("unimplemented toc64 expression modifier"));
 	      break;
 	    default:
@@ -2914,7 +2863,7 @@ md_assemble (char *str)
 	  bfd_reloc_code_real_type reloc;
 	  char *orig_str = str;
 
-	  if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
+	  if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_NONE)
 	    switch (reloc)
 	      {
 	      default:
@@ -3000,7 +2949,7 @@ md_assemble (char *str)
 	}
       else
 	{
-	  bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
+	  bfd_reloc_code_real_type reloc = BFD_RELOC_NONE;
 #ifdef OBJ_ELF
 	  if (ex.X_op == O_symbol && str[0] == '(')
 	    {
@@ -3017,7 +2966,7 @@ md_assemble (char *str)
 		  expression (&tls_exp);
 		  if (tls_exp.X_op == O_symbol)
 		    {
-		      reloc = BFD_RELOC_UNUSED;
+		      reloc = BFD_RELOC_NONE;
 		      if (strncasecmp (input_line_pointer, "@tlsgd)", 7) == 0)
 			{
 			  reloc = BFD_RELOC_PPC_TLSGD;
@@ -3028,7 +2977,7 @@ md_assemble (char *str)
 			  reloc = BFD_RELOC_PPC_TLSLD;
 			  input_line_pointer += 7;
 			}
-		      if (reloc != BFD_RELOC_UNUSED)
+		      if (reloc != BFD_RELOC_NONE)
 			{
 			  SKIP_WHITESPACE ();
 			  str = input_line_pointer;
@@ -3045,7 +2994,7 @@ md_assemble (char *str)
 		}
 	    }
 
-	  if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
+	  if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_NONE)
 	    {
 	      /* Some TLS tweaks.  */
 	      switch (reloc)
@@ -3144,7 +3093,7 @@ md_assemble (char *str)
 	    }
 #endif /* OBJ_ELF */
 
-	  if (reloc != BFD_RELOC_UNUSED)
+	  if (reloc != BFD_RELOC_NONE)
 	    ;
 	  /* Determine a BFD reloc value based on the operand information.
 	     We are only prepared to turn a few of the operands into
@@ -3405,7 +3354,7 @@ md_assemble (char *str)
   for (i = 0; i < fc; i++)
     {
       fixS *fixP;
-      if (fixups[i].reloc != BFD_RELOC_UNUSED)
+      if (fixups[i].reloc != BFD_RELOC_NONE)
 	{
 	  reloc_howto_type *reloc_howto;
 	  int size;
@@ -3438,7 +3387,7 @@ md_assemble (char *str)
 			      insn_length,
 			      &fixups[i].exp,
 			      (operand->flags & PPC_OPERAND_RELATIVE) != 0,
-			      BFD_RELOC_UNUSED);
+			      BFD_RELOC_NONE);
 	}
       fixP->fx_pcrel_adjust = fixups[i].opindex;
     }
@@ -6462,7 +6411,7 @@ ppc_handle_align (struct frag *fragP)
    fixups we generated by the calls to fix_new_exp, above.  */
 
 void
-md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
+md_apply_fix (fixS *fixP, valueT *valP, segT seg)
 {
   valueT value = * valP;
   offsetT fieldval;
@@ -6810,7 +6759,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 	return;
 
       gas_assert (fixP->fx_addsy != NULL);
-      if (fixP->fx_r_type == BFD_RELOC_UNUSED)
+      if (fixP->fx_r_type == BFD_RELOC_NONE)
 	{
 	  char *sfile;
 	  unsigned int sline;
diff --git a/gas/config/tc-ppc.h b/gas/config/tc-ppc.h
index 09eb889..a5e69ca 100644
--- a/gas/config/tc-ppc.h
+++ b/gas/config/tc-ppc.h
@@ -231,6 +231,10 @@ extern int ppc_fix_adjustable (struct fix *);
 /* Values passed to md_apply_fix don't include symbol values.  */
 #define MD_APPLY_SYM_VALUE(FIX) 0
 
+#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) \
+  ppc_elf_parse_cons (EXP, NBYTES)
+extern bfd_reloc_code_real_type ppc_elf_parse_cons (expressionS *,
+						    unsigned int);
 #define tc_frob_file_before_adjust ppc_frob_file_before_adjust
 extern void ppc_frob_file_before_adjust (void);
 
diff --git a/gas/config/tc-rx.c b/gas/config/tc-rx.c
index 87b1e09..c4842f9 100644
--- a/gas/config/tc-rx.c
+++ b/gas/config/tc-rx.c
@@ -2170,10 +2170,9 @@ void
 rx_cons_fix_new (fragS *	frag,
 		 int		where,
 		 int		size,
-		 expressionS *  exp)
+		 expressionS *  exp,
+		 bfd_reloc_code_real_type type)
 {
-  bfd_reloc_code_real_type type;
-
   switch (size)
     {
     case 1:
diff --git a/gas/config/tc-rx.h b/gas/config/tc-rx.h
index 937af25..b82812d 100644
--- a/gas/config/tc-rx.h
+++ b/gas/config/tc-rx.h
@@ -68,9 +68,10 @@ extern long md_pcrel_from_section (struct fix *, segT);
   rx_validate_fix_sub (FIX)
 extern int rx_validate_fix_sub (struct fix *);
 
-#define TC_CONS_FIX_NEW(FRAG, WHERE, NBYTES, EXP) \
-  rx_cons_fix_new (FRAG, WHERE, NBYTES, EXP)
-extern void rx_cons_fix_new (fragS *, int, int, expressionS *);
+#define TC_CONS_FIX_NEW(FRAG, WHERE, NBYTES, EXP, RELOC)	\
+  rx_cons_fix_new (FRAG, WHERE, NBYTES, EXP, RELOC)
+extern void rx_cons_fix_new (fragS *, int, int, expressionS *,
+			     bfd_reloc_code_real_type);
 
 #define tc_fix_adjustable(x) 0
 
diff --git a/gas/config/tc-sh.c b/gas/config/tc-sh.c
index da7d84a..a0cd212 100644
--- a/gas/config/tc-sh.c
+++ b/gas/config/tc-sh.c
@@ -765,9 +765,10 @@ sh_check_fixup (expressionS *main_exp, bfd_reloc_code_real_type *r_type_p)
 /* Add expression EXP of SIZE bytes to offset OFF of fragment FRAG.  */
 
 void
-sh_cons_fix_new (fragS *frag, int off, int size, expressionS *exp)
+sh_cons_fix_new (fragS *frag, int off, int size, expressionS *exp,
+		 bfd_reloc_code_real_type r_type)
 {
-  bfd_reloc_code_real_type r_type = BFD_RELOC_UNUSED;
+  r_type = BFD_RELOC_UNUSED;
 
   if (sh_check_fixup (exp, &r_type))
     as_bad (_("Invalid PIC expression."));
diff --git a/gas/config/tc-sh.h b/gas/config/tc-sh.h
index 40d8056..97b6b6d 100644
--- a/gas/config/tc-sh.h
+++ b/gas/config/tc-sh.h
@@ -232,9 +232,10 @@ extern bfd_boolean sh_fix_adjustable (struct fix *);
 int sh_parse_name (char const *, expressionS *,
 		   enum expr_mode, char *);
 
-#define TC_CONS_FIX_NEW(FRAG, OFF, LEN, EXP) \
-  sh_cons_fix_new ((FRAG), (OFF), (LEN), (EXP))
-void sh_cons_fix_new (fragS *, int, int, expressionS *);
+#define TC_CONS_FIX_NEW(FRAG, OFF, LEN, EXP, RELOC)	\
+  sh_cons_fix_new ((FRAG), (OFF), (LEN), (EXP), (RELOC))
+void sh_cons_fix_new (fragS *, int, int, expressionS *,
+		      bfd_reloc_code_real_type);
 
 /* This is used to construct expressions out of @GOTOFF, @PLT and @GOT
    symbols.  The relocation type is stored in X_md.  */
diff --git a/gas/config/tc-sparc.c b/gas/config/tc-sparc.c
index fdc2f03..5b0baad 100644
--- a/gas/config/tc-sparc.c
+++ b/gas/config/tc-sparc.c
@@ -4268,11 +4268,6 @@ s_proc (int ignore ATTRIBUTE_UNUSED)
 
 static int sparc_no_align_cons = 0;
 
-/* This static variable is set by sparc_cons to emit requested types
-   of relocations in cons_fix_new_sparc.  */
-
-static const char *sparc_cons_special_reloc;
-
 /* This handles the unaligned space allocation pseudo-ops, such as
    .uaword.  .uaword is just like .word, but the value does not need
    to be aligned.  */
@@ -4540,13 +4535,13 @@ sparc_elf_final_processing (void)
     elf_elfheader (stdoutput)->e_flags |= EF_SPARC_SUN_US1|EF_SPARC_SUN_US3;
 }
 
-void
+const char *
 sparc_cons (expressionS *exp, int size)
 {
   char *save;
+  const char *sparc_cons_special_reloc = NULL;
 
   SKIP_WHITESPACE ();
-  sparc_cons_special_reloc = NULL;
   save = input_line_pointer;
   if (input_line_pointer[0] == '%'
       && input_line_pointer[1] == 'r'
@@ -4673,6 +4668,7 @@ sparc_cons (expressionS *exp, int size)
     }
   if (sparc_cons_special_reloc == NULL)
     expression (exp);
+  return sparc_cons_special_reloc;
 }
 
 #endif
@@ -4685,7 +4681,8 @@ void
 cons_fix_new_sparc (fragS *frag,
 		    int where,
 		    unsigned int nbytes,
-		    expressionS *exp)
+		    expressionS *exp,
+		    const char *sparc_cons_special_reloc)
 {
   bfd_reloc_code_real_type r;
 
@@ -4734,7 +4731,6 @@ cons_fix_new_sparc (fragS *frag,
    }
 
   fix_new_exp (frag, where, (int) nbytes, exp, 0, r);
-  sparc_cons_special_reloc = NULL;
 }
 
 void
@@ -4788,9 +4784,7 @@ sparc_regname_to_dw2regnum (char *regname)
 void
 sparc_cfi_emit_pcrel_expr (expressionS *exp, unsigned int nbytes)
 {
-  sparc_cons_special_reloc = "disp";
   sparc_no_align_cons = 1;
-  emit_expr (exp, nbytes);
+  emit_expr_with_reloc (exp, nbytes, "disp");
   sparc_no_align_cons = 0;
-  sparc_cons_special_reloc = NULL;
 }
diff --git a/gas/config/tc-sparc.h b/gas/config/tc-sparc.h
index 10d4522..ef76c0b 100644
--- a/gas/config/tc-sparc.h
+++ b/gas/config/tc-sparc.h
@@ -155,14 +155,17 @@ extern void sparc_md_end (void);
 
 #endif
 
+#define TC_PARSE_CONS_RETURN_TYPE const char *
+#define TC_PARSE_CONS_RETURN_NONE NULL
+
 #ifdef OBJ_ELF
 #define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) sparc_cons (EXP, NBYTES)
-extern void sparc_cons (expressionS *, int);
+extern const char *sparc_cons (expressionS *, int);
 #endif
 
 #define TC_CONS_FIX_NEW cons_fix_new_sparc
 extern void cons_fix_new_sparc
-  (struct frag *, int, unsigned int, struct expressionS *);
+(struct frag *, int, unsigned int, struct expressionS *, const char *);
 
 #define TC_FIX_TYPE	valueT
 
diff --git a/gas/config/tc-tic54x.c b/gas/config/tc-tic54x.c
index 27a2111..bba743c 100644
--- a/gas/config/tc-tic54x.c
+++ b/gas/config/tc-tic54x.c
@@ -5121,10 +5121,9 @@ tc_gen_reloc (asection *section, fixS *fixP)
 /* Handle cons expressions.  */
 
 void
-tic54x_cons_fix_new (fragS *frag, int where, int octets, expressionS *expn)
+tic54x_cons_fix_new (fragS *frag, int where, int octets, expressionS *expn,
+		     bfd_reloc_code_real_type r)
 {
-  bfd_reloc_code_real_type r;
-
   switch (octets)
     {
     default:
diff --git a/gas/config/tc-tic54x.h b/gas/config/tc-tic54x.h
index 84f343f..3fe8be8 100644
--- a/gas/config/tc-tic54x.h
+++ b/gas/config/tc-tic54x.h
@@ -69,8 +69,10 @@ struct bit_info
 extern int tic54x_start_label (int, char *);
 
 /* custom handling for relocations in cons expressions */
-#define TC_CONS_FIX_NEW(FRAG,OFF,LEN,EXP) tic54x_cons_fix_new(FRAG,OFF,LEN,EXP)
-extern void tic54x_cons_fix_new (fragS *,int,int,expressionS *);
+#define TC_CONS_FIX_NEW(FRAG, OFF, LEN, EXP, RELOC)	\
+  tic54x_cons_fix_new (FRAG, OFF, LEN, EXP, RELOC)
+extern void tic54x_cons_fix_new (fragS *, int, int, expressionS *,
+				 bfd_reloc_code_real_type);
 
 /* Define md_number_to_chars as the appropriate standard big endian or
    little endian function.  Mostly littleendian, but longwords and floats are
diff --git a/gas/config/tc-tic6x.c b/gas/config/tc-tic6x.c
index 1ffbb68..aca07d3 100644
--- a/gas/config/tc-tic6x.c
+++ b/gas/config/tc-tic6x.c
@@ -2012,10 +2012,9 @@ tic6x_fix_new_exp (fragS *frag, int where, int size, expressionS *exp,
    go through the error checking in tic6x_fix_new_exp.  */
 
 void
-tic6x_cons_fix_new (fragS *frag, int where, int size, expressionS *exp)
+tic6x_cons_fix_new (fragS *frag, int where, int size, expressionS *exp,
+		    bfd_reloc_code_real_type r_type)
 {
-  bfd_reloc_code_real_type r_type;
-
   switch (size)
     {
     case 1:
diff --git a/gas/config/tc-tic6x.h b/gas/config/tc-tic6x.h
index 2612aab..dc110e8 100644
--- a/gas/config/tc-tic6x.h
+++ b/gas/config/tc-tic6x.h
@@ -184,10 +184,10 @@ extern long tic6x_pcrel_from_section (struct fix *fixp, segT sec);
 #define md_start_line_hook() tic6x_start_line_hook ()
 extern void tic6x_start_line_hook (void);
 
-#define TC_CONS_FIX_NEW(frag, where, size, exp)	\
-  tic6x_cons_fix_new (frag, where, size, exp)
-extern void tic6x_cons_fix_new (fragS *frag, int where, int size,
-				expressionS *exp);
+#define TC_CONS_FIX_NEW(frag, where, size, exp, reloc)	\
+  tic6x_cons_fix_new (frag, where, size, exp, reloc)
+extern void tic6x_cons_fix_new (fragS *, int, int, expressionS *,
+				bfd_reloc_code_real_type);
 
 #define tc_fix_adjustable(FIX) tic6x_fix_adjustable (FIX)
 extern bfd_boolean tic6x_fix_adjustable (struct fix *);
diff --git a/gas/config/tc-v850.c b/gas/config/tc-v850.c
index d7bd99a..d5b9d7a 100644
--- a/gas/config/tc-v850.c
+++ b/gas/config/tc-v850.c
@@ -27,9 +27,6 @@
 /* Sign-extend a 16-bit number.  */
 #define SEXT16(x)	((((x) & 0xffff) ^ (~0x7fff)) + 0x8000)
 
-/* Temporarily holds the reloc in a cons expression.  */
-static bfd_reloc_code_real_type hold_cons_reloc = BFD_RELOC_UNUSED;
-
 /* Set to TRUE if we want to be pedantic about signed overflows.  */
 static bfd_boolean warn_signed_overflows   = FALSE;
 static bfd_boolean warn_unsigned_overflows = FALSE;
@@ -2156,7 +2153,7 @@ v850_reloc_prefix (const struct v850_operand *operand, const char **errmsg)
   if (paren_skipped)
     --input_line_pointer;
 
-  return BFD_RELOC_UNUSED;
+  return BFD_RELOC_NONE;
 }
 
 /* Insert an operand value into an instruction.  */
@@ -2407,7 +2404,7 @@ md_assemble (char *str)
 	  input_line_pointer = str;
 
 	  /* lo(), hi(), hi0(), etc...  */
-	  if ((reloc = v850_reloc_prefix (operand, &errmsg)) != BFD_RELOC_UNUSED)
+	  if ((reloc = v850_reloc_prefix (operand, &errmsg)) != BFD_RELOC_NONE)
 	    {
 	      /* This is a fake reloc, used to indicate an error condition.  */
 	      if (reloc == BFD_RELOC_64)
@@ -2977,7 +2974,7 @@ md_assemble (char *str)
 
 		  fixups[fc].exp     = ex;
 		  fixups[fc].opindex = *opindex_ptr;
-		  fixups[fc].reloc   = BFD_RELOC_UNUSED;
+		  fixups[fc].reloc   = BFD_RELOC_NONE;
 		  ++fc;
 		  break;
 		}
@@ -3239,7 +3236,7 @@ md_assemble (char *str)
 
       reloc = fixups[i].reloc;
 
-      if (reloc != BFD_RELOC_UNUSED)
+      if (reloc != BFD_RELOC_NONE)
 	{
 	  reloc_howto_type *reloc_howto =
 	    bfd_reloc_type_lookup (stdoutput, reloc);
@@ -3634,15 +3631,18 @@ md_apply_fix (fixS *fixP, valueT *valueP, segT seg ATTRIBUTE_UNUSED)
 /* Parse a cons expression.  We have to handle hi(), lo(), etc
    on the v850.  */
 
-void
+bfd_reloc_code_real_type
 parse_cons_expression_v850 (expressionS *exp)
 {
   const char *errmsg;
+  bfd_reloc_code_real_type r;
+
   /* See if there's a reloc prefix like hi() we have to handle.  */
-  hold_cons_reloc = v850_reloc_prefix (NULL, &errmsg);
+  r = v850_reloc_prefix (NULL, &errmsg);
 
   /* Do normal expression parsing.  */
   expression (exp);
+  return r;
 }
 
 /* Create a fixup for a cons expression.  If parse_cons_expression_v850
@@ -3653,24 +3653,23 @@ void
 cons_fix_new_v850 (fragS *frag,
 		   int where,
 		   int size,
-		   expressionS *exp)
+		   expressionS *exp,
+		   bfd_reloc_code_real_type r)
 {
-  if (hold_cons_reloc == BFD_RELOC_UNUSED)
+  if (r == BFD_RELOC_NONE)
     {
       if (size == 4)
-	hold_cons_reloc = BFD_RELOC_32;
+	r = BFD_RELOC_32;
       if (size == 2)
-	hold_cons_reloc = BFD_RELOC_16;
+	r = BFD_RELOC_16;
       if (size == 1)
-	hold_cons_reloc = BFD_RELOC_8;
+	r = BFD_RELOC_8;
     }
 
   if (exp != NULL)
-    fix_new_exp (frag, where, size, exp, 0, hold_cons_reloc);
+    fix_new_exp (frag, where, size, exp, 0, r);
   else
-    fix_new (frag, where, size, NULL, 0, 0, hold_cons_reloc);
-
-  hold_cons_reloc = BFD_RELOC_UNUSED;
+    fix_new (frag, where, size, NULL, 0, 0, r);
 }
 
 bfd_boolean
diff --git a/gas/config/tc-v850.h b/gas/config/tc-v850.h
index 1030ef3..a0aeeb4 100644
--- a/gas/config/tc-v850.h
+++ b/gas/config/tc-v850.h
@@ -58,10 +58,11 @@ extern int v850_force_relocation (struct fix *);
 /* We need to handle lo(), hi(), etc etc in .hword, .word, etc
    directives, so we have to parse "cons" expressions ourselves.  */
 #define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_cons_expression_v850 (EXP)
-extern void parse_cons_expression_v850 (expressionS *);
+extern bfd_reloc_code_real_type parse_cons_expression_v850 (expressionS *);
 
 #define TC_CONS_FIX_NEW cons_fix_new_v850
-extern void cons_fix_new_v850 (fragS *, int, int, expressionS *);
+extern void cons_fix_new_v850 (fragS *, int, int, expressionS *,
+			       bfd_reloc_code_real_type);
 
 #define TC_GENERIC_RELAX_TABLE md_relax_table
 extern const struct relax_type md_relax_table[];
diff --git a/gas/config/tc-vax.c b/gas/config/tc-vax.c
index 7a9ef0b..0740a9b 100644
--- a/gas/config/tc-vax.c
+++ b/gas/config/tc-vax.c
@@ -3264,12 +3264,11 @@ md_begin (void)
     }
 }
 
-static char *vax_cons_special_reloc;
-
-void
+bfd_reloc_code_real_type
 vax_cons (expressionS *exp, int size)
 {
   char *save;
+  char *vax_cons_special_reloc;
 
   SKIP_WHITESPACE ();
   vax_cons_special_reloc = NULL;
@@ -3373,35 +3372,29 @@ vax_cons (expressionS *exp, int size)
     }
   if (vax_cons_special_reloc == NULL)
     expression (exp);
+  else
+    switch (size)
+      {
+      case 1: return BFD_RELOC_8_PCREL;
+      case 2: return BFD_RELOC_16_PCREL;
+      case 4: return BFD_RELOC_32_PCREL;
+      }
+  return BFD_RELOC_NONE;
 }
 
 /* This is called by emit_expr via TC_CONS_FIX_NEW when creating a
    reloc for a cons.  */
 
 void
-vax_cons_fix_new (fragS *frag, int where, unsigned int nbytes, expressionS *exp)
+vax_cons_fix_new (fragS *frag, int where, unsigned int nbytes, expressionS *exp,
+		  bfd_reloc_code_real_type r)
 {
-  bfd_reloc_code_real_type r;
-
-  r = (nbytes == 1 ? BFD_RELOC_8 :
-       (nbytes == 2 ? BFD_RELOC_16 : BFD_RELOC_32));
-
-  if (vax_cons_special_reloc)
-    {
-      if (*vax_cons_special_reloc == 'p')
-	{
-	  switch (nbytes)
-	    {
-	    case 1: r = BFD_RELOC_8_PCREL; break;
-	    case 2: r = BFD_RELOC_16_PCREL; break;
-	    case 4: r = BFD_RELOC_32_PCREL; break;
-	    default: abort ();
-	    }
-	}
-    }
+  if (r == BFD_RELOC_NONE)
+    r = (nbytes == 1 ? BFD_RELOC_8
+	 : nbytes == 2 ? BFD_RELOC_16
+	 : BFD_RELOC_32);
 
   fix_new_exp (frag, where, (int) nbytes, exp, 0, r);
-  vax_cons_special_reloc = NULL;
 }
 
 char *
diff --git a/gas/config/tc-vax.h b/gas/config/tc-vax.h
index b242fe0..cc94bb2 100644
--- a/gas/config/tc-vax.h
+++ b/gas/config/tc-vax.h
@@ -49,8 +49,9 @@
 #ifdef OBJ_ELF
 #define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) vax_cons (EXP, NBYTES)
 #define TC_CONS_FIX_NEW vax_cons_fix_new
-void vax_cons (expressionS *, int);
-void vax_cons_fix_new (struct frag *, int, unsigned int, struct expressionS *);
+bfd_reloc_code_real_type vax_cons (expressionS *, int);
+void vax_cons_fix_new (struct frag *, int, unsigned int, struct expressionS *,
+		       bfd_reloc_code_real_type);
 #endif
 
 extern const struct relax_type md_relax_table[];
diff --git a/gas/config/tc-xstormy16.c b/gas/config/tc-xstormy16.c
index 1d57d60..e8eba89 100644
--- a/gas/config/tc-xstormy16.c
+++ b/gas/config/tc-xstormy16.c
@@ -193,10 +193,9 @@ void
 xstormy16_cons_fix_new (fragS *f,
 			int where,
 			int nbytes,
-			expressionS *exp)
+			expressionS *exp,
+			bfd_reloc_code_real_type code)
 {
-  bfd_reloc_code_real_type code;
-
   if (exp->X_op == O_fptr_symbol)
     {
       switch (nbytes)
diff --git a/gas/config/tc-xstormy16.h b/gas/config/tc-xstormy16.h
index 31ec16c..064a85c 100644
--- a/gas/config/tc-xstormy16.h
+++ b/gas/config/tc-xstormy16.h
@@ -57,7 +57,8 @@ extern int xstormy16_force_relocation (struct fix *);
 extern long md_pcrel_from_section (struct fix *, segT);
 
 #define TC_CONS_FIX_NEW xstormy16_cons_fix_new
-extern void xstormy16_cons_fix_new (fragS *f, int, int, expressionS *);
+extern void xstormy16_cons_fix_new (fragS *f, int, int, expressionS *,
+				    bfd_reloc_code_real_type);
 
 #define md_cgen_record_fixup_exp  xstormy16_cgen_record_fixup_exp
 
diff --git a/gas/dwarf2dbg.c b/gas/dwarf2dbg.c
index 4e9b654..5cc4662 100644
--- a/gas/dwarf2dbg.c
+++ b/gas/dwarf2dbg.c
@@ -158,6 +158,10 @@
 /* The maximum address skip amount that can be encoded with a special op.  */
 #define MAX_SPECIAL_ADDR_DELTA		SPECIAL_ADDR(255)
 
+#ifndef TC_PARSE_CONS_RETURN_NONE
+#define TC_PARSE_CONS_RETURN_NONE BFD_RELOC_NONE
+#endif
+
 struct line_entry {
   struct line_entry *next;
   symbolS *label;
@@ -1144,13 +1148,13 @@ emit_fixed_inc_line_addr (int line_delta, addressT addr_delta, fragS *frag,
       exp.X_op = O_symbol;
       exp.X_add_symbol = to_sym;
       exp.X_add_number = 0;
-      emit_expr_fix (&exp, sizeof_address, frag, p);
+      emit_expr_fix (&exp, sizeof_address, frag, p, TC_PARSE_CONS_RETURN_NONE);
       p += sizeof_address;
     }
   else
     {
       *p++ = DW_LNS_fixed_advance_pc;
-      emit_expr_fix (pexp, 2, frag, p);
+      emit_expr_fix (pexp, 2, frag, p, TC_PARSE_CONS_RETURN_NONE);
       p += 2;
     }
 
diff --git a/gas/read.c b/gas/read.c
index 08b129f..306f7ec 100644
--- a/gas/read.c
+++ b/gas/read.c
@@ -3851,19 +3851,22 @@ parse_mri_cons (expressionS *exp, unsigned int nbytes);
 
 #ifndef TC_PARSE_CONS_EXPRESSION
 #ifdef BITFIELD_CONS_EXPRESSIONS
-#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_bitfield_cons (EXP, NBYTES)
+#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) \
+  (parse_bitfield_cons (EXP, NBYTES), TC_PARSE_CONS_RETURN_NONE)
 static void
 parse_bitfield_cons (expressionS *exp, unsigned int nbytes);
 #endif
 #ifdef REPEAT_CONS_EXPRESSIONS
-#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_repeat_cons (EXP, NBYTES)
+#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) \
+  (parse_repeat_cons (EXP, NBYTES), TC_PARSE_CONS_RETURN_NONE)
 static void
 parse_repeat_cons (expressionS *exp, unsigned int nbytes);
 #endif
 
 /* If we haven't gotten one yet, just call expression.  */
 #ifndef TC_PARSE_CONS_EXPRESSION
-#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) expression (EXP)
+#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) \
+  (expression (EXP), TC_PARSE_CONS_RETURN_NONE)
 #endif
 #endif
 
@@ -3871,7 +3874,7 @@ void
 do_parse_cons_expression (expressionS *exp,
 			  int nbytes ATTRIBUTE_UNUSED)
 {
-  TC_PARSE_CONS_EXPRESSION (exp, nbytes);
+  (void) TC_PARSE_CONS_EXPRESSION (exp, nbytes);
 }
 
 
@@ -3914,6 +3917,8 @@ cons_worker (int nbytes,	/* 1=.byte, 2=.word, 4=.long.  */
   c = 0;
   do
     {
+      TC_PARSE_CONS_RETURN_TYPE ret = TC_PARSE_CONS_RETURN_NONE;
+
 #ifdef TC_M68K
       if (flag_m68k_mri)
 	parse_mri_cons (&exp, (unsigned int) nbytes);
@@ -3926,7 +3931,7 @@ cons_worker (int nbytes,	/* 1=.byte, 2=.word, 4=.long.  */
 	      ignore_rest_of_line ();
 	      return;
 	    }
-	  TC_PARSE_CONS_EXPRESSION (&exp, (unsigned int) nbytes);
+	  ret = TC_PARSE_CONS_EXPRESSION (&exp, (unsigned int) nbytes);
 	}
 
       if (rva)
@@ -3936,7 +3941,7 @@ cons_worker (int nbytes,	/* 1=.byte, 2=.word, 4=.long.  */
 	  else
 	    as_fatal (_("rva without symbol"));
 	}
-      emit_expr (&exp, (unsigned int) nbytes);
+      emit_expr_with_reloc (&exp, (unsigned int) nbytes, ret);
       ++c;
     }
   while (*input_line_pointer++ == ',');
@@ -4080,6 +4085,14 @@ s_reloc (int ignore ATTRIBUTE_UNUSED)
 void
 emit_expr (expressionS *exp, unsigned int nbytes)
 {
+  emit_expr_with_reloc (exp, nbytes, TC_PARSE_CONS_RETURN_NONE);
+}
+
+void
+emit_expr_with_reloc (expressionS *exp,
+		      unsigned int nbytes,
+		      TC_PARSE_CONS_RETURN_TYPE reloc)
+{
   operatorT op;
   char *p;
   valueT extra_digit = 0;
@@ -4221,6 +4234,12 @@ emit_expr (expressionS *exp, unsigned int nbytes)
 
   p = frag_more ((int) nbytes);
 
+  if (reloc != TC_PARSE_CONS_RETURN_NONE)
+    {
+      emit_expr_fix (exp, nbytes, frag_now, p, reloc);
+      return;
+    }
+
 #ifndef WORKING_DOT_WORD
   /* If we have the difference of two symbols in a word, save it on
      the broken_words list.  See the code in write.c.  */
@@ -4379,23 +4398,41 @@ emit_expr (expressionS *exp, unsigned int nbytes)
 	}
     }
   else
-    emit_expr_fix (exp, nbytes, frag_now, p);
+    emit_expr_fix (exp, nbytes, frag_now, p, TC_PARSE_CONS_RETURN_NONE);
 }
 
 void
-emit_expr_fix (expressionS *exp, unsigned int nbytes, fragS *frag, char *p)
+emit_expr_fix (expressionS *exp, unsigned int nbytes, fragS *frag, char *p,
+	       TC_PARSE_CONS_RETURN_TYPE r)
 {
-  memset (p, 0, nbytes);
+  int offset = 0;
+  unsigned int size = nbytes;
+
+  memset (p, 0, size);
 
   /* Generate a fixS to record the symbol value.  */
 
 #ifdef TC_CONS_FIX_NEW
-  TC_CONS_FIX_NEW (frag, p - frag->fr_literal, nbytes, exp);
+  TC_CONS_FIX_NEW (frag, p - frag->fr_literal + offset, size, exp, r);
 #else
-  {
-    bfd_reloc_code_real_type r;
+  if (r != TC_PARSE_CONS_RETURN_NONE)
+    {
+      reloc_howto_type *reloc_howto;
 
-    switch (nbytes)
+      reloc_howto = bfd_reloc_type_lookup (stdoutput, r);
+      size = bfd_get_reloc_size (reloc_howto);
+
+      if (size > nbytes)
+	{
+	  as_bad (_("%s relocations do not fit in %u bytes\n"),
+		  reloc_howto->name, nbytes);
+	  return;
+	}
+      else if (target_big_endian)
+	offset = nbytes - size;
+    }
+  else
+    switch (size)
       {
       case 1:
 	r = BFD_RELOC_8;
@@ -4413,13 +4450,11 @@ emit_expr_fix (expressionS *exp, unsigned int nbytes, fragS *frag, char *p)
 	r = BFD_RELOC_64;
 	break;
       default:
-	as_bad (_("unsupported BFD relocation size %u"), nbytes);
-	r = BFD_RELOC_32;
-	break;
+	as_bad (_("unsupported BFD relocation size %u"), size);
+	return;
       }
-    fix_new_exp (frag, p - frag->fr_literal, (int) nbytes, exp,
-		 0, r);
-  }
+  fix_new_exp (frag, p - frag->fr_literal + offset, size,
+	       exp, 0, r);
 #endif
 }
 
@@ -4555,9 +4590,7 @@ parse_bitfield_cons (exp, nbytes)
 
 #ifdef TC_M68K
 static void
-parse_mri_cons (exp, nbytes)
-     expressionS *exp;
-     unsigned int nbytes;
+parse_mri_cons (expressionS *exp, unsigned int nbytes)
 {
   if (*input_line_pointer != '\''
       && (input_line_pointer[1] != '\''
diff --git a/gas/read.h b/gas/read.h
index 59c0027..b85d3a9 100644
--- a/gas/read.h
+++ b/gas/read.h
@@ -93,6 +93,11 @@ enum linkonce_type {
 extern char original_case_string[];
 #endif
 
+#ifndef TC_PARSE_CONS_RETURN_TYPE
+#define TC_PARSE_CONS_RETURN_TYPE bfd_reloc_code_real_type
+#define TC_PARSE_CONS_RETURN_NONE BFD_RELOC_NONE
+#endif
+
 extern void pop_insert (const pseudo_typeS *);
 extern unsigned int get_stab_string_offset
   (const char *string, const char *stabstr_secname);
@@ -109,7 +114,10 @@ extern void add_include_dir (char *path);
 extern void cons (int nbytes);
 extern void demand_empty_rest_of_line (void);
 extern void emit_expr (expressionS *exp, unsigned int nbytes);
-extern void emit_expr_fix (expressionS *, unsigned int, fragS *, char *);
+extern void emit_expr_with_reloc (expressionS *exp, unsigned int nbytes,
+				  TC_PARSE_CONS_RETURN_TYPE);
+extern void emit_expr_fix (expressionS *, unsigned int, fragS *, char *,
+			   TC_PARSE_CONS_RETURN_TYPE);
 extern void equals (char *sym_name, int reassign);
 extern void float_cons (int float_type);
 extern void ignore_rest_of_line (void);
diff --git a/gas/write.c b/gas/write.c
index c974121..4ab275d 100644
--- a/gas/write.c
+++ b/gas/write.c
@@ -1883,7 +1883,7 @@ write_object_file (void)
 #ifdef TC_CONS_FIX_NEW
 	  TC_CONS_FIX_NEW (lie->frag,
 			   lie->word_goes_here - lie->frag->fr_literal,
-			   2, &exp);
+			   2, &exp, TC_PARSE_CONS_RETURN_NONE);
 #else
 	  fix_new_exp (lie->frag,
 		       lie->word_goes_here - lie->frag->fr_literal,

-- 
Alan Modra
Australia Development Lab, IBM


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