* config/tc-ppc.c (md_chars_to_number): Delete.
authorAlan Modra <amodra@gmail.com>
Mon, 5 Nov 2012 10:00:12 +0000 (10:00 +0000)
committerAlan Modra <amodra@gmail.com>
Mon, 5 Nov 2012 10:00:12 +0000 (10:00 +0000)
(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.

gas/ChangeLog
gas/config/tc-ppc.c

index 082dfd60164b42064f2c19046c4d0a753608bc3c..17045c73394bfc9d0dca89194917d9b77653b6c3 100644 (file)
@@ -1,5 +1,16 @@
 2012-11-05  Alan Modra  <amodra@gmail.com>
 
+       * 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.
+
        * write.h (struct fix <fx_pcrel_adjust>): Make it a signed char.
        * config/tc-m68k.c (tc_gen_reloc, md_pcrel_from): Remove explicit
        sign extendion of fx_pxrel_adjust.
index 0f8da736d8018633e9cd9a20d83f2b23e9747bb3..2dc2f59af54757e15fbc15724d94733a9f099d8f 100644 (file)
@@ -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 +2426,25 @@ parse_toc_entry (enum toc_size_qualifier *toc_kind)
   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) */
 \f
 
 #ifdef OBJ_ELF
@@ -2533,9 +2527,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 +2808,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 +2874,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 +3115,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 +3184,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 +3284,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 +3310,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 +4857,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) */
 \f
 #ifdef TE_PE
@@ -6292,13 +6284,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 +6328,15 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       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 +6357,72 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
          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);
+         fieldval = SEX16 (PPC_HA (value));
          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:
-         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);
+#ifdef OBJ_ELF
+       case BFD_RELOC_PPC64_HIGHER:
+         if (fixP->fx_pcrel)
+           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);
+           goto bad_pcrel;
+         fieldval = SEX16 (PPC_HIGHESTA (value));
          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:
-         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 +6451,386 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
        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 +6840,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     }
 
 #ifdef OBJ_ELF
+  ppc_elf_validate_fix (fixP, seg);
   fixP->fx_addnumber = value;
 
   /* PowerPC uses RELA relocs, ie. the reloc addend is stored separately