Support R_SPARC_WDISP10 and R_SPARC_H34.
[external/binutils.git] / gas / config / tc-ppc.c
index c80dd18..0e7f017 100644 (file)
@@ -1,6 +1,7 @@
 /* tc-ppc.c -- Assemble for the PowerPC or POWER (RS/6000)
    Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-   2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+   2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+   Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of GAS, the GNU Assembler.
 #include "coff/pe.h"
 #endif
 
+#ifdef OBJ_XCOFF
+#include "coff/xcoff.h"
+#include "libxcoff.h"
+#endif
+
 /* This is the assembler for the PowerPC or POWER (RS/6000) chips.  */
 
 /* Tell the main code what the endianness is.  */
@@ -104,10 +110,12 @@ static void ppc_ec (int);
 static void ppc_ef (int);
 static void ppc_es (int);
 static void ppc_csect (int);
+static void ppc_dwsect (int);
 static void ppc_change_csect (symbolS *, offsetT);
 static void ppc_function (int);
 static void ppc_extern (int);
 static void ppc_lglobl (int);
+static void ppc_ref (int);
 static void ppc_section (int);
 static void ppc_named_section (int);
 static void ppc_stabx (int);
@@ -179,9 +187,19 @@ const char ppc_symbol_chars[] = "%[";
 /* The dwarf2 data alignment, adjusted for 32 or 64 bit.  */
 int ppc_cie_data_alignment;
 
+/* More than this number of nops in an alignment op gets a branch
+   instead.  */
+unsigned long nop_limit = 4;
+
 /* The type of processor we are assembling for.  This is one or more
    of the PPC_OPCODE flags defined in opcode/ppc.h.  */
 ppc_cpu_t ppc_cpu = 0;
+
+/* Flags set on encountering toc relocs.  */
+enum {
+  has_large_toc_reloc = 1,
+  has_small_toc_reloc = 2
+} toc_reloc_types;
 \f
 /* The target specific pseudo-ops which we support.  */
 
@@ -203,6 +221,7 @@ const pseudo_typeS md_pseudo_table[] =
   { "bi",      ppc_biei,       0 },
   { "bs",      ppc_bs,         0 },
   { "csect",   ppc_csect,      0 },
+  { "dwsect",  ppc_dwsect,     0 },
   { "data",    ppc_section,    'd' },
   { "eb",      ppc_eb,         0 },
   { "ec",      ppc_ec,         0 },
@@ -212,6 +231,7 @@ const pseudo_typeS md_pseudo_table[] =
   { "extern",  ppc_extern,     0 },
   { "function",        ppc_function,   0 },
   { "lglobl",  ppc_lglobl,     0 },
+  { "ref",     ppc_ref,        0 },
   { "rename",  ppc_rename,     0 },
   { "section", ppc_named_section, 0 },
   { "stabx",   ppc_stabx,      0 },
@@ -877,7 +897,7 @@ static const struct pd_reg cr_names[] =
    expression.  */
 
 int
-ppc_parse_name (const char *name, expressionS *expr)
+ppc_parse_name (const char *name, expressionS *exp)
 {
   int val;
 
@@ -891,8 +911,8 @@ ppc_parse_name (const char *name, expressionS *expr)
   if (val < 0)
     return 0;
 
-  expr->X_op = O_constant;
-  expr->X_add_number = val;
+  exp->X_op = O_constant;
+  exp->X_add_number = val;
 
   return 1;
 }
@@ -970,6 +990,28 @@ static symbolS *ppc_current_block;
    cause BFD to set the section number of a symbol to N_DEBUG.  */
 static asection *ppc_coff_debug_section;
 
+/* Structure to set the length field of the dwarf sections.  */
+struct dw_subsection {
+  /* Subsections are simply linked.  */
+  struct dw_subsection *link;
+
+  /* The subsection number.  */
+  subsegT subseg;
+
+  /* Expression to compute the length of the section.  */
+  expressionS end_exp;
+};
+
+static struct dw_section {
+  /* Corresponding section.  */
+  segT sect;
+
+  /* Simply linked list of subsections with a label.  */
+  struct dw_subsection *list_subseg;
+
+  /* The anonymous subsection.  */
+  struct dw_subsection *anon_subseg;
+} dw_sections[XCOFF_DWSECT_NBR_NAMES];
 #endif /* OBJ_XCOFF */
 
 #ifdef TE_PE
@@ -1010,162 +1052,18 @@ const char *const md_shortopts = "b:l:usm:K:VQ:";
 #else
 const char *const md_shortopts = "um:";
 #endif
+#define OPTION_NOPS (OPTION_MD_BASE + 0)
 const struct option md_longopts[] = {
+  {"nops", required_argument, NULL, OPTION_NOPS},
   {NULL, no_argument, NULL, 0}
 };
 const size_t md_longopts_size = sizeof (md_longopts);
 
-
-/* Handle -m options that set cpu type, and .machine arg.  */
-
-static int
-parse_cpu (const char *arg)
-{
-  ppc_cpu_t retain_flags =
-    ppc_cpu & (PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX | PPC_OPCODE_SPE);
-
-  /* -mpwrx and -mpwr2 mean to assemble for the IBM POWER/2
-     (RIOS2).  */
-  if (strcmp (arg, "pwrx") == 0 || strcmp (arg, "pwr2") == 0)
-    ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_POWER2 | PPC_OPCODE_32;
-  /* -mpwr means to assemble for the IBM POWER (RIOS1).  */
-  else if (strcmp (arg, "pwr") == 0)
-    ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_32;
-  /* -m601 means to assemble for the PowerPC 601, which includes
-     instructions that are holdovers from the Power.  */
-  else if (strcmp (arg, "601") == 0)
-    ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
-              | PPC_OPCODE_601 | PPC_OPCODE_32);
-  /* -mppc, -mppc32, -m603, and -m604 mean to assemble for the
-     PowerPC 603/604.  */
-  else if (strcmp (arg, "ppc") == 0
-          || strcmp (arg, "ppc32") == 0
-          || strcmp (arg, "603") == 0
-          || strcmp (arg, "604") == 0)
-    ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32;
-  /* Do all PPC750s have paired single ops?  */
-  else if (strcmp (arg, "750cl") == 0)
-    ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_PPCPS;
-  else if (strcmp (arg, "403") == 0)
-    ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
-              | PPC_OPCODE_403 | PPC_OPCODE_32);
-  else if (strcmp (arg, "405") == 0)
-    ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
-              | PPC_OPCODE_403 | PPC_OPCODE_405 | PPC_OPCODE_32);
-  else if (strcmp (arg, "440") == 0
-          || strcmp (arg, "464") == 0)
-    ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_32
-              | PPC_OPCODE_440 | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI);
-  else if (strcmp (arg, "7400") == 0
-          || strcmp (arg, "7410") == 0
-          || strcmp (arg, "7450") == 0
-          || strcmp (arg, "7455") == 0)
-    ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
-              | PPC_OPCODE_ALTIVEC | PPC_OPCODE_32);
-  else if (strcmp (arg, "e300") == 0)
-    ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32
-              | PPC_OPCODE_E300);
-  else if (strcmp (arg, "altivec") == 0)
-    {
-      if (ppc_cpu == 0)
-       ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC;
-
-      retain_flags |= PPC_OPCODE_ALTIVEC;
-    }
-  else if (strcmp (arg, "vsx") == 0)
-    {
-      if (ppc_cpu == 0)
-       ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC;
-
-      retain_flags |= PPC_OPCODE_VSX;
-    }
-  else if (strcmp (arg, "e500") == 0 || strcmp (arg, "e500x2") == 0)
-    {
-      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_SPE
-                | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
-                | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK
-                | PPC_OPCODE_RFMCI | PPC_OPCODE_E500MC);
-    }
-  else if (strcmp (arg, "e500mc") == 0)
-    {
-      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL
-                | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK
-                | PPC_OPCODE_RFMCI | PPC_OPCODE_E500MC);
-    }
-  else if (strcmp (arg, "spe") == 0)
-    {
-      if (ppc_cpu == 0)
-       ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_EFS;
-
-      retain_flags |= PPC_OPCODE_SPE;
-    }
-  /* -mppc64 and -m620 mean to assemble for the 64-bit PowerPC
-     620.  */
-  else if (strcmp (arg, "ppc64") == 0 || strcmp (arg, "620") == 0)
-    {
-      ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64;
-    }
-  else if (strcmp (arg, "ppc64bridge") == 0)
-    {
-      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
-                | PPC_OPCODE_64_BRIDGE | PPC_OPCODE_64);
-    }
-  /* -mbooke/-mbooke32 mean enable 32-bit BookE support.  */
-  else if (strcmp (arg, "booke") == 0 || strcmp (arg, "booke32") == 0)
-    {
-      ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_32;
-    }
-  else if (strcmp (arg, "power4") == 0)
-    {
-      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
-                | PPC_OPCODE_64 | PPC_OPCODE_POWER4);
-    }
-  else if (strcmp (arg, "power5") == 0)
-    {
-      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
-                | PPC_OPCODE_64 | PPC_OPCODE_POWER4
-                | PPC_OPCODE_POWER5);
-    }
-  else if (strcmp (arg, "power6") == 0)
-    {
-      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
-                | PPC_OPCODE_64 | PPC_OPCODE_POWER4
-                | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
-                | PPC_OPCODE_ALTIVEC);
-    }
-  else if (strcmp (arg, "power7") == 0)
-    {
-      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
-                | PPC_OPCODE_ISEL | PPC_OPCODE_64
-                | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5
-                | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7
-                | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX);
-    }
-  else if (strcmp (arg, "cell") == 0)
-    {
-      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
-                | PPC_OPCODE_64 | PPC_OPCODE_POWER4
-                | PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC);
-    }
-  /* -mcom means assemble for the common intersection between Power
-     and PowerPC.  At present, we just allow the union, rather
-     than the intersection.  */
-  else if (strcmp (arg, "com") == 0)
-    ppc_cpu = PPC_OPCODE_COMMON | PPC_OPCODE_32;
-  /* -many means to assemble for any architecture (PWR/PWRX/PPC).  */
-  else if (strcmp (arg, "any") == 0)
-    ppc_cpu |= PPC_OPCODE_ANY;
-  else
-    return 0;
-
-  /* Make sure the the Altivec, VSX and SPE bits are not lost.  */
-  ppc_cpu |= retain_flags;
-  return 1;
-}
-
 int
 md_parse_option (int c, char *arg)
 {
+  ppc_cpu_t new_cpu;
+
   switch (c)
     {
     case 'u':
@@ -1228,8 +1126,8 @@ md_parse_option (int c, char *arg)
       break;
 
     case 'm':
-      if (parse_cpu (arg))
-       ;
+      if ((new_cpu = ppc_parse_cpu (ppc_cpu, arg)) != 0)
+       ppc_cpu = new_cpu;
 
       else if (strcmp (arg, "regnames") == 0)
        reg_names_p = TRUE;
@@ -1256,7 +1154,7 @@ md_parse_option (int c, char *arg)
       else if (strcmp (arg, "emb") == 0)
        ppc_flags |= EF_PPC_EMB;
 
-      /* -mlittle/-mbig set the endianess.  */
+      /* -mlittle/-mbig set the endianness.  */
       else if (strcmp (arg, "little") == 0
               || strcmp (arg, "little-endian") == 0)
        {
@@ -1310,6 +1208,15 @@ md_parse_option (int c, char *arg)
       break;
 #endif
 
+    case OPTION_NOPS:
+      {
+       char *end;
+       nop_limit = strtoul (optarg, &end, 0);
+       if (*end)
+         as_bad (_("--nops needs a numeric argument"));
+      }
+      break;
+
     default:
       return 0;
     }
@@ -1322,55 +1229,65 @@ md_show_usage (FILE *stream)
 {
   fprintf (stream, _("\
 PowerPC options:\n\
--a32                   generate ELF32/XCOFF32\n\
--a64                   generate ELF64/XCOFF64\n\
--u                     ignored\n\
--mpwrx, -mpwr2         generate code for POWER/2 (RIOS2)\n\
--mpwr                  generate code for POWER (RIOS1)\n\
--m601                  generate code for PowerPC 601\n\
+-a32                    generate ELF32/XCOFF32\n\
+-a64                    generate ELF64/XCOFF64\n\
+-u                      ignored\n\
+-mpwrx, -mpwr2          generate code for POWER/2 (RIOS2)\n\
+-mpwr                   generate code for POWER (RIOS1)\n\
+-m601                   generate code for PowerPC 601\n\
 -mppc, -mppc32, -m603, -m604\n\
-                       generate code for PowerPC 603/604\n\
--m403                  generate code for PowerPC 403\n\
--m405                  generate code for PowerPC 405\n\
--m440                  generate code for PowerPC 440\n\
--m464                  generate code for PowerPC 464\n\
+                        generate code for PowerPC 603/604\n\
+-m403                   generate code for PowerPC 403\n\
+-m405                   generate code for PowerPC 405\n\
+-m440                   generate code for PowerPC 440\n\
+-m464                   generate code for PowerPC 464\n\
+-m476                   generate code for PowerPC 476\n\
 -m7400, -m7410, -m7450, -m7455\n\
-                       generate code for PowerPC 7400/7410/7450/7455\n\
--m750cl                        generate code for PowerPC 750cl\n"));
+                        generate code for PowerPC 7400/7410/7450/7455\n\
+-m750cl                 generate code for PowerPC 750cl\n"));
   fprintf (stream, _("\
--mppc64, -m620         generate code for PowerPC 620/625/630\n\
--mppc64bridge          generate code for PowerPC 64, including bridge insns\n\
--mbooke                        generate code for 32-bit PowerPC BookE\n\
--mpower4               generate code for Power4 architecture\n\
--mpower5               generate code for Power5 architecture\n\
--mpower6               generate code for Power6 architecture\n\
--mpower7               generate code for Power7 architecture\n\
--mcell                 generate code for Cell Broadband Engine architecture\n\
--mcom                  generate code Power/PowerPC common instructions\n\
--many                  generate code for any architecture (PWR/PWRX/PPC)\n"));
+-mppc64, -m620          generate code for PowerPC 620/625/630\n\
+-mppc64bridge           generate code for PowerPC 64, including bridge insns\n\
+-mbooke                 generate code for 32-bit PowerPC BookE\n\
+-ma2                    generate code for A2 architecture\n\
+-mpower4, -mpwr4        generate code for Power4 architecture\n\
+-mpower5, -mpwr5, -mpwr5x\n\
+                        generate code for Power5 architecture\n\
+-mpower6, -mpwr6        generate code for Power6 architecture\n\
+-mpower7, -mpwr7        generate code for Power7 architecture\n\
+-mcell                  generate code for Cell Broadband Engine architecture\n\
+-mcom                   generate code Power/PowerPC common instructions\n\
+-many                   generate code for any architecture (PWR/PWRX/PPC)\n"));
   fprintf (stream, _("\
--maltivec              generate code for AltiVec\n\
--mvsx                  generate code for Vector-Scalar (VSX) instructions\n\
--me300                 generate code for PowerPC e300 family\n\
--me500, -me500x2       generate code for Motorola e500 core complex\n\
+-maltivec               generate code for AltiVec\n\
+-mvsx                   generate code for Vector-Scalar (VSX) instructions\n\
+-me300                  generate code for PowerPC e300 family\n\
+-me500, -me500x2        generate code for Motorola e500 core complex\n\
 -me500mc,               generate code for Freescale e500mc core complex\n\
--mspe                  generate code for Motorola SPE instructions\n\
--mregnames             Allow symbolic names for registers\n\
--mno-regnames          Do not allow symbolic names for registers\n"));
+-me500mc64,             generate code for Freescale e500mc64 core complex\n\
+-me5500,                generate code for Freescale e5500 core complex\n\
+-me6500,                generate code for Freescale e6500 core complex\n\
+-mspe                   generate code for Motorola SPE instructions\n\
+-mtitan                 generate code for AppliedMicro Titan core complex\n\
+-mregnames              Allow symbolic names for registers\n\
+-mno-regnames           Do not allow symbolic names for registers\n"));
 #ifdef OBJ_ELF
   fprintf (stream, _("\
--mrelocatable          support for GCC's -mrelocatble option\n\
--mrelocatable-lib      support for GCC's -mrelocatble-lib option\n\
--memb                  set PPC_EMB bit in ELF flags\n\
--mlittle, -mlittle-endian, -l, -le\n\
-                       generate code for a little endian machine\n\
--mbig, -mbig-endian, -b, -be\n\
-                       generate code for a big endian machine\n\
--msolaris              generate code for Solaris\n\
--mno-solaris           do not generate code for Solaris\n\
--V                     print assembler version number\n\
--Qy, -Qn               ignored\n"));
+-mrelocatable           support for GCC's -mrelocatble option\n\
+-mrelocatable-lib       support for GCC's -mrelocatble-lib option\n\
+-memb                   set PPC_EMB bit in ELF flags\n\
+-mlittle, -mlittle-endian, -le\n\
+                        generate code for a little endian machine\n\
+-mbig, -mbig-endian, -be\n\
+                        generate code for a big endian machine\n\
+-msolaris               generate code for Solaris\n\
+-mno-solaris            do not generate code for Solaris\n\
+-K PIC                  set EF_PPC_RELOCATABLE_LIB in ELF flags\n\
+-V                      print assembler version number\n\
+-Qy, -Qn                ignored\n"));
 #endif
+  fprintf (stream, _("\
+-nops=count             when aligning, more than COUNT nops uses a branch\n"));
 }
 \f
 /* Set ppc_cpu if it is not already set.  */
@@ -1381,19 +1298,19 @@ ppc_set_cpu (void)
   const char *default_os  = TARGET_OS;
   const char *default_cpu = TARGET_CPU;
 
-  if ((ppc_cpu & ~PPC_OPCODE_ANY) == 0)
+  if ((ppc_cpu & ~(ppc_cpu_t) PPC_OPCODE_ANY) == 0)
     {
       if (ppc_obj64)
-       ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64;
+       ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_64;
       else if (strncmp (default_os, "aix", 3) == 0
               && default_os[3] >= '4' && default_os[3] <= '9')
-       ppc_cpu |= PPC_OPCODE_COMMON | PPC_OPCODE_32;
+       ppc_cpu |= PPC_OPCODE_COMMON;
       else if (strncmp (default_os, "aix3", 4) == 0)
-       ppc_cpu |= PPC_OPCODE_POWER | PPC_OPCODE_32;
+       ppc_cpu |= PPC_OPCODE_POWER;
       else if (strcmp (default_cpu, "rs6000") == 0)
-       ppc_cpu |= PPC_OPCODE_POWER | PPC_OPCODE_32;
+       ppc_cpu |= PPC_OPCODE_POWER;
       else if (strncmp (default_cpu, "powerpc", 7) == 0)
-       ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32;
+       ppc_cpu |= PPC_OPCODE_PPC;
       else
        as_fatal (_("Unknown default cpu = %s, os = %s"),
                  default_cpu, default_os);
@@ -1432,6 +1349,8 @@ ppc_mach (void)
     return bfd_mach_ppc64;
   else if (ppc_arch () == bfd_arch_rs6000)
     return bfd_mach_rs6k;
+  else if (ppc_cpu & PPC_OPCODE_TITAN)
+    return bfd_mach_ppc_titan;
   else
     return bfd_mach_ppc;
 }
@@ -1446,14 +1365,16 @@ ppc_target_format (void)
   return "xcoff-powermac";
 #else
 #  ifdef TE_AIX5
-    return (ppc_obj64 ? "aix5coff64-rs6000" : "aixcoff-rs6000");
+  return (ppc_obj64 ? "aix5coff64-rs6000" : "aixcoff-rs6000");
 #  else
-    return (ppc_obj64 ? "aixcoff64-rs6000" : "aixcoff-rs6000");
+  return (ppc_obj64 ? "aixcoff64-rs6000" : "aixcoff-rs6000");
 #  endif
 #endif
 #endif
 #ifdef OBJ_ELF
-# ifdef TE_VXWORKS
+# ifdef TE_FreeBSD
+  return (ppc_obj64 ? "elf64-powerpc-freebsd" : "elf32-powerpc-freebsd");
+# elif defined (TE_VXWORKS)
   return "elf32-powerpc-vxworks";
 # else
   return (target_big_endian
@@ -1604,11 +1525,7 @@ ppc_setup_opcodes (void)
              }
        }
 
-      if ((op->flags & ppc_cpu & ~(PPC_OPCODE_32 | PPC_OPCODE_64)) != 0
-         && ((op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64)) == 0
-             || ((op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64))
-                 == (ppc_cpu & (PPC_OPCODE_32 | PPC_OPCODE_64)))
-             || (ppc_cpu & PPC_OPCODE_64_BRIDGE) != 0)
+      if ((ppc_cpu & op->flags) != 0
          && !(ppc_cpu & op->deprecated))
        {
          const char *retval;
@@ -1616,11 +1533,6 @@ ppc_setup_opcodes (void)
          retval = hash_insert (ppc_hash, op->name, (void *) op);
          if (retval != NULL)
            {
-             /* Ignore Power duplicates for -m601.  */
-             if ((ppc_cpu & PPC_OPCODE_601) != 0
-                 && (op->flags & PPC_OPCODE_POWER) != 0)
-               continue;
-
              as_bad (_("duplicate instruction %s"),
                      op->name);
              bad_insn = TRUE;
@@ -1638,7 +1550,7 @@ ppc_setup_opcodes (void)
   macro_end = powerpc_macros + powerpc_num_macros;
   for (macro = powerpc_macros; macro < macro_end; macro++)
     {
-      if ((macro->flags & ppc_cpu) != 0)
+      if ((macro->flags & ppc_cpu) != 0 || (ppc_cpu & PPC_OPCODE_ANY) != 0)
        {
          const char *retval;
 
@@ -1768,7 +1680,7 @@ static unsigned long
 ppc_insert_operand (unsigned long insn,
                    const struct powerpc_operand *operand,
                    offsetT val,
-                   ppc_cpu_t ppc_cpu,
+                   ppc_cpu_t cpu,
                    char *file,
                    unsigned int line)
 {
@@ -1827,7 +1739,7 @@ ppc_insert_operand (unsigned long insn,
       const char *errmsg;
 
       errmsg = NULL;
-      insn = (*operand->insert) (insn, (long) val, ppc_cpu, &errmsg);
+      insn = (*operand->insert) (insn, (long) val, cpu, &errmsg);
       if (errmsg != (const char *) NULL)
        as_bad_where (file, line, "%s", errmsg);
     }
@@ -1974,13 +1886,38 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p)
       {
        int reloc = ptr->reloc;
 
-       if (!ppc_obj64)
-         if (exp_p->X_add_number != 0
-             && (reloc == (int) BFD_RELOC_16_GOTOFF
-                 || reloc == (int) BFD_RELOC_LO16_GOTOFF
-                 || reloc == (int) BFD_RELOC_HI16_GOTOFF
-                 || reloc == (int) BFD_RELOC_HI16_S_GOTOFF))
-           as_warn (_("identifier+constant@got means identifier@got+constant"));
+       if (!ppc_obj64 && exp_p->X_add_number != 0)
+         {
+           switch (reloc)
+             {
+             case BFD_RELOC_16_GOTOFF:
+             case BFD_RELOC_LO16_GOTOFF:
+             case BFD_RELOC_HI16_GOTOFF:
+             case BFD_RELOC_HI16_S_GOTOFF:
+               as_warn (_("identifier+constant@got means "
+                          "identifier@got+constant"));
+               break;
+
+             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:
+               as_bad (_("symbol+offset not supported for got tls"));
+               break;
+             }
+         }
 
        /* Now check for identifier@suffix+constant.  */
        if (*str == '-' || *str == '+')
@@ -2055,6 +1992,7 @@ ppc_elf_cons (int nbytes /* 1=.byte, 2=.word, 4=.long, 8=.llong */)
              int offset;
 
              p = frag_more (nbytes);
+             memset (p, 0, nbytes);
              offset = 0;
              if (target_big_endian)
                offset = nbytes - size;
@@ -2279,6 +2217,7 @@ ppc_frob_file_before_adjust (void)
 
   toc = bfd_get_section_by_name (stdoutput, ".toc");
   if (toc != NULL
+      && toc_reloc_types != has_large_toc_reloc
       && bfd_section_size (stdoutput, toc) > 0x10000)
     as_warn (_("TOC section size exceeds 64k"));
 
@@ -2500,7 +2439,6 @@ md_assemble (char *str)
        {
          unsigned int opcount;
          unsigned int num_operands_expected;
-         unsigned int i;
 
          /* There is an optional operand.  Count the number of
             commas in the input line.  */
@@ -2648,7 +2586,7 @@ md_assemble (char *str)
                 explain.  */
              if (ex.X_op == O_symbol)
                {
-                 assert (ex.X_add_symbol != NULL);
+                 gas_assert (ex.X_add_symbol != NULL);
                  if (symbol_get_bfdsym (ex.X_add_symbol)->section
                      != tocdata_section)
                    {
@@ -2797,121 +2735,189 @@ md_assemble (char *str)
                                     ppc_cpu, (char *) NULL, 0);
        }
 #ifdef OBJ_ELF
-      else if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
+      else
        {
-         /* Some TLS tweaks.  */
-         switch (reloc)
+         if (ex.X_op == O_symbol && str[0] == '(')
            {
-           default:
-             break;
-           case BFD_RELOC_PPC_TLS:
-             insn = ppc_insert_operand (insn, operand, ppc_obj64 ? 13 : 2,
-                                        ppc_cpu, (char *) NULL, 0);
-             break;
-         /* We'll only use the 32 (or 64) bit form of these relocations
-            in constants.  Instructions get the 16 bit form.  */
-           case BFD_RELOC_PPC_DTPREL:
-             reloc = BFD_RELOC_PPC_DTPREL16;
-             break;
-           case BFD_RELOC_PPC_TPREL:
-             reloc = BFD_RELOC_PPC_TPREL16;
-             break;
+             const char *sym_name = S_GET_NAME (ex.X_add_symbol);
+             if (sym_name[0] == '.')
+               ++sym_name;
+
+             if (strcasecmp (sym_name, "__tls_get_addr") == 0)
+               {
+                 expressionS tls_exp;
+
+                 hold = input_line_pointer;
+                 input_line_pointer = str + 1;
+                 expression (&tls_exp);
+                 if (tls_exp.X_op == O_symbol)
+                   {
+                     reloc = BFD_RELOC_UNUSED;
+                     if (strncasecmp (input_line_pointer, "@tlsgd)", 7) == 0)
+                       {
+                         reloc = BFD_RELOC_PPC_TLSGD;
+                         input_line_pointer += 7;
+                       }
+                     else if (strncasecmp (input_line_pointer, "@tlsld)", 7) == 0)
+                       {
+                         reloc = BFD_RELOC_PPC_TLSLD;
+                         input_line_pointer += 7;
+                       }
+                     if (reloc != BFD_RELOC_UNUSED)
+                       {
+                         SKIP_WHITESPACE ();
+                         str = input_line_pointer;
+
+                         if (fc >= MAX_INSN_FIXUPS)
+                           as_fatal (_("too many fixups"));
+                         fixups[fc].exp = tls_exp;
+                         fixups[fc].opindex = *opindex_ptr;
+                         fixups[fc].reloc = reloc;
+                         ++fc;
+                       }
+                   }
+                 input_line_pointer = hold;
+               }
            }
 
-         /* For the absolute forms of branches, convert the PC
-            relative form back into the absolute.  */
-         if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
+         if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
            {
+             /* Some TLS tweaks.  */
              switch (reloc)
                {
-               case BFD_RELOC_PPC_B26:
-                 reloc = BFD_RELOC_PPC_BA26;
-                 break;
-               case BFD_RELOC_PPC_B16:
-                 reloc = BFD_RELOC_PPC_BA16;
+               default:
                  break;
-               case BFD_RELOC_PPC_B16_BRTAKEN:
-                 reloc = BFD_RELOC_PPC_BA16_BRTAKEN;
+
+               case BFD_RELOC_PPC_TLS:
+                 if (!_bfd_elf_ppc_at_tls_transform (opcode->opcode, 0))
+                   as_bad (_("@tls may not be used with \"%s\" operands"),
+                           opcode->name);
+                 else if (operand->shift != 11)
+                   as_bad (_("@tls may only be used in last operand"));
+                 else
+                   insn = ppc_insert_operand (insn, operand,
+                                              ppc_obj64 ? 13 : 2,
+                                              ppc_cpu, (char *) NULL, 0);
                  break;
-               case BFD_RELOC_PPC_B16_BRNTAKEN:
-                 reloc = BFD_RELOC_PPC_BA16_BRNTAKEN;
+
+                 /* We'll only use the 32 (or 64) bit form of these relocations
+                    in constants.  Instructions get the 16 bit form.  */
+               case BFD_RELOC_PPC_DTPREL:
+                 reloc = BFD_RELOC_PPC_DTPREL16;
                  break;
-               default:
+               case BFD_RELOC_PPC_TPREL:
+                 reloc = BFD_RELOC_PPC_TPREL16;
                  break;
                }
-           }
 
-         if (ppc_obj64
-             && (operand->flags & (PPC_OPERAND_DS | PPC_OPERAND_DQ)) != 0)
-           {
+             /* For the absolute forms of branches, convert the PC
+                relative form back into the absolute.  */
+             if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
+               {
+                 switch (reloc)
+                   {
+                   case BFD_RELOC_PPC_B26:
+                     reloc = BFD_RELOC_PPC_BA26;
+                     break;
+                   case BFD_RELOC_PPC_B16:
+                     reloc = BFD_RELOC_PPC_BA16;
+                     break;
+                   case BFD_RELOC_PPC_B16_BRTAKEN:
+                     reloc = BFD_RELOC_PPC_BA16_BRTAKEN;
+                     break;
+                   case BFD_RELOC_PPC_B16_BRNTAKEN:
+                     reloc = BFD_RELOC_PPC_BA16_BRNTAKEN;
+                     break;
+                   default:
+                     break;
+                   }
+               }
+
              switch (reloc)
                {
-               case BFD_RELOC_16:
-                 reloc = BFD_RELOC_PPC64_ADDR16_DS;
-                 break;
-               case BFD_RELOC_LO16:
-                 reloc = BFD_RELOC_PPC64_ADDR16_LO_DS;
-                 break;
-               case BFD_RELOC_16_GOTOFF:
-                 reloc = BFD_RELOC_PPC64_GOT16_DS;
-                 break;
-               case BFD_RELOC_LO16_GOTOFF:
-                 reloc = BFD_RELOC_PPC64_GOT16_LO_DS;
-                 break;
-               case BFD_RELOC_LO16_PLTOFF:
-                 reloc = BFD_RELOC_PPC64_PLT16_LO_DS;
-                 break;
-               case BFD_RELOC_16_BASEREL:
-                 reloc = BFD_RELOC_PPC64_SECTOFF_DS;
-                 break;
-               case BFD_RELOC_LO16_BASEREL:
-                 reloc = BFD_RELOC_PPC64_SECTOFF_LO_DS;
-                 break;
                case BFD_RELOC_PPC_TOC16:
-                 reloc = BFD_RELOC_PPC64_TOC16_DS;
+                 toc_reloc_types |= has_small_toc_reloc;
                  break;
                case BFD_RELOC_PPC64_TOC16_LO:
-                 reloc = BFD_RELOC_PPC64_TOC16_LO_DS;
-                 break;
-               case BFD_RELOC_PPC64_PLTGOT16:
-                 reloc = BFD_RELOC_PPC64_PLTGOT16_DS;
-                 break;
-               case BFD_RELOC_PPC64_PLTGOT16_LO:
-                 reloc = BFD_RELOC_PPC64_PLTGOT16_LO_DS;
-                 break;
-               case BFD_RELOC_PPC_DTPREL16:
-                 reloc = BFD_RELOC_PPC64_DTPREL16_DS;
-                 break;
-               case BFD_RELOC_PPC_DTPREL16_LO:
-                 reloc = BFD_RELOC_PPC64_DTPREL16_LO_DS;
-                 break;
-               case BFD_RELOC_PPC_TPREL16:
-                 reloc = BFD_RELOC_PPC64_TPREL16_DS;
-                 break;
-               case BFD_RELOC_PPC_TPREL16_LO:
-                 reloc = BFD_RELOC_PPC64_TPREL16_LO_DS;
-                 break;
-               case BFD_RELOC_PPC_GOT_DTPREL16:
-               case BFD_RELOC_PPC_GOT_DTPREL16_LO:
-               case BFD_RELOC_PPC_GOT_TPREL16:
-               case BFD_RELOC_PPC_GOT_TPREL16_LO:
+               case BFD_RELOC_PPC64_TOC16_HI:
+               case BFD_RELOC_PPC64_TOC16_HA:
+                 toc_reloc_types |= has_large_toc_reloc;
                  break;
                default:
-                 as_bad (_("unsupported relocation for DS offset field"));
                  break;
                }
+
+             if (ppc_obj64
+                 && (operand->flags & (PPC_OPERAND_DS | PPC_OPERAND_DQ)) != 0)
+               {
+                 switch (reloc)
+                   {
+                   case BFD_RELOC_16:
+                     reloc = BFD_RELOC_PPC64_ADDR16_DS;
+                     break;
+                   case BFD_RELOC_LO16:
+                     reloc = BFD_RELOC_PPC64_ADDR16_LO_DS;
+                     break;
+                   case BFD_RELOC_16_GOTOFF:
+                     reloc = BFD_RELOC_PPC64_GOT16_DS;
+                     break;
+                   case BFD_RELOC_LO16_GOTOFF:
+                     reloc = BFD_RELOC_PPC64_GOT16_LO_DS;
+                     break;
+                   case BFD_RELOC_LO16_PLTOFF:
+                     reloc = BFD_RELOC_PPC64_PLT16_LO_DS;
+                     break;
+                   case BFD_RELOC_16_BASEREL:
+                     reloc = BFD_RELOC_PPC64_SECTOFF_DS;
+                     break;
+                   case BFD_RELOC_LO16_BASEREL:
+                     reloc = BFD_RELOC_PPC64_SECTOFF_LO_DS;
+                     break;
+                   case BFD_RELOC_PPC_TOC16:
+                     reloc = BFD_RELOC_PPC64_TOC16_DS;
+                     break;
+                   case BFD_RELOC_PPC64_TOC16_LO:
+                     reloc = BFD_RELOC_PPC64_TOC16_LO_DS;
+                     break;
+                   case BFD_RELOC_PPC64_PLTGOT16:
+                     reloc = BFD_RELOC_PPC64_PLTGOT16_DS;
+                     break;
+                   case BFD_RELOC_PPC64_PLTGOT16_LO:
+                     reloc = BFD_RELOC_PPC64_PLTGOT16_LO_DS;
+                     break;
+                   case BFD_RELOC_PPC_DTPREL16:
+                     reloc = BFD_RELOC_PPC64_DTPREL16_DS;
+                     break;
+                   case BFD_RELOC_PPC_DTPREL16_LO:
+                     reloc = BFD_RELOC_PPC64_DTPREL16_LO_DS;
+                     break;
+                   case BFD_RELOC_PPC_TPREL16:
+                     reloc = BFD_RELOC_PPC64_TPREL16_DS;
+                     break;
+                   case BFD_RELOC_PPC_TPREL16_LO:
+                     reloc = BFD_RELOC_PPC64_TPREL16_LO_DS;
+                     break;
+                   case BFD_RELOC_PPC_GOT_DTPREL16:
+                   case BFD_RELOC_PPC_GOT_DTPREL16_LO:
+                   case BFD_RELOC_PPC_GOT_TPREL16:
+                   case BFD_RELOC_PPC_GOT_TPREL16_LO:
+                     break;
+                   default:
+                     as_bad (_("unsupported relocation for DS offset field"));
+                     break;
+                   }
+               }
            }
 
          /* 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 = 0;
+         fixups[fc].opindex = *opindex_ptr;
          fixups[fc].reloc = reloc;
          ++fc;
        }
-#endif /* OBJ_ELF */
-
+#else /* OBJ_ELF */
       else
        {
          /* We need to generate a fixup for this expression.  */
@@ -2922,6 +2928,7 @@ md_assemble (char *str)
          fixups[fc].reloc = BFD_RELOC_UNUSED;
          ++fc;
        }
+#endif /* OBJ_ELF */
 
       if (need_paren)
        {
@@ -2949,7 +2956,10 @@ md_assemble (char *str)
       if (*str != endc
          && (endc != ',' || *str != '\0'))
        {
-         as_bad (_("syntax error; found `%c' but expected `%c'"), *str, endc);
+         if (*str == '\0')
+           as_bad (_("syntax error; end of line, expected `%c'"), endc);
+         else
+           as_bad (_("syntax error; found `%c', expected `%c'"), *str, endc);
          break;
        }
 
@@ -2965,7 +2975,7 @@ md_assemble (char *str)
 
 #ifdef OBJ_ELF
   /* Do we need/want a APUinfo section? */
-  if ((ppc_cpu & PPC_OPCODE_E500MC) != 0)
+  if ((ppc_cpu & (PPC_OPCODE_E500 | PPC_OPCODE_E500MC)) != 0)
     {
       /* These are all version "1".  */
       if (opcode->flags & PPC_OPCODE_SPE)
@@ -3006,9 +3016,6 @@ md_assemble (char *str)
      md_apply_fix.  */
   for (i = 0; i < fc; i++)
     {
-      const struct powerpc_operand *operand;
-
-      operand = &powerpc_operands[fixups[i].opindex];
       if (fixups[i].reloc != BFD_RELOC_UNUSED)
        {
          reloc_howto_type *reloc_howto;
@@ -3055,13 +3062,18 @@ md_assemble (char *str)
            }
        }
       else
-       fix_new_exp (frag_now,
-                    f - frag_now->fr_literal,
-                    4,
-                    &fixups[i].exp,
-                    (operand->flags & PPC_OPERAND_RELATIVE) != 0,
-                    ((bfd_reloc_code_real_type)
-                     (fixups[i].opindex + (int) BFD_RELOC_UNUSED)));
+       {
+         const struct powerpc_operand *operand;
+
+         operand = &powerpc_operands[fixups[i].opindex];
+         fix_new_exp (frag_now,
+                      f - frag_now->fr_literal,
+                      4,
+                      &fixups[i].exp,
+                      (operand->flags & PPC_OPERAND_RELATIVE) != 0,
+                      ((bfd_reloc_code_real_type)
+                       (fixups[i].opindex + (int) BFD_RELOC_UNUSED)));
+       }
     }
 }
 
@@ -3144,26 +3156,7 @@ ppc_macro (char *str, const struct powerpc_macro *macro)
 }
 \f
 #ifdef OBJ_ELF
-/* For ELF, add support for SHF_EXCLUDE and SHT_ORDERED.  */
-
-bfd_vma
-ppc_section_letter (int letter, char **ptr_msg)
-{
-  if (letter == 'e')
-    return SHF_EXCLUDE;
-
-  *ptr_msg = _("Bad .section directive: want a,e,w,x,M,S,G,T in string");
-  return -1;
-}
-
-bfd_vma
-ppc_section_word (char *str, size_t len)
-{
-  if (len == 7 && strncmp (str, "exclude", 7) == 0)
-    return SHF_EXCLUDE;
-
-  return -1;
-}
+/* For ELF, add support for SHT_ORDERED.  */
 
 int
 ppc_section_type (char *str, size_t len)
@@ -3175,14 +3168,11 @@ ppc_section_type (char *str, size_t len)
 }
 
 int
-ppc_section_flags (flagword flags, bfd_vma attr, int type)
+ppc_section_flags (flagword flags, bfd_vma attr ATTRIBUTE_UNUSED, int type)
 {
   if (type == SHT_ORDERED)
     flags |= SEC_ALLOC | SEC_LOAD | SEC_SORT_ENTRIES;
 
-  if (attr & SHF_EXCLUDE)
-    flags |= SEC_EXCLUDE;
-
   return flags;
 }
 #endif /* OBJ_ELF */
@@ -3409,7 +3399,7 @@ ppc_csect (int ignore ATTRIBUTE_UNUSED)
   if (S_GET_NAME (sym)[0] == '\0')
     {
       /* An unnamed csect is assumed to be [PR].  */
-      symbol_get_tc (sym)->class = XMC_PR;
+      symbol_get_tc (sym)->symbol_class = XMC_PR;
     }
 
   align = 2;
@@ -3445,7 +3435,7 @@ ppc_change_csect (symbolS *sym, offsetT align)
         data section.  */
       after_toc = 0;
       is_code = 0;
-      switch (symbol_get_tc (sym)->class)
+      switch (symbol_get_tc (sym)->symbol_class)
        {
        case XMC_PR:
        case XMC_RO:
@@ -3522,6 +3512,158 @@ ppc_change_csect (symbolS *sym, offsetT align)
   ppc_current_csect = sym;
 }
 
+static void
+ppc_change_debug_section (unsigned int idx, subsegT subseg)
+{
+  segT sec;
+  flagword oldflags;
+  const struct xcoff_dwsect_name *dw = &xcoff_dwsect_names[idx];
+
+  sec = subseg_new (dw->name, subseg);
+  oldflags = bfd_get_section_flags (stdoutput, sec);
+  if (oldflags == SEC_NO_FLAGS)
+    {
+      /* Just created section.  */
+      gas_assert (dw_sections[idx].sect == NULL);
+
+      bfd_set_section_flags (stdoutput, sec, SEC_DEBUGGING);
+      bfd_set_section_alignment (stdoutput, sec, 0);
+      dw_sections[idx].sect = sec;
+    }
+
+  /* Not anymore in a csect.  */
+  ppc_current_csect = NULL;
+}
+
+/* The .dwsect pseudo-op.  Defines a DWARF section.  Syntax is:
+     .dwsect flag [, opt-label ]
+*/
+
+static void
+ppc_dwsect (int ignore ATTRIBUTE_UNUSED)
+{
+  offsetT flag;
+  symbolS *opt_label;
+  const struct xcoff_dwsect_name *dw;
+  struct dw_subsection *subseg;
+  struct dw_section *dws;
+  int i;
+
+  /* Find section.  */
+  flag = get_absolute_expression ();
+  dw = NULL;
+  for (i = 0; i < XCOFF_DWSECT_NBR_NAMES; i++)
+    if (xcoff_dwsect_names[i].flag == flag)
+      {
+        dw = &xcoff_dwsect_names[i];
+        break;
+      }
+
+  /* Parse opt-label.  */
+  if (*input_line_pointer == ',')
+    {
+      const char *label;
+      char c;
+
+      ++input_line_pointer;
+
+      label = input_line_pointer;
+      c = get_symbol_end ();
+      opt_label = symbol_find_or_make (label);
+      *input_line_pointer = c;
+    }
+  else
+    opt_label = NULL;
+
+  demand_empty_rest_of_line ();
+
+  /* Return now in case of unknown subsection.  */
+  if (dw == NULL)
+    {
+      as_bad (_("No known dwarf XCOFF section for flag 0x%08x\n"),
+              (unsigned)flag);
+      return;
+    }
+
+  /* Find the subsection.  */
+  dws = &dw_sections[i];
+  subseg = NULL;
+  if (opt_label != NULL && S_IS_DEFINED (opt_label))
+    {
+      /* Sanity check (note that in theory S_GET_SEGMENT mustn't be null).  */
+      if (dws->sect == NULL || S_GET_SEGMENT (opt_label) != dws->sect)
+        {
+          as_bad (_("label %s was not defined in this dwarf section"),
+                  S_GET_NAME (opt_label));
+          subseg = dws->anon_subseg;
+          opt_label = NULL;
+        }
+      else
+        subseg = symbol_get_tc (opt_label)->u.dw;
+    }
+
+  if (subseg != NULL)
+    {
+      /* Switch to the subsection.  */
+      ppc_change_debug_section (i, subseg->subseg);
+    }
+  else
+    {
+      /* Create a new dw subsection.  */
+      subseg = (struct dw_subsection *)
+        xmalloc (sizeof (struct dw_subsection));
+
+      if (opt_label == NULL)
+        {
+          /* The anonymous one.  */
+          subseg->subseg = 0;
+          subseg->link = NULL;
+          dws->anon_subseg = subseg;
+        }
+      else
+        {
+          /* A named one.  */
+          if (dws->list_subseg != NULL)
+            subseg->subseg = dws->list_subseg->subseg + 1;
+          else
+            subseg->subseg = 1;
+
+          subseg->link = dws->list_subseg;
+          dws->list_subseg = subseg;
+          symbol_get_tc (opt_label)->u.dw = subseg;
+        }
+
+      ppc_change_debug_section (i, subseg->subseg);
+
+      if (dw->def_size)
+        {
+          /* Add the length field.  */
+          expressionS *exp = &subseg->end_exp;
+          int sz;
+
+          if (opt_label != NULL)
+            symbol_set_value_now (opt_label);
+
+          /* Add the length field.  Note that according to the AIX assembler
+             manual, the size of the length field is 4 for powerpc32 but
+             12 for powerpc64.  */
+          if (ppc_obj64)
+            {
+              /* Write the 64bit marker.  */
+              md_number_to_chars (frag_more (4), -1, 4);
+            }
+
+          exp->X_op = O_subtract;
+          exp->X_op_symbol = symbol_temp_new_now ();
+          exp->X_add_symbol = symbol_temp_make ();
+
+          sz = ppc_obj64 ? 8 : 4;
+          exp->X_add_number = -sz;
+          emit_expr (exp, sz);
+        }
+    }
+}
+
 /* This function handles the .text and .data pseudo-ops.  These
    pseudo-ops aren't really used by XCOFF; we implement them for the
    convenience of people who aren't used to XCOFF.  */
@@ -3621,6 +3763,58 @@ ppc_lglobl (int ignore ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
+/* The .ref pseudo-op.  It takes a list of symbol names and inserts R_REF
+   relocations at the beginning of the current csect.
+
+   (In principle, there's no reason why the relocations _have_ to be at
+   the beginning.  Anywhere in the csect would do.  However, inserting
+   at the beginning is what the native assmebler does, and it helps to
+   deal with cases where the .ref statements follow the section contents.)
+
+   ??? .refs don't work for empty .csects.  However, the native assembler
+   doesn't report an error in this case, and neither yet do we.  */
+
+static void
+ppc_ref (int ignore ATTRIBUTE_UNUSED)
+{
+  char *name;
+  char c;
+
+  if (ppc_current_csect == NULL)
+    {
+      as_bad (_(".ref outside .csect"));
+      ignore_rest_of_line ();
+      return;
+    }
+
+  do
+    {
+      name = input_line_pointer;
+      c = get_symbol_end ();
+
+      fix_at_start (symbol_get_frag (ppc_current_csect), 0,
+                   symbol_find_or_make (name), 0, FALSE, BFD_RELOC_NONE);
+
+      *input_line_pointer = c;
+      SKIP_WHITESPACE ();
+      c = *input_line_pointer;
+      if (c == ',')
+       {
+         input_line_pointer++;
+         SKIP_WHITESPACE ();
+         if (is_end_of_line[(unsigned char) *input_line_pointer])
+           {
+             as_bad (_("missing symbol name"));
+             ignore_rest_of_line ();
+             return;
+           }
+       }
+    }
+  while (c == ',');
+
+  demand_empty_rest_of_line ();
+}
+
 /* The .rename pseudo-op.  The RS/6000 assembler can rename symbols,
    although I don't know why it bothers.  */
 
@@ -3739,28 +3933,30 @@ ppc_stabx (int ignore ATTRIBUTE_UNUSED)
 
   symbol_get_tc (sym)->output = 1;
 
-  if (S_GET_STORAGE_CLASS (sym) == C_STSYM) {
-
-    symbol_get_tc (sym)->within = ppc_current_block;
+  if (S_GET_STORAGE_CLASS (sym) == C_STSYM)
+    {
+      /* In this case :
 
-    /* In this case :
+         .bs name
+         .stabx        "z",arrays_,133,0
+         .es
 
-       .bs name
-       .stabx  "z",arrays_,133,0
-       .es
+         .comm arrays_,13768,3
 
-       .comm arrays_,13768,3
+         resolve_symbol_value will copy the exp's "within" into sym's when the
+         offset is 0.  Since this seems to be corner case problem,
+         only do the correction for storage class C_STSYM.  A better solution
+         would be to have the tc field updated in ppc_symbol_new_hook.  */
 
-       resolve_symbol_value will copy the exp's "within" into sym's when the
-       offset is 0.  Since this seems to be corner case problem,
-       only do the correction for storage class C_STSYM.  A better solution
-       would be to have the tc field updated in ppc_symbol_new_hook.  */
+      if (exp.X_op == O_symbol)
+        {
+          if (ppc_current_block == NULL)
+            as_bad (_(".stabx of storage class stsym must be within .bs/.es"));
 
-    if (exp.X_op == O_symbol)
-      {
-       symbol_get_tc (exp.X_add_symbol)->within = ppc_current_block;
-      }
-  }
+          symbol_get_tc (sym)->within = ppc_current_block;
+          symbol_get_tc (exp.X_add_symbol)->within = ppc_current_block;
+        }
+    }
 
   if (exp.X_op != O_symbol
       || ! S_IS_EXTERNAL (exp.X_add_symbol)
@@ -3835,31 +4031,29 @@ ppc_function (int ignore ATTRIBUTE_UNUSED)
       symbol_set_value_expression (ext_sym, &exp);
     }
 
-  if (symbol_get_tc (ext_sym)->class == -1)
-    symbol_get_tc (ext_sym)->class = XMC_PR;
+  if (symbol_get_tc (ext_sym)->symbol_class == -1)
+    symbol_get_tc (ext_sym)->symbol_class = XMC_PR;
   symbol_get_tc (ext_sym)->output = 1;
 
   if (*input_line_pointer == ',')
     {
-      expressionS ignore;
+      expressionS exp;
 
       /* Ignore the third argument.  */
       ++input_line_pointer;
-      expression (&ignore);
+      expression (& exp);
       if (*input_line_pointer == ',')
        {
          /* Ignore the fourth argument.  */
          ++input_line_pointer;
-         expression (&ignore);
+         expression (& exp);
          if (*input_line_pointer == ',')
            {
              /* The fifth argument is the function size.  */
              ++input_line_pointer;
-             symbol_get_tc (ext_sym)->size = symbol_new ("L0\001",
-                                                         absolute_section,
-                                                         (valueT) 0,
-                                                         &zero_address_frag);
-             pseudo_set (symbol_get_tc (ext_sym)->size);
+             symbol_get_tc (ext_sym)->u.size = symbol_new
+                ("L0\001", absolute_section,(valueT) 0, &zero_address_frag);
+             pseudo_set (symbol_get_tc (ext_sym)->u.size);
            }
        }
     }
@@ -4221,6 +4415,33 @@ ppc_vbyte (int dummy ATTRIBUTE_UNUSED)
   cons (byte_count);
 }
 
+void
+ppc_xcoff_end (void)
+{
+  int i;
+
+  for (i = 0; i < XCOFF_DWSECT_NBR_NAMES; i++)
+    {
+      struct dw_section *dws = &dw_sections[i];
+      struct dw_subsection *dwss;
+
+      if (dws->anon_subseg)
+        {
+          dwss = dws->anon_subseg;
+          dwss->link = dws->list_subseg;
+        }
+      else
+        dwss = dws->list_subseg;
+
+      for (; dwss != NULL; dwss = dwss->link)
+        if (dwss->end_exp.X_add_symbol != NULL)
+          {
+            subseg_set (dws->sect, dwss->subseg);
+            symbol_set_value_now (dwss->end_exp.X_add_symbol);
+          }
+    }
+}
+
 #endif /* OBJ_XCOFF */
 #if defined (OBJ_XCOFF) || defined (OBJ_ELF)
 \f
@@ -4269,7 +4490,7 @@ ppc_tc (int ignore ATTRIBUTE_UNUSED)
        symbolS *label;
 
        label = symbol_get_tc (ppc_current_csect)->within;
-       if (symbol_get_tc (label)->class != XMC_TC0)
+       if (symbol_get_tc (label)->symbol_class != XMC_TC0)
          {
            as_bad (_(".tc with no label"));
            ignore_rest_of_line ();
@@ -4289,7 +4510,7 @@ ppc_tc (int ignore ATTRIBUTE_UNUSED)
     S_SET_SEGMENT (sym, now_seg);
     symbol_set_frag (sym, frag_now);
     S_SET_VALUE (sym, (valueT) frag_now_fix ());
-    symbol_get_tc (sym)->class = XMC_TC;
+    symbol_get_tc (sym)->symbol_class = XMC_TC;
     symbol_get_tc (sym)->output = 1;
 
     ppc_frob_label (sym);
@@ -4352,6 +4573,7 @@ ppc_machine (int ignore ATTRIBUTE_UNUSED)
   if (cpu_string != NULL)
     {
       ppc_cpu_t old_cpu = ppc_cpu;
+      ppc_cpu_t new_cpu;
       char *p;
 
       for (p = cpu_string; *p != 0; p++)
@@ -4374,8 +4596,8 @@ ppc_machine (int ignore ATTRIBUTE_UNUSED)
          else
            ppc_cpu = cpu_history[--curr_hist];
        }
-      else if (parse_cpu (cpu_string))
-       ;
+      else if ((new_cpu = ppc_parse_cpu (ppc_cpu, cpu_string)) != 0)
+       ppc_cpu = new_cpu;
       else
        as_bad (_("invalid machine `%s'"), cpu_string);
 
@@ -4392,7 +4614,7 @@ static int
 ppc_is_toc_sym (symbolS *sym)
 {
 #ifdef OBJ_XCOFF
-  return symbol_get_tc (sym)->class == XMC_TC;
+  return symbol_get_tc (sym)->symbol_class == XMC_TC;
 #endif
 #ifdef OBJ_ELF
   const char *sname = segment_name (S_GET_SEGMENT (sym));
@@ -5042,11 +5264,12 @@ ppc_symbol_new_hook (symbolS *sym)
   tc = symbol_get_tc (sym);
   tc->next = NULL;
   tc->output = 0;
-  tc->class = -1;
+  tc->symbol_class = -1;
   tc->real_name = NULL;
   tc->subseg = 0;
   tc->align = 0;
-  tc->size = NULL;
+  tc->u.size = NULL;
+  tc->u.dw = NULL;
   tc->within = NULL;
 
   if (ppc_stab_symbol)
@@ -5065,55 +5288,55 @@ ppc_symbol_new_hook (symbolS *sym)
     {
     case 'B':
       if (strcmp (s, "BS]") == 0)
-       tc->class = XMC_BS;
+       tc->symbol_class = XMC_BS;
       break;
     case 'D':
       if (strcmp (s, "DB]") == 0)
-       tc->class = XMC_DB;
+       tc->symbol_class = XMC_DB;
       else if (strcmp (s, "DS]") == 0)
-       tc->class = XMC_DS;
+       tc->symbol_class = XMC_DS;
       break;
     case 'G':
       if (strcmp (s, "GL]") == 0)
-       tc->class = XMC_GL;
+       tc->symbol_class = XMC_GL;
       break;
     case 'P':
       if (strcmp (s, "PR]") == 0)
-       tc->class = XMC_PR;
+       tc->symbol_class = XMC_PR;
       break;
     case 'R':
       if (strcmp (s, "RO]") == 0)
-       tc->class = XMC_RO;
+       tc->symbol_class = XMC_RO;
       else if (strcmp (s, "RW]") == 0)
-       tc->class = XMC_RW;
+       tc->symbol_class = XMC_RW;
       break;
     case 'S':
       if (strcmp (s, "SV]") == 0)
-       tc->class = XMC_SV;
+       tc->symbol_class = XMC_SV;
       break;
     case 'T':
       if (strcmp (s, "TC]") == 0)
-       tc->class = XMC_TC;
+       tc->symbol_class = XMC_TC;
       else if (strcmp (s, "TI]") == 0)
-       tc->class = XMC_TI;
+       tc->symbol_class = XMC_TI;
       else if (strcmp (s, "TB]") == 0)
-       tc->class = XMC_TB;
+       tc->symbol_class = XMC_TB;
       else if (strcmp (s, "TC0]") == 0 || strcmp (s, "T0]") == 0)
-       tc->class = XMC_TC0;
+       tc->symbol_class = XMC_TC0;
       break;
     case 'U':
       if (strcmp (s, "UA]") == 0)
-       tc->class = XMC_UA;
+       tc->symbol_class = XMC_UA;
       else if (strcmp (s, "UC]") == 0)
-       tc->class = XMC_UC;
+       tc->symbol_class = XMC_UC;
       break;
     case 'X':
       if (strcmp (s, "XO]") == 0)
-       tc->class = XMC_XO;
+       tc->symbol_class = XMC_XO;
       break;
     }
 
-  if (tc->class == -1)
+  if (tc->symbol_class == -1)
     as_bad (_("Unrecognized symbol suffix"));
 }
 
@@ -5126,13 +5349,14 @@ ppc_frob_label (symbolS *sym)
 {
   if (ppc_current_csect != (symbolS *) NULL)
     {
-      if (symbol_get_tc (sym)->class == -1)
-       symbol_get_tc (sym)->class = symbol_get_tc (ppc_current_csect)->class;
+      if (symbol_get_tc (sym)->symbol_class == -1)
+       symbol_get_tc (sym)->symbol_class = symbol_get_tc (ppc_current_csect)->symbol_class;
 
       symbol_remove (sym, &symbol_rootP, &symbol_lastP);
       symbol_append (sym, symbol_get_tc (ppc_current_csect)->within,
                     &symbol_rootP, &symbol_lastP);
       symbol_get_tc (ppc_current_csect)->within = sym;
+      symbol_get_tc (sym)->within = ppc_current_csect;
     }
 
 #ifdef OBJ_ELF
@@ -5204,11 +5428,11 @@ ppc_frob_symbol (symbolS *sym)
       if (ppc_last_function != (symbolS *) NULL)
        as_bad (_("two .function pseudo-ops with no intervening .ef"));
       ppc_last_function = sym;
-      if (symbol_get_tc (sym)->size != (symbolS *) NULL)
+      if (symbol_get_tc (sym)->u.size != (symbolS *) NULL)
        {
-         resolve_symbol_value (symbol_get_tc (sym)->size);
+         resolve_symbol_value (symbol_get_tc (sym)->u.size);
          SA_SET_SYM_FSIZE (sym,
-                           (long) S_GET_VALUE (symbol_get_tc (sym)->size));
+                           (long) S_GET_VALUE (symbol_get_tc (sym)->u.size));
        }
     }
   else if (S_GET_STORAGE_CLASS (sym) == C_FCN
@@ -5240,6 +5464,7 @@ ppc_frob_symbol (symbolS *sym)
     S_SET_STORAGE_CLASS (sym, C_HIDEXT);
 
   if (S_GET_STORAGE_CLASS (sym) == C_EXT
+      || S_GET_STORAGE_CLASS (sym) == C_AIX_WEAKEXT
       || S_GET_STORAGE_CLASS (sym) == C_HIDEXT)
     {
       int i;
@@ -5249,7 +5474,7 @@ ppc_frob_symbol (symbolS *sym)
       i = S_GET_NUMBER_AUXILIARY (sym);
       S_SET_NUMBER_AUXILIARY (sym, i + 1);
       a = &coffsymbol (symbol_get_bfdsym (sym))->native[i + 1].u.auxent;
-      if (symbol_get_tc (sym)->class == XMC_TC0)
+      if (symbol_get_tc (sym)->symbol_class == XMC_TC0)
        {
          /* This is the TOC table.  */
          know (strcmp (S_GET_NAME (sym), "TOC") == 0);
@@ -5278,9 +5503,9 @@ ppc_frob_symbol (symbolS *sym)
          a->x_csect.x_scnlen.l = symbol_get_frag (sym)->fr_offset;
          a->x_csect.x_smtyp = (symbol_get_tc (sym)->align << 3) | XTY_CM;
          if (S_IS_EXTERNAL (sym))
-           symbol_get_tc (sym)->class = XMC_RW;
+           symbol_get_tc (sym)->symbol_class = XMC_RW;
          else
-           symbol_get_tc (sym)->class = XMC_BS;
+           symbol_get_tc (sym)->symbol_class = XMC_BS;
        }
       else if (S_GET_SEGMENT (sym) == absolute_section)
        {
@@ -5288,8 +5513,8 @@ ppc_frob_symbol (symbolS *sym)
             ppc_adjust_symtab.  */
          ppc_saw_abs = TRUE;
          a->x_csect.x_smtyp = XTY_LD;
-         if (symbol_get_tc (sym)->class == -1)
-           symbol_get_tc (sym)->class = XMC_XO;
+         if (symbol_get_tc (sym)->symbol_class == -1)
+           symbol_get_tc (sym)->symbol_class = XMC_XO;
        }
       else if (! S_IS_DEFINED (sym))
        {
@@ -5297,17 +5522,17 @@ ppc_frob_symbol (symbolS *sym)
          a->x_csect.x_scnlen.l = 0;
          a->x_csect.x_smtyp = XTY_ER;
        }
-      else if (symbol_get_tc (sym)->class == XMC_TC)
+      else if (symbol_get_tc (sym)->symbol_class == XMC_TC)
        {
          symbolS *next;
 
          /* This is a TOC definition.  x_scnlen is the size of the
             TOC entry.  */
          next = symbol_next (sym);
-         while (symbol_get_tc (next)->class == XMC_TC0)
+         while (symbol_get_tc (next)->symbol_class == XMC_TC0)
            next = symbol_next (next);
          if (next == (symbolS *) NULL
-             || symbol_get_tc (next)->class != XMC_TC)
+             || symbol_get_tc (next)->symbol_class != XMC_TC)
            {
              if (ppc_after_toc_frag == (fragS *) NULL)
                a->x_csect.x_scnlen.l = (bfd_section_size (stdoutput,
@@ -5367,10 +5592,10 @@ ppc_frob_symbol (symbolS *sym)
 
       a->x_csect.x_parmhash = 0;
       a->x_csect.x_snhash = 0;
-      if (symbol_get_tc (sym)->class == -1)
+      if (symbol_get_tc (sym)->symbol_class == -1)
        a->x_csect.x_smclas = XMC_PR;
       else
-       a->x_csect.x_smclas = symbol_get_tc (sym)->class;
+       a->x_csect.x_smclas = symbol_get_tc (sym)->symbol_class;
       a->x_csect.x_stab = 0;
       a->x_csect.x_snstab = 0;
 
@@ -5391,13 +5616,22 @@ ppc_frob_symbol (symbolS *sym)
   else if (S_GET_STORAGE_CLASS (sym) == C_STSYM)
     {
       symbolS *block;
-      symbolS *csect;
+      valueT base;
 
-      /* The value is the offset from the enclosing csect.  */
       block = symbol_get_tc (sym)->within;
-      csect = symbol_get_tc (block)->within;
-      resolve_symbol_value (csect);
-      S_SET_VALUE (sym, S_GET_VALUE (sym) - S_GET_VALUE (csect));
+      if (block)
+        {
+          /* The value is the offset from the enclosing csect.  */
+          symbolS *csect;
+
+          csect = symbol_get_tc (block)->within;
+          resolve_symbol_value (csect);
+          base = S_GET_VALUE (csect);
+        }
+      else
+        base = 0;
+
+      S_SET_VALUE (sym, S_GET_VALUE (sym) - base);
     }
   else if (S_GET_STORAGE_CLASS (sym) == C_BINCL
           || S_GET_STORAGE_CLASS (sym) == C_EINCL)
@@ -5465,6 +5699,10 @@ ppc_frob_section (asection *sec)
 {
   static bfd_vma vma = 0;
 
+  /* Dwarf sections start at 0.  */
+  if (bfd_get_section_flags (NULL, sec) & SEC_DEBUGGING)
+    return;
+
   vma = md_section_align (sec, vma);
   bfd_set_section_vma (stdoutput, sec, vma);
   vma += bfd_section_size (stdoutput, sec);
@@ -5560,6 +5798,10 @@ ppc_fix_adjustable (fixS *fix)
   if (symseg == absolute_section)
     return 0;
 
+  /* Always adjust symbols in debugging sections.  */
+  if (bfd_get_section_flags (stdoutput, symseg) & SEC_DEBUGGING)
+    return 1;
+
   if (ppc_toc_csect != (symbolS *) NULL
       && fix->fx_addsy != ppc_toc_csect
       && symseg == data_section
@@ -5575,9 +5817,9 @@ ppc_fix_adjustable (fixS *fix)
        {
          TC_SYMFIELD_TYPE *sy_tc = symbol_get_tc (sy);
 
-         if (sy_tc->class == XMC_TC0)
+         if (sy_tc->symbol_class == XMC_TC0)
            continue;
-         if (sy_tc->class != XMC_TC)
+         if (sy_tc->symbol_class != XMC_TC)
            break;
          if (val == resolve_symbol_value (sy))
            {
@@ -5594,8 +5836,8 @@ ppc_fix_adjustable (fixS *fix)
   /* Possibly adjust the reloc to be against the csect.  */
   tc = symbol_get_tc (fix->fx_addsy);
   if (tc->subseg == 0
-      && tc->class != XMC_TC0
-      && tc->class != XMC_TC
+      && tc->symbol_class != XMC_TC0
+      && tc->symbol_class != XMC_TC
       && symseg != bss_section
       /* Don't adjust if this is a reloc in the toc section.  */
       && (symseg != data_section
@@ -5604,55 +5846,17 @@ ppc_fix_adjustable (fixS *fix)
          || (ppc_after_toc_frag != NULL
              && val >= ppc_after_toc_frag->fr_address)))
     {
-      symbolS *csect;
-      symbolS *next_csect;
+      symbolS *csect = tc->within;
 
-      if (symseg == text_section)
-       csect = ppc_text_csects;
-      else if (symseg == data_section)
-       csect = ppc_data_csects;
-      else
-       abort ();
+      /* If the symbol was not declared by a label (eg: a section symbol),
+         use the section instead of the csect.  This doesn't happen in
+         normal AIX assembly code.  */
+      if (csect == NULL)
+        csect = seg_info (symseg)->sym;
 
-      /* Skip the initial dummy symbol.  */
-      csect = symbol_get_tc (csect)->next;
-
-      if (csect != (symbolS *) NULL)
-       {
-         while ((next_csect = symbol_get_tc (csect)->next) != (symbolS *) NULL
-                && (symbol_get_frag (next_csect)->fr_address <= val))
-           {
-             /* If the csect address equals the symbol value, then we
-                have to look through the full symbol table to see
-                whether this is the csect we want.  Note that we will
-                only get here if the csect has zero length.  */
-             if (symbol_get_frag (csect)->fr_address == val
-                 && S_GET_VALUE (csect) == val)
-               {
-                 symbolS *scan;
-
-                 for (scan = symbol_next (csect);
-                      scan != NULL;
-                      scan = symbol_next (scan))
-                   {
-                     if (symbol_get_tc (scan)->subseg != 0)
-                       break;
-                     if (scan == fix->fx_addsy)
-                       break;
-                   }
+      fix->fx_offset += val - symbol_get_frag (csect)->fr_address;
+      fix->fx_addsy = csect;
 
-                 /* If we found the symbol before the next csect
-                    symbol, then this is the csect we want.  */
-                 if (scan == fix->fx_addsy)
-                   break;
-               }
-
-             csect = next_csect;
-           }
-
-         fix->fx_offset += val - symbol_get_frag (csect)->fr_address;
-         fix->fx_addsy = csect;
-       }
       return 0;
     }
 
@@ -5694,6 +5898,13 @@ ppc_force_relocation (fixS *fix)
   return generic_force_reloc (fix);
 }
 
+void
+ppc_new_dot_label (symbolS *sym)
+{
+  /* Anchor this label to the current csect for relocations.  */
+  symbol_get_tc (sym)->within = ppc_current_csect;
+}
+
 #endif /* OBJ_XCOFF */
 
 #ifdef OBJ_ELF
@@ -5732,6 +5943,8 @@ ppc_fix_adjustable (fixS *fix)
          && fix->fx_r_type != BFD_RELOC_LO16_GOTOFF
          && fix->fx_r_type != BFD_RELOC_HI16_GOTOFF
          && fix->fx_r_type != BFD_RELOC_HI16_S_GOTOFF
+         && fix->fx_r_type != BFD_RELOC_PPC64_GOT16_DS
+         && fix->fx_r_type != BFD_RELOC_PPC64_GOT16_LO_DS
          && fix->fx_r_type != BFD_RELOC_GPREL16
          && fix->fx_r_type != BFD_RELOC_VTABLE_INHERIT
          && fix->fx_r_type != BFD_RELOC_VTABLE_ENTRY
@@ -5754,15 +5967,41 @@ ppc_handle_align (struct frag *fragP)
       char *dest = fragP->fr_literal + fragP->fr_fix;
 
       fragP->fr_var = 4;
+
+      if (count > 4 * nop_limit && count < 0x2000000)
+       {
+         struct frag *rest;
+
+         /* Make a branch, then follow with nops.  Insert another
+            frag to handle the nops.  */
+         md_number_to_chars (dest, 0x48000000 + count, 4);
+         count -= 4;
+         if (count == 0)
+           return;
+
+         rest = xmalloc (SIZEOF_STRUCT_FRAG + 4);
+         memcpy (rest, fragP, SIZEOF_STRUCT_FRAG);
+         fragP->fr_next = rest;
+         fragP = rest;
+         rest->fr_address += rest->fr_fix + 4;
+         rest->fr_fix = 0;
+         /* If we leave the next frag as rs_align_code we'll come here
+            again, resulting in a bunch of branches rather than a
+            branch followed by nops.  */
+         rest->fr_type = rs_align;
+         dest = rest->fr_literal;
+       }
+
       md_number_to_chars (dest, 0x60000000, 4);
 
-      if ((ppc_cpu & PPC_OPCODE_POWER6) != 0)
+      if ((ppc_cpu & PPC_OPCODE_POWER6) != 0
+         || (ppc_cpu & PPC_OPCODE_POWER7) != 0)
        {
-         /* For power6, we want the last nop to be a group terminating
-            one, "ori 1,1,0".  Do this by inserting an rs_fill frag
-            immediately after this one, with its address set to the last
-            nop location.  This will automatically reduce the number of
-            nops in the current frag by one.  */
+         /* For power6 and power7, we want the last nop to be a group
+            terminating one.  Do this by inserting an rs_fill frag immediately
+            after this one, with its address set to the last nop location.
+            This will automatically reduce the number of nops in the current
+            frag by one.  */
          if (count > 4)
            {
              struct frag *group_nop = xmalloc (SIZEOF_STRUCT_FRAG + 4);
@@ -5776,7 +6015,18 @@ ppc_handle_align (struct frag *fragP)
              dest = group_nop->fr_literal;
            }
 
-         md_number_to_chars (dest, 0x60210000, 4);
+         if ((ppc_cpu & PPC_OPCODE_POWER7) != 0)
+           {
+             if (ppc_cpu & PPC_OPCODE_E500MC)
+               /* e500mc group terminating nop: "ori 0,0,0".  */
+               md_number_to_chars (dest, 0x60000000, 4);
+             else
+               /* power7 group terminating nop: "ori 2,2,0".  */
+               md_number_to_chars (dest, 0x60420000, 4);
+           }
+         else
+           /* power6 group terminating nop: "ori 1,1,0".  */
+           md_number_to_chars (dest, 0x60210000, 4);
        }
     }
 }
@@ -5811,18 +6061,19 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
      going to use the symbol value.  That means that if the reloc is
      fully resolved we want to use *valP since bfd_install_relocation is
      not being used.
-     However, if the reloc is not fully resolved we do not want to use
-     *valP, and must use fx_offset instead.  However, if the reloc
-     is PC relative, we do want to use *valP since it includes the
-     result of md_pcrel_from.  This is confusing.  */
+     However, if the reloc is not fully resolved we do not want to
+     use *valP, and must use fx_offset instead.  If the relocation
+     is PC-relative, we then need to re-apply md_pcrel_from_section
+     to this new relocation value.  */
   if (fixP->fx_addsy == (symbolS *) NULL)
     fixP->fx_done = 1;
 
-  else if (fixP->fx_pcrel)
-    ;
-
   else
-    value = fixP->fx_offset;
+    {
+      value = fixP->fx_offset;
+      if (fixP->fx_pcrel)
+       value -= md_pcrel_from_section (fixP, seg);
+    }
 #endif
 
   if (fixP->fx_subsy != (symbolS *) NULL)
@@ -5853,8 +6104,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
          && (operand->insert == NULL || ppc_obj64)
          && fixP->fx_addsy != NULL
          && symbol_get_tc (fixP->fx_addsy)->subseg != 0
-         && symbol_get_tc (fixP->fx_addsy)->class != XMC_TC
-         && symbol_get_tc (fixP->fx_addsy)->class != XMC_TC0
+         && symbol_get_tc (fixP->fx_addsy)->symbol_class != XMC_TC
+         && symbol_get_tc (fixP->fx_addsy)->symbol_class != XMC_TC0
          && S_GET_SEGMENT (fixP->fx_addsy) != bss_section)
        {
          value = fixP->fx_offset;
@@ -5881,7 +6132,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
        /* Nothing else to do here.  */
        return;
 
-      assert (fixP->fx_addsy != NULL);
+      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
@@ -6085,6 +6336,11 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
                              PPC_HA (value), 2);
          break;
 
+#ifdef OBJ_XCOFF
+       case BFD_RELOC_NONE:
+         break;
+#endif
+
 #ifdef OBJ_ELF
        case BFD_RELOC_PPC64_HIGHER:
          if (fixP->fx_pcrel)
@@ -6155,6 +6411,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
          break;
 
        case BFD_RELOC_PPC_TLS:
+       case BFD_RELOC_PPC_TLSGD:
+       case BFD_RELOC_PPC_TLSLD:
          break;
 
        case BFD_RELOC_PPC_DTPMOD: