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]

powerpc gas fixups


PowerPC gas has two schemes for applying fixups.  One passes the
operand type (powerpc_operands index) in fx_r_type, encoded to not
clash with any bfd reloc numbers, so that md_apply_fix can use the
operand insertion code to apply relocs.  A bfd reloc type is then
chosen in md_apply_fix for cases where the fixup does not resolve.
The second scheme chooses a reloc in md_assemble, then applies the
reloc much as ld does.  This loses some checks, for instance the
recently exposed problem with gas modifying insn opcode bits, changing
lwa to ld, would not happen if we always used the operand insertion
code.  However, with a plethora of ELF relocs, you can't decide a
reloc just given the insn operand.  Various @ modifiers select the
reloc too.  So in this patch I steal fx_pcrel_adjust to store the
operand index, passing both reloc type and operand index to
md_apply_fix, allowing ppc_operand_insert to be used for all insn
fixups.

I've also changed gas to always write a zero into an insn field having
an ELF relocation.  I think that makes for cleaner disassembly of
object files.  Previously, gas wrote the symbol value plus addend
there.

	* config/tc-ppc.c (md_chars_to_number): Delete.
	(ppc_setup_opcodes): Assert num_powerpc_operands fit.
	(ppc_is_toc_sym): Move earlier in file.
	(md_assemble): Move code setting reloc from md_apply_fix.  Combine
	non-ELF code setting fixup with ELF code.  Stash opindex in
	fx_pcrel_adjust.  Adjust fixup offset for VLE.  Don't set
	fx_no_overflow here.
	(md_apply_fix): Rewrite to use ppc_insert_operand for all
	resolved instruction fields.  Leave insn field zero when
	emitting an ELF reloc in most cases.

Index: gas/config/tc-ppc.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-ppc.c,v
retrieving revision 1.187
diff -u -p -r1.187 tc-ppc.c
--- gas/config/tc-ppc.c	29 Oct 2012 10:09:29 -0000	1.187
+++ gas/config/tc-ppc.c	5 Nov 2012 00:39:15 -0000
@@ -1089,35 +1089,6 @@ const struct option md_longopts[] = {
 };
 const size_t md_longopts_size = sizeof (md_longopts);
 
-/* Convert the target integer stored in N bytes in BUF to a host
-   integer, returning that value.  */
-
-static valueT
-md_chars_to_number (char *buf, int n)
-{
-  valueT result = 0;
-  unsigned char *p = (unsigned char *) buf;
-
-  if (target_big_endian)
-    {
-      while (n--)
-	{
-	  result <<= 8;
-	  result |= (*p++ & 0xff);
-	}
-    }
-  else
-    {
-      while (n--)
-	{
-	  result <<= 8;
-	  result |= (p[n] & 0xff);
-	}
-    }
-
-  return result;
-}
-
 int
 md_parse_option (int c, char *arg)
 {
@@ -1536,6 +1507,10 @@ ppc_setup_opcodes (void)
     {
       unsigned int i;
 
+      /* An index into powerpc_operands is stored in struct fix
+	 fx_pcrel_adjust which is 8 bits wide.  */
+      gas_assert (num_powerpc_operands < 256);
+
       /* Check operand masks.  Code here and in the disassembler assumes
 	 all the 1's in the mask are contiguous.  */
       for (i = 0; i < num_powerpc_operands; ++i)
@@ -2451,6 +2440,25 @@ parse_toc_entry (enum toc_size_qualifier
   return 1;
 }
 #endif
+
+#if defined (OBJ_XCOFF) || defined (OBJ_ELF)
+/* See whether a symbol is in the TOC section.  */
+
+static int
+ppc_is_toc_sym (symbolS *sym)
+{
+#ifdef OBJ_XCOFF
+  return symbol_get_tc (sym)->symbol_class == XMC_TC;
+#endif
+#ifdef OBJ_ELF
+  const char *sname = segment_name (S_GET_SEGMENT (sym));
+  if (ppc_obj64)
+    return strcmp (sname, ".toc") == 0;
+  else
+    return strcmp (sname, ".got") == 0;
+#endif
+}
+#endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */
 
 
 #ifdef OBJ_ELF
@@ -2533,9 +2541,6 @@ md_assemble (char *str)
   int addr_mod;
   int i;
   unsigned int insn_length;
-#ifdef OBJ_ELF
-  bfd_reloc_code_real_type reloc;
-#endif
 
   /* Get the opcode.  */
   for (s = str; *s != '\0' && ! ISSPACE (*s); s++)
@@ -2817,6 +2822,7 @@ md_assemble (char *str)
 	{
 #ifdef OBJ_ELF
 	  /* Allow @HA, @L, @H on constants.  */
+	  bfd_reloc_code_real_type reloc;
 	  char *orig_str = str;
 
 	  if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
@@ -2882,9 +2888,10 @@ md_assemble (char *str)
 	  insn = ppc_insert_operand (insn, operand, ex.X_add_number,
 				     ppc_cpu, (char *) NULL, 0);
 	}
-#ifdef OBJ_ELF
       else
 	{
+	  bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
+#ifdef OBJ_ELF
 	  if (ex.X_op == O_symbol && str[0] == '(')
 	    {
 	      const char *sym_name = S_GET_NAME (ex.X_add_symbol);
@@ -3122,6 +3129,66 @@ md_assemble (char *str)
 		    }
 		}
 	    }
+#endif /* OBJ_ELF */
+
+	  if (reloc != BFD_RELOC_UNUSED)
+	    ;
+	  /* Determine a BFD reloc value based on the operand information.
+	     We are only prepared to turn a few of the operands into
+	     relocs.  */
+	  else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
+		   && operand->bitm == 0x3fffffc
+		   && operand->shift == 0)
+	    reloc = BFD_RELOC_PPC_B26;
+	  else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
+		   && operand->bitm == 0xfffc
+		   && operand->shift == 0)
+	    reloc = BFD_RELOC_PPC_B16;
+	  else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
+		   && operand->bitm == 0x1fe
+		   && operand->shift == -1)
+	    reloc = BFD_RELOC_PPC_VLE_REL8;
+	  else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
+		   && operand->bitm == 0xfffe
+		   && operand->shift == 0)
+	    reloc = BFD_RELOC_PPC_VLE_REL15;
+	  else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
+		   && operand->bitm == 0x1fffffe
+		   && operand->shift == 0)
+	    reloc = BFD_RELOC_PPC_VLE_REL24;
+	  else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0
+		   && operand->bitm == 0x3fffffc
+		   && operand->shift == 0)
+	    reloc = BFD_RELOC_PPC_BA26;
+	  else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0
+		   && operand->bitm == 0xfffc
+		   && operand->shift == 0)
+	    reloc = BFD_RELOC_PPC_BA16;
+#if defined (OBJ_XCOFF) || defined (OBJ_ELF)
+	  else if ((operand->flags & PPC_OPERAND_PARENS) != 0
+		   && (operand->bitm & 0xfff0) == 0xfff0
+		   && operand->shift == 0)
+	    {
+	      if (ppc_is_toc_sym (ex.X_add_symbol))
+		{
+		  reloc = BFD_RELOC_PPC_TOC16;
+#ifdef OBJ_ELF
+		  if (ppc_obj64
+		      && (operand->flags & PPC_OPERAND_DS) != 0)
+		    reloc = BFD_RELOC_PPC64_TOC16_DS;
+#endif
+		}
+	      else
+		{
+		  reloc = BFD_RELOC_16;
+#ifdef OBJ_ELF
+		  if (ppc_obj64
+		      && (operand->flags & PPC_OPERAND_DS) != 0)
+		    reloc = BFD_RELOC_PPC64_ADDR16_DS;
+#endif
+		}
+	    }
+#endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */
 
 	  /* We need to generate a fixup for this expression.  */
 	  if (fc >= MAX_INSN_FIXUPS)
@@ -3131,18 +3198,6 @@ md_assemble (char *str)
 	  fixups[fc].reloc = reloc;
 	  ++fc;
 	}
-#else /* OBJ_ELF */
-      else
-	{
-	  /* We need to generate a fixup for this expression.  */
-	  if (fc >= MAX_INSN_FIXUPS)
-	    as_fatal (_("too many fixups"));
-	  fixups[fc].exp = ex;
-	  fixups[fc].opindex = *opindex_ptr;
-	  fixups[fc].reloc = BFD_RELOC_UNUSED;
-	  ++fc;
-	}
-#endif /* OBJ_ELF */
 
       if (need_paren)
 	{
@@ -3243,27 +3298,22 @@ md_assemble (char *str)
   dwarf2_emit_insn (insn_length);
 #endif
 
-  /* Create any fixups.  At this point we do not use a
-     bfd_reloc_code_real_type, but instead just use the
-     BFD_RELOC_UNUSED plus the operand index.  This lets us easily
-     handle fixups for any operand type, although that is admittedly
-     not a very exciting feature.  We pick a BFD reloc type in
-     md_apply_fix.  */
+  /* Create any fixups.  */
   for (i = 0; i < fc; i++)
     {
+      fixS *fixP;
       if (fixups[i].reloc != BFD_RELOC_UNUSED)
 	{
 	  reloc_howto_type *reloc_howto;
 	  int size;
 	  int offset;
-	  fixS *fixP;
 
 	  reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc);
 	  if (!reloc_howto)
 	    abort ();
 
 	  size = bfd_get_reloc_size (reloc_howto);
-	  offset = target_big_endian ? (4 - size) : 0;
+	  offset = target_big_endian ? (insn_length - size) : 0;
 
 	  if (size < 1 || size > 4)
 	    abort ();
@@ -3274,47 +3324,20 @@ md_assemble (char *str)
 			      &fixups[i].exp,
 			      reloc_howto->pc_relative,
 			      fixups[i].reloc);
-
-	  /* Turn off complaints that the addend is too large for things like
-	     foo+100000@ha.  */
-	  switch (fixups[i].reloc)
-	    {
-	    case BFD_RELOC_16_GOTOFF:
-	    case BFD_RELOC_PPC_TOC16:
-	    case BFD_RELOC_LO16:
-	    case BFD_RELOC_HI16:
-	    case BFD_RELOC_HI16_S:
-	    case BFD_RELOC_PPC_VLE_LO16A:
-	    case BFD_RELOC_PPC_VLE_LO16D:
-	    case BFD_RELOC_PPC_VLE_HI16A:
-	    case BFD_RELOC_PPC_VLE_HI16D:
-	    case BFD_RELOC_PPC_VLE_HA16A:
-	    case BFD_RELOC_PPC_VLE_HA16D:
-#ifdef OBJ_ELF
-	    case BFD_RELOC_PPC64_HIGHER:
-	    case BFD_RELOC_PPC64_HIGHER_S:
-	    case BFD_RELOC_PPC64_HIGHEST:
-	    case BFD_RELOC_PPC64_HIGHEST_S:
-#endif
-	      fixP->fx_no_overflow = 1;
-	      break;
-	    default:
-	      break;
-	    }
 	}
       else
 	{
 	  const struct powerpc_operand *operand;
 
 	  operand = &powerpc_operands[fixups[i].opindex];
-	  fix_new_exp (frag_now,
-		       f - frag_now->fr_literal,
-		       insn_length,
-		       &fixups[i].exp,
-		       (operand->flags & PPC_OPERAND_RELATIVE) != 0,
-		       ((bfd_reloc_code_real_type)
-			(fixups[i].opindex + (int) BFD_RELOC_UNUSED)));
+	  fixP = fix_new_exp (frag_now,
+			      f - frag_now->fr_literal,
+			      insn_length,
+			      &fixups[i].exp,
+			      (operand->flags & PPC_OPERAND_RELATIVE) != 0,
+			      BFD_RELOC_UNUSED);
 	}
+      fixP->fx_pcrel_adjust = fixups[i].opindex;
     }
 }
 
@@ -4848,23 +4871,6 @@ ppc_machine (int ignore ATTRIBUTE_UNUSED
 
   demand_empty_rest_of_line ();
 }
-
-/* See whether a symbol is in the TOC section.  */
-
-static int
-ppc_is_toc_sym (symbolS *sym)
-{
-#ifdef OBJ_XCOFF
-  return symbol_get_tc (sym)->symbol_class == XMC_TC;
-#endif
-#ifdef OBJ_ELF
-  const char *sname = segment_name (S_GET_SEGMENT (sym));
-  if (ppc_obj64)
-    return strcmp (sname, ".toc") == 0;
-  else
-    return strcmp (sname, ".got") == 0;
-#endif
-}
 #endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */
 
 #ifdef TE_PE
@@ -6292,13 +6298,7 @@ ppc_handle_align (struct frag *fragP)
 }
 
 /* Apply a fixup to the object code.  This is called for all the
-   fixups we generated by the call to fix_new_exp, above.  In the call
-   above we used a reloc code which was the largest legal reloc code
-   plus the operand index.  Here we undo that to recover the operand
-   index.  At this point all symbol values should be fully resolved,
-   and we attempt to completely resolve the reloc.  If we can not do
-   that, we determine the correct reloc code and put it back in the
-   fixup.  */
+   fixups we generated by the calls to fix_new_exp, above.  */
 
 void
 md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
@@ -6342,16 +6342,15 @@ md_apply_fix (fixS *fixP, valueT *valP, 
       as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
     }
 
-  if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
+  if (fixP->fx_pcrel_adjust != 0)
     {
-      int opindex;
-      const struct powerpc_operand *operand;
+      /* Handle relocs in an insn.  */
+
+      int opindex = fixP->fx_pcrel_adjust & 0xff;
+      const struct powerpc_operand *operand = &powerpc_operands[opindex];
       char *where;
       unsigned long insn;
-
-      opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
-
-      operand = &powerpc_operands[opindex];
+      offsetT fieldval;
 
 #ifdef OBJ_XCOFF
       /* An instruction like `lwz 9,sym(30)' when `sym' is not a TOC symbol
@@ -6372,437 +6371,72 @@ md_apply_fix (fixS *fixP, valueT *valP, 
 	  fixP->fx_done = 1;
 	}
 #endif
-
-      /* Fetch the instruction, insert the fully resolved operand
-	 value, and stuff the instruction back again.  */
-      where = fixP->fx_frag->fr_literal + fixP->fx_where;
-      if (target_big_endian)
-	{
-	  if (fixP->fx_size == 4)
-	    insn = bfd_getb32 ((unsigned char *) where);
-	  else
-	    insn = bfd_getb16 ((unsigned char *) where);
-	}
-      else
-	{
-	  if (fixP->fx_size == 4)
-	    insn = bfd_getl32 ((unsigned char *) where);
-	  else
-	    insn = bfd_getl16 ((unsigned char *) where);
-	}
-      insn = ppc_insert_operand (insn, operand, (offsetT) value,
-				 fixP->tc_fix_data.ppc_cpu,
-				 fixP->fx_file, fixP->fx_line);
-      if (target_big_endian)
-	{
-	  if (fixP->fx_size == 4)
-	    bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
-	  else
-	    bfd_putb16 ((bfd_vma) insn, (unsigned char *) where);
-	}
-      else
-	{
-	  if (fixP->fx_size == 4)
-	    bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
-	  else
-	    bfd_putl16 ((bfd_vma) insn, (unsigned char *) where);
-	}
-
-      if (fixP->fx_done)
-	/* Nothing else to do here.  */
-	return;
-
-      gas_assert (fixP->fx_addsy != NULL);
-
-      /* Determine a BFD reloc value based on the operand information.
-	 We are only prepared to turn a few of the operands into
-	 relocs.  */
-      if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
-	  && operand->bitm == 0x3fffffc
-	  && operand->shift == 0)
-	fixP->fx_r_type = BFD_RELOC_PPC_B26;
-      else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
-	  && operand->bitm == 0xfffc
-	  && operand->shift == 0)
-	{
-	  fixP->fx_r_type = BFD_RELOC_PPC_B16;
-#ifdef OBJ_XCOFF
-	  fixP->fx_size = 2;
-	  if (target_big_endian)
-	    fixP->fx_where += 2;
-#endif
-	}
-      else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
-	  && operand->bitm == 0x1fe
-	  && operand->shift == -1)
-	fixP->fx_r_type = BFD_RELOC_PPC_VLE_REL8;
-      else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
-	  && operand->bitm == 0xfffe
-	  && operand->shift == 0)
-	fixP->fx_r_type = BFD_RELOC_PPC_VLE_REL15;
-      else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
-	  && operand->bitm == 0x1fffffe
-	  && operand->shift == 0)
-	fixP->fx_r_type = BFD_RELOC_PPC_VLE_REL24;
-      else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0
-	       && operand->bitm == 0x3fffffc
-	       && operand->shift == 0)
-	fixP->fx_r_type = BFD_RELOC_PPC_BA26;
-      else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0
-	       && operand->bitm == 0xfffc
-	       && operand->shift == 0)
-	{
-	  fixP->fx_r_type = BFD_RELOC_PPC_BA16;
-#ifdef OBJ_XCOFF
-	  fixP->fx_size = 2;
-	  if (target_big_endian)
-	    fixP->fx_where += 2;
-#endif
-	}
-#if defined (OBJ_XCOFF) || defined (OBJ_ELF)
-      else if ((operand->flags & PPC_OPERAND_PARENS) != 0
-	       && (operand->bitm & 0xfff0) == 0xfff0
-	       && operand->shift == 0)
-	{
-	  if (ppc_is_toc_sym (fixP->fx_addsy))
-	    {
-	      fixP->fx_r_type = BFD_RELOC_PPC_TOC16;
-#ifdef OBJ_ELF
-	      if (ppc_obj64
-		  && (operand->flags & PPC_OPERAND_DS) != 0)
-		fixP->fx_r_type = BFD_RELOC_PPC64_TOC16_DS;
-#endif
-	    }
-	  else
-	    {
-	      fixP->fx_r_type = BFD_RELOC_16;
-#ifdef OBJ_ELF
-	      if (ppc_obj64
-		  && (operand->flags & PPC_OPERAND_DS) != 0)
-		fixP->fx_r_type = BFD_RELOC_PPC64_ADDR16_DS;
-#endif
-	    }
-	  fixP->fx_size = 2;
-	  if (target_big_endian)
-	    fixP->fx_where += 2;
-	}
-#endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */
-      else
-	{
-	  char *sfile;
-	  unsigned int sline;
-
-	  /* Use expr_symbol_where to see if this is an expression
-	     symbol.  */
-	  if (expr_symbol_where (fixP->fx_addsy, &sfile, &sline))
-	    as_bad_where (fixP->fx_file, fixP->fx_line,
-			  _("unresolved expression that must be resolved"));
-	  else
-	    as_bad_where (fixP->fx_file, fixP->fx_line,
-			  _("unsupported relocation against %s"),
-			  S_GET_NAME (fixP->fx_addsy));
-	  fixP->fx_done = 1;
-	  return;
-	}
-    }
-  else
-    {
-#ifdef OBJ_ELF
-      ppc_elf_validate_fix (fixP, seg);
-#endif
+      fieldval = value;
       switch (fixP->fx_r_type)
 	{
-	case BFD_RELOC_CTOR:
-	  if (ppc_obj64)
-	    goto ctor64;
-	  /* fall through */
-
-	case BFD_RELOC_32:
-	  if (fixP->fx_pcrel)
-	    fixP->fx_r_type = BFD_RELOC_32_PCREL;
-	  /* fall through */
-
-	case BFD_RELOC_RVA:
-	case BFD_RELOC_32_PCREL:
-	case BFD_RELOC_PPC_EMB_NADDR32:
-	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			      value, 4);
-	  break;
-
-	case BFD_RELOC_64:
-	ctor64:
-	  if (fixP->fx_pcrel)
-	    fixP->fx_r_type = BFD_RELOC_64_PCREL;
-	  /* fall through */
-
-	case BFD_RELOC_64_PCREL:
-	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			      value, 8);
-	  break;
-
-	case BFD_RELOC_GPREL16:
-	case BFD_RELOC_16_GOT_PCREL:
-	case BFD_RELOC_16_GOTOFF:
-	case BFD_RELOC_LO16_GOTOFF:
-	case BFD_RELOC_HI16_GOTOFF:
-	case BFD_RELOC_HI16_S_GOTOFF:
-	case BFD_RELOC_16_BASEREL:
-	case BFD_RELOC_LO16_BASEREL:
-	case BFD_RELOC_HI16_BASEREL:
-	case BFD_RELOC_HI16_S_BASEREL:
-	case BFD_RELOC_PPC_EMB_NADDR16:
-	case BFD_RELOC_PPC_EMB_NADDR16_LO:
-	case BFD_RELOC_PPC_EMB_NADDR16_HI:
-	case BFD_RELOC_PPC_EMB_NADDR16_HA:
-	case BFD_RELOC_PPC_EMB_SDAI16:
-	case BFD_RELOC_PPC_EMB_SDA2REL:
-	case BFD_RELOC_PPC_EMB_SDA2I16:
-	case BFD_RELOC_PPC_EMB_RELSEC16:
-	case BFD_RELOC_PPC_EMB_RELST_LO:
-	case BFD_RELOC_PPC_EMB_RELST_HI:
-	case BFD_RELOC_PPC_EMB_RELST_HA:
-	case BFD_RELOC_PPC_EMB_RELSDA:
-	case BFD_RELOC_PPC_TOC16:
-#ifdef OBJ_ELF
-	case BFD_RELOC_PPC64_TOC16_LO:
-	case BFD_RELOC_PPC64_TOC16_HI:
-	case BFD_RELOC_PPC64_TOC16_HA:
-#endif
-	  if (fixP->fx_pcrel)
-	    {
-	      if (fixP->fx_addsy != NULL)
-		as_bad_where (fixP->fx_file, fixP->fx_line,
-			      _("cannot emit PC relative %s relocation against %s"),
-			      bfd_get_reloc_code_name (fixP->fx_r_type),
-			      S_GET_NAME (fixP->fx_addsy));
-	      else
-		as_bad_where (fixP->fx_file, fixP->fx_line,
-			      _("cannot emit PC relative %s relocation"),
-			      bfd_get_reloc_code_name (fixP->fx_r_type));
-	    }
-
-	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			      value, 2);
-	  break;
-
-	case BFD_RELOC_16:
+	case BFD_RELOC_PPC64_ADDR16_LO_DS:
 	  if (fixP->fx_pcrel)
-	    fixP->fx_r_type = BFD_RELOC_16_PCREL;
+	    goto bad_pcrel;
 	  /* fall through */
-
-	case BFD_RELOC_16_PCREL:
-	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			      value, 2);
-	  break;
-
 	case BFD_RELOC_LO16:
 	  if (fixP->fx_pcrel)
 	    fixP->fx_r_type = BFD_RELOC_LO16_PCREL;
 	  /* fall through */
-
 	case BFD_RELOC_LO16_PCREL:
-	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			      value, 2);
+	  fieldval = SEX16 (value);
 	  break;
 
-	  /* This case happens when you write, for example,
-	     lis %r3,(L1-L2)@ha
-	     where L1 and L2 are defined later.  */
 	case BFD_RELOC_HI16:
 	  if (fixP->fx_pcrel)
 	    fixP->fx_r_type = BFD_RELOC_HI16_PCREL;
 	  /* fall through */
-
 	case BFD_RELOC_HI16_PCREL:
-	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			      PPC_HI (value), 2);
+	  fieldval = SEX16 (PPC_HI (value));
 	  break;
 
 	case BFD_RELOC_HI16_S:
 	  if (fixP->fx_pcrel)
 	    fixP->fx_r_type = BFD_RELOC_HI16_S_PCREL;
 	  /* fall through */
-
 	case BFD_RELOC_HI16_S_PCREL:
-	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			      PPC_HA (value), 2);
-	  break;
-
-	case BFD_RELOC_PPC_VLE_SDAREL_LO16A:
-	case BFD_RELOC_PPC_VLE_LO16A:
-	  {
-	    int tval = PPC_VLE_LO16A (value);
-  	    valueT oldval = md_chars_to_number (
-				fixP->fx_frag->fr_literal + fixP->fx_where, 4);
-	    md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			        (oldval | tval), 4);
-	  }
-	  break;
-
-	case BFD_RELOC_PPC_VLE_SDAREL_LO16D:
-	case BFD_RELOC_PPC_VLE_LO16D:
-	  {
-	    int tval = PPC_VLE_LO16D (value);
-  	    valueT oldval = md_chars_to_number (
-				fixP->fx_frag->fr_literal + fixP->fx_where, 4);
-	    md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			        (oldval | tval), 4);
-	  }
-	  break;
-
-	case BFD_RELOC_PPC_VLE_SDAREL_HI16A:
-	case BFD_RELOC_PPC_VLE_HI16A:
-	  {
-	    int tval = PPC_VLE_HI16A (value);
-  	    valueT oldval = md_chars_to_number (
-				fixP->fx_frag->fr_literal + fixP->fx_where, 4);
-	    md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			        (oldval | tval), 4);
-	  }
-	  break;
-
-	case BFD_RELOC_PPC_VLE_SDAREL_HI16D:
-	case BFD_RELOC_PPC_VLE_HI16D:
-	  {
-	    int tval = PPC_VLE_HI16D (value);
-  	    valueT oldval = md_chars_to_number (
-				fixP->fx_frag->fr_literal + fixP->fx_where, 4);
-	    md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			        (oldval | tval), 4);
-	  }
-	  break;
-
-	case BFD_RELOC_PPC_VLE_SDAREL_HA16A:
-	case BFD_RELOC_PPC_VLE_HA16A:
-	  {
-	    int tval = PPC_VLE_HA16A (value);
-  	    valueT oldval = md_chars_to_number (
-				fixP->fx_frag->fr_literal + fixP->fx_where, 4);
-	    md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			        (oldval | tval), 4);
-	  }
-	  break;
-
-	case BFD_RELOC_PPC_VLE_SDAREL_HA16D:
-	case BFD_RELOC_PPC_VLE_HA16D:
-	  {
-	    int tval = PPC_VLE_HA16D (value);
-  	    valueT oldval = md_chars_to_number (
-				fixP->fx_frag->fr_literal + fixP->fx_where, 4);
-	    md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			        (oldval | tval), 4);
-	  }
-	  break;
-
-	case BFD_RELOC_PPC_VLE_SDA21_LO:
-	  {
-	    int tval = PPC_LO (value);
-  	    valueT oldval = md_chars_to_number (
-			     fixP->fx_frag->fr_literal + fixP->fx_where, 4);
-	    md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			        (oldval | tval), 4);
-	  }
-	  break;
-
-	case BFD_RELOC_PPC_VLE_SDA21:
-	  {
-  	    valueT oldval = md_chars_to_number (
-			     fixP->fx_frag->fr_literal + fixP->fx_where, 4);
-	    md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			        (oldval | value), 4);
-	  }
-	  break;
-
-#ifdef OBJ_XCOFF
-	case BFD_RELOC_NONE:
+	  fieldval = SEX16 (PPC_HA (value));
 	  break;
-#endif
 
 #ifdef OBJ_ELF
 	case BFD_RELOC_PPC64_HIGHER:
 	  if (fixP->fx_pcrel)
-	    abort ();
-	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			      PPC_HIGHER (value), 2);
+	    goto bad_pcrel;
+	  fieldval = SEX16 (PPC_HIGHER (value));
 	  break;
 
 	case BFD_RELOC_PPC64_HIGHER_S:
 	  if (fixP->fx_pcrel)
-	    abort ();
-	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			      PPC_HIGHERA (value), 2);
+	    goto bad_pcrel;
+	  fieldval = SEX16 (PPC_HIGHERA (value));
 	  break;
 
 	case BFD_RELOC_PPC64_HIGHEST:
 	  if (fixP->fx_pcrel)
-	    abort ();
-	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			      PPC_HIGHEST (value), 2);
+	    goto bad_pcrel;
+	  fieldval = SEX16 (PPC_HIGHEST (value));
 	  break;
 
 	case BFD_RELOC_PPC64_HIGHEST_S:
 	  if (fixP->fx_pcrel)
-	    abort ();
-	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-			      PPC_HIGHESTA (value), 2);
-	  break;
-
-	case BFD_RELOC_PPC64_ADDR16_DS:
-	case BFD_RELOC_PPC64_ADDR16_LO_DS:
-	case BFD_RELOC_PPC64_GOT16_DS:
-	case BFD_RELOC_PPC64_GOT16_LO_DS:
-	case BFD_RELOC_PPC64_PLT16_LO_DS:
-	case BFD_RELOC_PPC64_SECTOFF_DS:
-	case BFD_RELOC_PPC64_SECTOFF_LO_DS:
-	case BFD_RELOC_PPC64_TOC16_DS:
-	case BFD_RELOC_PPC64_TOC16_LO_DS:
-	case BFD_RELOC_PPC64_PLTGOT16_DS:
-	case BFD_RELOC_PPC64_PLTGOT16_LO_DS:
-	  if (fixP->fx_pcrel)
-	    abort ();
-	  {
-	    char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
-	    unsigned long val, mask;
-
-	    if (target_big_endian)
-	      val = bfd_getb32 (where - 2);
-	    else
-	      val = bfd_getl32 (where);
-	    mask = 0xfffc;
-	    /* lq insns reserve the four lsbs.  */
-	    if ((ppc_cpu & PPC_OPCODE_POWER4) != 0
-		&& (val & (0x3f << 26)) == (56u << 26))
-	      mask = 0xfff0;
-	    val |= value & mask;
-	    if (target_big_endian)
-	      bfd_putb16 ((bfd_vma) val, where);
-	    else
-	      bfd_putl16 ((bfd_vma) val, where);
-	  }
-	  break;
-
-	case BFD_RELOC_PPC_B16_BRTAKEN:
-	case BFD_RELOC_PPC_B16_BRNTAKEN:
-	case BFD_RELOC_PPC_BA16_BRTAKEN:
-	case BFD_RELOC_PPC_BA16_BRNTAKEN:
+	    goto bad_pcrel;
+	  fieldval = SEX16 (PPC_HIGHESTA (value));
 	  break;
 
-	case BFD_RELOC_PPC_TLS:
-	case BFD_RELOC_PPC_TLSGD:
-	case BFD_RELOC_PPC_TLSLD:
-	  break;
-
-	case BFD_RELOC_PPC_DTPMOD:
+	  /* The following relocs can't be calculated by the assembler.
+	     Leave the field zero.  */
 	case BFD_RELOC_PPC_TPREL16:
 	case BFD_RELOC_PPC_TPREL16_LO:
 	case BFD_RELOC_PPC_TPREL16_HI:
 	case BFD_RELOC_PPC_TPREL16_HA:
-	case BFD_RELOC_PPC_TPREL:
 	case BFD_RELOC_PPC_DTPREL16:
 	case BFD_RELOC_PPC_DTPREL16_LO:
 	case BFD_RELOC_PPC_DTPREL16_HI:
 	case BFD_RELOC_PPC_DTPREL16_HA:
-	case BFD_RELOC_PPC_DTPREL:
 	case BFD_RELOC_PPC_GOT_TLSGD16:
 	case BFD_RELOC_PPC_GOT_TLSGD16_LO:
 	case BFD_RELOC_PPC_GOT_TLSGD16_HI:
@@ -6831,98 +6465,386 @@ md_apply_fix (fixS *fixP, valueT *valP, 
 	case BFD_RELOC_PPC64_DTPREL16_HIGHERA:
 	case BFD_RELOC_PPC64_DTPREL16_HIGHEST:
 	case BFD_RELOC_PPC64_DTPREL16_HIGHESTA:
+	  gas_assert (fixP->fx_addsy != NULL);
 	  S_SET_THREAD_LOCAL (fixP->fx_addsy);
+	  fieldval = 0;
+	  if (fixP->fx_pcrel)
+	    goto bad_pcrel;
 	  break;
-#endif
-	  /* Because SDA21 modifies the register field, the size is set to 4
-	     bytes, rather than 2, so offset it here appropriately.  */
+
+	  /* These also should leave the field zero for the same
+	     reason.  Note that older versions of gas wrote values
+	     here.  If we want to go back to the old behaviour, then
+	     all _LO and _LO_DS cases will need to be treated like
+	     BFD_RELOC_LO16_PCREL above.  Similarly for _HI etc.  */
+	case BFD_RELOC_16_GOTOFF:
+	case BFD_RELOC_LO16_GOTOFF:
+	case BFD_RELOC_HI16_GOTOFF:
+	case BFD_RELOC_HI16_S_GOTOFF:
+	case BFD_RELOC_LO16_PLTOFF:
+	case BFD_RELOC_HI16_PLTOFF:
+	case BFD_RELOC_HI16_S_PLTOFF:
+	case BFD_RELOC_GPREL16:
+	case BFD_RELOC_16_BASEREL:
+	case BFD_RELOC_LO16_BASEREL:
+	case BFD_RELOC_HI16_BASEREL:
+	case BFD_RELOC_HI16_S_BASEREL:
+	case BFD_RELOC_PPC_TOC16:
+	case BFD_RELOC_PPC64_TOC16_LO:
+	case BFD_RELOC_PPC64_TOC16_HI:
+	case BFD_RELOC_PPC64_TOC16_HA:
+	case BFD_RELOC_PPC64_PLTGOT16:
+	case BFD_RELOC_PPC64_PLTGOT16_LO:
+	case BFD_RELOC_PPC64_PLTGOT16_HI:
+	case BFD_RELOC_PPC64_PLTGOT16_HA:
+	case BFD_RELOC_PPC64_GOT16_DS:
+	case BFD_RELOC_PPC64_GOT16_LO_DS:
+	case BFD_RELOC_PPC64_PLT16_LO_DS:
+	case BFD_RELOC_PPC64_SECTOFF_DS:
+	case BFD_RELOC_PPC64_SECTOFF_LO_DS:
+	case BFD_RELOC_PPC64_TOC16_DS:
+	case BFD_RELOC_PPC64_TOC16_LO_DS:
+	case BFD_RELOC_PPC64_PLTGOT16_DS:
+	case BFD_RELOC_PPC64_PLTGOT16_LO_DS:
+	case BFD_RELOC_PPC_EMB_NADDR16:
+	case BFD_RELOC_PPC_EMB_NADDR16_LO:
+	case BFD_RELOC_PPC_EMB_NADDR16_HI:
+	case BFD_RELOC_PPC_EMB_NADDR16_HA:
+	case BFD_RELOC_PPC_EMB_SDAI16:
+	case BFD_RELOC_PPC_EMB_SDA2I16:
+	case BFD_RELOC_PPC_EMB_SDA2REL:
 	case BFD_RELOC_PPC_EMB_SDA21:
+	case BFD_RELOC_PPC_EMB_MRKREF:
+	case BFD_RELOC_PPC_EMB_RELSEC16:
+	case BFD_RELOC_PPC_EMB_RELST_LO:
+	case BFD_RELOC_PPC_EMB_RELST_HI:
+	case BFD_RELOC_PPC_EMB_RELST_HA:
+	case BFD_RELOC_PPC_EMB_BIT_FLD:
+	case BFD_RELOC_PPC_EMB_RELSDA:
+	case BFD_RELOC_PPC_VLE_SDA21:
+	case BFD_RELOC_PPC_VLE_SDA21_LO:
+	case BFD_RELOC_PPC_VLE_SDAREL_LO16A:
+	case BFD_RELOC_PPC_VLE_SDAREL_LO16D:
+	case BFD_RELOC_PPC_VLE_SDAREL_HI16A:
+	case BFD_RELOC_PPC_VLE_SDAREL_HI16D:
+	case BFD_RELOC_PPC_VLE_SDAREL_HA16A:
+	case BFD_RELOC_PPC_VLE_SDAREL_HA16D:
+	  gas_assert (fixP->fx_addsy != NULL);
+	  /* Fall thru */
+
+	case BFD_RELOC_PPC_TLS:
+	case BFD_RELOC_PPC_TLSGD:
+	case BFD_RELOC_PPC_TLSLD:
+	  fieldval = 0;
 	  if (fixP->fx_pcrel)
-	    abort ();
+	    goto bad_pcrel;
+	  break;
+#endif
 
-	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where
-			      + ((target_big_endian) ? 2 : 0),
-			      value, 2);
+	default:
 	  break;
+	}
 
-	case BFD_RELOC_8:
-	  if (fixP->fx_pcrel)
+#ifdef OBJ_ELF
+/* powerpc uses RELA style relocs, so if emitting a reloc the field
+   contents can stay at zero.  */
+#define APPLY_RELOC fixP->fx_done
+#else
+#define APPLY_RELOC 1
+#endif
+      if ((fieldval != 0 && APPLY_RELOC) || operand->insert != NULL)
+	{
+	  /* Fetch the instruction, insert the fully resolved operand
+	     value, and stuff the instruction back again.  */
+	  where = fixP->fx_frag->fr_literal + fixP->fx_where;
+	  if (target_big_endian)
 	    {
-	      /* This can occur if there is a bug in the input assembler, eg:
-		 ".byte <undefined_symbol> - ."  */
-	      if (fixP->fx_addsy)
-		as_bad (_("unable to handle reference to symbol %s"),
-			S_GET_NAME (fixP->fx_addsy));
+	      if (fixP->fx_size == 4)
+		insn = bfd_getb32 ((unsigned char *) where);
 	      else
-		as_bad (_("unable to resolve expression"));
-	      fixP->fx_done = 1;
+		insn = bfd_getb16 ((unsigned char *) where);
 	    }
 	  else
-	    md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-				value, 1);
+	    {
+	      if (fixP->fx_size == 4)
+		insn = bfd_getl32 ((unsigned char *) where);
+	      else
+		insn = bfd_getl16 ((unsigned char *) where);
+	    }
+	  insn = ppc_insert_operand (insn, operand, fieldval,
+				     fixP->tc_fix_data.ppc_cpu,
+				     fixP->fx_file, fixP->fx_line);
+	  if (target_big_endian)
+	    {
+	      if (fixP->fx_size == 4)
+		bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
+	      else
+		bfd_putb16 ((bfd_vma) insn, (unsigned char *) where);
+	    }
+	  else
+	    {
+	      if (fixP->fx_size == 4)
+		bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
+	      else
+		bfd_putl16 ((bfd_vma) insn, (unsigned char *) where);
+	    }
+	}
+
+      if (fixP->fx_done)
+	/* Nothing else to do here.  */
+	return;
+
+      gas_assert (fixP->fx_addsy != NULL);
+      if (fixP->fx_r_type == BFD_RELOC_UNUSED)
+	{
+	  char *sfile;
+	  unsigned int sline;
+
+	  /* Use expr_symbol_where to see if this is an expression
+	     symbol.  */
+	  if (expr_symbol_where (fixP->fx_addsy, &sfile, &sline))
+	    as_bad_where (fixP->fx_file, fixP->fx_line,
+			  _("unresolved expression that must be resolved"));
+	  else
+	    as_bad_where (fixP->fx_file, fixP->fx_line,
+			  _("unsupported relocation against %s"),
+			  S_GET_NAME (fixP->fx_addsy));
+	  fixP->fx_done = 1;
+	  return;
+	}
+    }
+  else
+    {
+      /* Handle relocs in data.  */
+      switch (fixP->fx_r_type)
+	{
+	case BFD_RELOC_CTOR:
+	  if (ppc_obj64)
+	    goto ctor64;
+	  /* fall through */
+
+	case BFD_RELOC_32:
+	  if (fixP->fx_pcrel)
+	    fixP->fx_r_type = BFD_RELOC_32_PCREL;
+	  /* fall through */
+
+	case BFD_RELOC_32_PCREL:
+	case BFD_RELOC_RVA:
+	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+			      value, 4);
 	  break;
 
-	case BFD_RELOC_24_PLT_PCREL:
-	case BFD_RELOC_PPC_LOCAL24PC:
-	  if (!fixP->fx_pcrel && !fixP->fx_done)
-	    abort ();
+	case BFD_RELOC_64:
+	ctor64:
+	  if (fixP->fx_pcrel)
+	    fixP->fx_r_type = BFD_RELOC_64_PCREL;
+	  /* fall through */
 
-	  if (fixP->fx_done)
-	    {
-	      char *where;
-	      unsigned long insn;
+	case BFD_RELOC_64_PCREL:
+	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+			      value, 8);
+	  break;
 
-	      /* Fetch the instruction, insert the fully resolved operand
-		 value, and stuff the instruction back again.  */
-	      where = fixP->fx_frag->fr_literal + fixP->fx_where;
-	      if (target_big_endian)
-		insn = bfd_getb32 ((unsigned char *) where);
-	      else
-		insn = bfd_getl32 ((unsigned char *) where);
-	      if (ppc_mach() == bfd_mach_ppc_vle)
+	case BFD_RELOC_16:
+	  if (fixP->fx_pcrel)
+	    fixP->fx_r_type = BFD_RELOC_16_PCREL;
+	  /* fall through */
+
+	case BFD_RELOC_16_PCREL:
+	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+			      value, 2);
+	  break;
+
+	case BFD_RELOC_8:
+	  if (fixP->fx_pcrel)
+	    {
+#ifdef OBJ_ELF
+	    bad_pcrel:
+#endif
+	      if (fixP->fx_addsy)
 		{
-		  if ((value & 1) != 0)
+		  char *sfile;
+		  unsigned int sline;
+
+		  /* Use expr_symbol_where to see if this is an
+		     expression symbol.  */
+		  if (expr_symbol_where (fixP->fx_addsy, &sfile, &sline))
 		    as_bad_where (fixP->fx_file, fixP->fx_line,
-			          _("branch address must be a multiple of 2"));
-		}
-	      else
-		{
-		  if ((value & 3) != 0)
+				  _("unresolved expression that must"
+				    " be resolved"));
+		  else
 		    as_bad_where (fixP->fx_file, fixP->fx_line,
-			          _("branch address must be a multiple of 4"));
+				  _("cannot emit PC relative %s relocation"
+				    " against %s"),
+				  bfd_get_reloc_code_name (fixP->fx_r_type),
+				  S_GET_NAME (fixP->fx_addsy));
 		}
-	      if ((offsetT) value < -0x40000000
-		  || (offsetT) value >= 0x40000000)
-		as_bad_where (fixP->fx_file, fixP->fx_line,
-			      _("@local or @plt branch destination is too far away, %ld bytes"),
-			      (long) value);
-	      insn = insn | (value & 0x03fffffc);
-	      if (target_big_endian)
-		bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
 	      else
-		bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
+		as_bad_where (fixP->fx_file, fixP->fx_line,
+			      _("unable to resolve expression"));
+	      fixP->fx_done = 1;
 	    }
+	  else
+	    md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+				value, 1);
 	  break;
 
 	case BFD_RELOC_VTABLE_INHERIT:
-	  fixP->fx_done = 0;
 	  if (fixP->fx_addsy
 	      && !S_IS_DEFINED (fixP->fx_addsy)
 	      && !S_IS_WEAK (fixP->fx_addsy))
 	    S_SET_WEAK (fixP->fx_addsy);
-	  break;
+	  /* Fall thru */
 
 	case BFD_RELOC_VTABLE_ENTRY:
 	  fixP->fx_done = 0;
 	  break;
 
 #ifdef OBJ_ELF
-	  /* Generated by reference to `sym@tocbase'.  The sym is
-	     ignored by the linker.  */
+	  /* These can appear with @l etc. in data.  */
+	case BFD_RELOC_LO16:
+	  if (fixP->fx_pcrel)
+	    fixP->fx_r_type = BFD_RELOC_LO16_PCREL;
+	case BFD_RELOC_LO16_PCREL:
+	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+			      value, 2);
+	  break;
+
+	case BFD_RELOC_HI16:
+	  if (fixP->fx_pcrel)
+	    fixP->fx_r_type = BFD_RELOC_HI16_PCREL;
+	case BFD_RELOC_HI16_PCREL:
+	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+			      PPC_HI (value), 2);
+	  break;
+
+	case BFD_RELOC_HI16_S:
+	  if (fixP->fx_pcrel)
+	    fixP->fx_r_type = BFD_RELOC_HI16_S_PCREL;
+	case BFD_RELOC_HI16_S_PCREL:
+	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+			      PPC_HA (value), 2);
+	  break;
+
+	case BFD_RELOC_PPC64_HIGHER:
+	  if (fixP->fx_pcrel)
+	    goto bad_pcrel;
+	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+			      PPC_HIGHER (value), 2);
+	  break;
+
+	case BFD_RELOC_PPC64_HIGHER_S:
+	  if (fixP->fx_pcrel)
+	    goto bad_pcrel;
+	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+			      PPC_HIGHERA (value), 2);
+	  break;
+
+	case BFD_RELOC_PPC64_HIGHEST:
+	  if (fixP->fx_pcrel)
+	    goto bad_pcrel;
+	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+			      PPC_HIGHEST (value), 2);
+	  break;
+
+	case BFD_RELOC_PPC64_HIGHEST_S:
+	  if (fixP->fx_pcrel)
+	    goto bad_pcrel;
+	  md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+			      PPC_HIGHESTA (value), 2);
+	  break;
+
+	case BFD_RELOC_PPC_DTPMOD:
+	case BFD_RELOC_PPC_TPREL:
+	case BFD_RELOC_PPC_DTPREL:
+	  S_SET_THREAD_LOCAL (fixP->fx_addsy);
+	  break;
+
+	  /* Just punt all of these to the linker.  */
+	case BFD_RELOC_PPC_B16_BRTAKEN:
+	case BFD_RELOC_PPC_B16_BRNTAKEN:
+	case BFD_RELOC_16_GOTOFF:
+	case BFD_RELOC_LO16_GOTOFF:
+	case BFD_RELOC_HI16_GOTOFF:
+	case BFD_RELOC_HI16_S_GOTOFF:
+	case BFD_RELOC_LO16_PLTOFF:
+	case BFD_RELOC_HI16_PLTOFF:
+	case BFD_RELOC_HI16_S_PLTOFF:
+	case BFD_RELOC_PPC_COPY:
+	case BFD_RELOC_PPC_GLOB_DAT:
+	case BFD_RELOC_16_BASEREL:
+	case BFD_RELOC_LO16_BASEREL:
+	case BFD_RELOC_HI16_BASEREL:
+	case BFD_RELOC_HI16_S_BASEREL:
+	case BFD_RELOC_PPC_TLS:
+	case BFD_RELOC_PPC_DTPREL16_LO:
+	case BFD_RELOC_PPC_DTPREL16_HI:
+	case BFD_RELOC_PPC_DTPREL16_HA:
+	case BFD_RELOC_PPC_TPREL16_LO:
+	case BFD_RELOC_PPC_TPREL16_HI:
+	case BFD_RELOC_PPC_TPREL16_HA:
+	case BFD_RELOC_PPC_GOT_TLSGD16:
+	case BFD_RELOC_PPC_GOT_TLSGD16_LO:
+	case BFD_RELOC_PPC_GOT_TLSGD16_HI:
+	case BFD_RELOC_PPC_GOT_TLSGD16_HA:
+	case BFD_RELOC_PPC_GOT_TLSLD16:
+	case BFD_RELOC_PPC_GOT_TLSLD16_LO:
+	case BFD_RELOC_PPC_GOT_TLSLD16_HI:
+	case BFD_RELOC_PPC_GOT_TLSLD16_HA:
+	case BFD_RELOC_PPC_GOT_DTPREL16:
+	case BFD_RELOC_PPC_GOT_DTPREL16_LO:
+	case BFD_RELOC_PPC_GOT_DTPREL16_HI:
+	case BFD_RELOC_PPC_GOT_DTPREL16_HA:
+	case BFD_RELOC_PPC_GOT_TPREL16:
+	case BFD_RELOC_PPC_GOT_TPREL16_LO:
+	case BFD_RELOC_PPC_GOT_TPREL16_HI:
+	case BFD_RELOC_PPC_GOT_TPREL16_HA:
+	case BFD_RELOC_24_PLT_PCREL:
+	case BFD_RELOC_PPC_LOCAL24PC:
+	case BFD_RELOC_32_PLT_PCREL:
+	case BFD_RELOC_GPREL16:
+	case BFD_RELOC_PPC_VLE_SDAREL_LO16A:
+	case BFD_RELOC_PPC_VLE_SDAREL_HI16A:
+	case BFD_RELOC_PPC_VLE_SDAREL_HA16A:
+	case BFD_RELOC_PPC_EMB_NADDR32:
+	case BFD_RELOC_PPC_EMB_NADDR16:
+	case BFD_RELOC_PPC_EMB_NADDR16_LO:
+	case BFD_RELOC_PPC_EMB_NADDR16_HI:
+	case BFD_RELOC_PPC_EMB_NADDR16_HA:
+	case BFD_RELOC_PPC_EMB_SDAI16:
+	case BFD_RELOC_PPC_EMB_SDA2REL:
+	case BFD_RELOC_PPC_EMB_SDA2I16:
+	case BFD_RELOC_PPC_EMB_SDA21:
+	case BFD_RELOC_PPC_VLE_SDA21_LO:
+	case BFD_RELOC_PPC_EMB_MRKREF:
+	case BFD_RELOC_PPC_EMB_RELSEC16:
+	case BFD_RELOC_PPC_EMB_RELST_LO:
+	case BFD_RELOC_PPC_EMB_RELST_HI:
+	case BFD_RELOC_PPC_EMB_RELST_HA:
+	case BFD_RELOC_PPC_EMB_BIT_FLD:
+	case BFD_RELOC_PPC_EMB_RELSDA:
 	case BFD_RELOC_PPC64_TOC:
+	case BFD_RELOC_PPC_TOC16:
+	case BFD_RELOC_PPC64_TOC16_LO:
+	case BFD_RELOC_PPC64_TOC16_HI:
+	case BFD_RELOC_PPC64_TOC16_HA:
+	case BFD_RELOC_PPC64_DTPREL16_HIGHER:
+	case BFD_RELOC_PPC64_DTPREL16_HIGHERA:
+	case BFD_RELOC_PPC64_DTPREL16_HIGHEST:
+	case BFD_RELOC_PPC64_DTPREL16_HIGHESTA:
+	case BFD_RELOC_PPC64_TPREL16_HIGHER:
+	case BFD_RELOC_PPC64_TPREL16_HIGHERA:
+	case BFD_RELOC_PPC64_TPREL16_HIGHEST:
+	case BFD_RELOC_PPC64_TPREL16_HIGHESTA:
 	  fixP->fx_done = 0;
 	  break;
 #endif
+
+#ifdef OBJ_XCOFF
+	case BFD_RELOC_NONE:
+	  break;
+#endif
+
 	default:
 	  fprintf (stderr,
 		   _("Gas failure, reloc value %d\n"), fixP->fx_r_type);
@@ -6932,6 +6854,7 @@ md_apply_fix (fixS *fixP, valueT *valP, 
     }
 
 #ifdef OBJ_ELF
+  ppc_elf_validate_fix (fixP, seg);
   fixP->fx_addnumber = value;
 
   /* PowerPC uses RELA relocs, ie. the reloc addend is stored separately

-- 
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]