(obj_coff_section [BEF_ASSEMBLER]): Make 'r' mean readonly data.
[deliverable/binutils-gdb.git] / gas / config / tc-ppc.c
index ef4341fe530d1b8e06c3d95e787d039f1b5a5ac4..5849654837a318f3b8a8b89323d4404219f9acc4 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-ppc.c -- Assemble for the PowerPC or POWER (RS/6000)
-   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
    Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
@@ -24,7 +24,7 @@
 #include "as.h"
 #include "safe-ctype.h"
 #include "subsegs.h"
-
+#include "dw2gencfi.h"
 #include "opcode/ppc.h"
 
 #ifdef OBJ_ELF
@@ -47,9 +47,9 @@ static int set_target_endian = 0;
 /* Whether to use user friendly register names.  */
 #ifndef TARGET_REG_NAMES_P
 #ifdef TE_PE
-#define TARGET_REG_NAMES_P true
+#define TARGET_REG_NAMES_P TRUE
 #else
-#define TARGET_REG_NAMES_P false
+#define TARGET_REG_NAMES_P FALSE
 #endif
 #endif
 
@@ -65,32 +65,27 @@ static int set_target_endian = 0;
 /* #ha(value) denotes the high adjusted value: bits 16 through 31 of
   the indicated value, compensating for #lo() being treated as a
   signed number.  */
-#define PPC_HA(v) ((((v) >> 16) + (((v) >> 15) & 1)) & 0xffff)
+#define PPC_HA(v) PPC_HI ((v) + 0x8000)
 
 /* #higher(value) denotes bits 32 through 47 of the indicated value.  */
-#define PPC_HIGHER(v) (((v) >> 32) & 0xffff)
+#define PPC_HIGHER(v) (((v) >> 16 >> 16) & 0xffff)
 
 /* #highera(value) denotes bits 32 through 47 of the indicated value,
    compensating for #lo() being treated as a signed number.  */
-#define PPC_HIGHERA(v) \
-  ((((v) >> 32) + (((v) & 0xffff8000) == 0xffff8000)) & 0xffff)
+#define PPC_HIGHERA(v) PPC_HIGHER ((v) + 0x8000)
 
 /* #highest(value) denotes bits 48 through 63 of the indicated value.  */
-#define PPC_HIGHEST(v) (((v) >> 48) & 0xffff)
+#define PPC_HIGHEST(v) (((v) >> 24 >> 24) & 0xffff)
 
 /* #highesta(value) denotes bits 48 through 63 of the indicated value,
-   compensating for #lo being treated as a signed number.
-   Generate 0xffffffff8000 with arithmetic here, for portability.  */
-#define PPC_HIGHESTA(v) \
-  ((((v) >> 48)                                                                      \
-    + (((v) & (((valueT) 1 << 48) - 0x8000)) == ((valueT) 1 << 48) - 0x8000)) \
-   & 0xffff)
+   compensating for #lo being treated as a signed number.  */
+#define PPC_HIGHESTA(v) PPC_HIGHEST ((v) + 0x8000)
 
 #define SEX16(val) ((((val) & 0xffff) ^ 0x8000) - 0x8000)
 
-static boolean reg_names_p = TARGET_REG_NAMES_P;
+static bfd_boolean reg_names_p = TARGET_REG_NAMES_P;
 
-static boolean register_name PARAMS ((expressionS *));
+static bfd_boolean register_name PARAMS ((expressionS *));
 static void ppc_set_cpu PARAMS ((void));
 static unsigned long ppc_insert_operand
   PARAMS ((unsigned long insn, const struct powerpc_operand *operand,
@@ -116,7 +111,7 @@ static void ppc_ec PARAMS ((int));
 static void ppc_ef PARAMS ((int));
 static void ppc_es PARAMS ((int));
 static void ppc_csect PARAMS ((int));
-static void ppc_change_csect PARAMS ((symbolS *));
+static void ppc_change_csect PARAMS ((symbolS *, offsetT));
 static void ppc_function PARAMS ((int));
 static void ppc_extern PARAMS ((int));
 static void ppc_lglobl PARAMS ((int));
@@ -135,6 +130,7 @@ static void ppc_elf_cons PARAMS ((int));
 static void ppc_elf_rdata PARAMS ((int));
 static void ppc_elf_lcomm PARAMS ((int));
 static void ppc_elf_validate_fix PARAMS ((fixS *, segT));
+static void ppc_apuinfo_section_add PARAMS ((unsigned int apu, unsigned int version));
 #endif
 
 #ifdef TE_PE
@@ -186,6 +182,13 @@ const char EXP_CHARS[] = "eE";
 /* Characters which mean that a number is a floating point constant,
    as in 0d1.0.  */
 const char FLT_CHARS[] = "dD";
+
+/* '+' and '-' can be used as postfix predicate predictors for conditional 
+   branches.  So they need to be accepted as symbol characters.  */
+const char ppc_symbol_chars[] = "+-";
+
+/* The dwarf2 data alignment, adjusted for 32 or 64 bit.  */
+int ppc_cie_data_alignment;
 \f
 /* The target specific pseudo-ops which we support.  */
 
@@ -237,8 +240,6 @@ const pseudo_typeS md_pseudo_table[] =
   { "rdata",   ppc_elf_rdata,  0 },
   { "rodata",  ppc_elf_rdata,  0 },
   { "lcomm",   ppc_elf_lcomm,  0 },
-  { "file",    dwarf2_directive_file, 0 },
-  { "loc",     dwarf2_directive_loc, 0 },
 #endif
 
 #ifdef TE_PE
@@ -607,7 +608,7 @@ reg_name_search (regs, regcount, name)
  *      original state.
  */
 
-static boolean
+static bfd_boolean
 register_name (expressionP)
      expressionS *expressionP;
 {
@@ -622,7 +623,7 @@ register_name (expressionP)
     name = ++input_line_pointer;
 
   else if (!reg_names_p || !ISALPHA (name[0]))
-    return false;
+    return FALSE;
 
   c = get_symbol_end ();
   reg_number = reg_name_search (pre_defined_registers, REG_NAME_CNT, name);
@@ -639,12 +640,12 @@ register_name (expressionP)
       /* Make the rest nice.  */
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol = NULL;
-      return true;
+      return TRUE;
     }
 
   /* Reset the line as if we had not done anything.  */
   input_line_pointer = start;
-  return false;
+  return FALSE;
 }
 \f
 /* This function is called for each symbol seen in an expression.  It
@@ -652,7 +653,7 @@ register_name (expressionP)
    to use for condition codes.  */
 
 /* Whether to do the special parsing.  */
-static boolean cr_operand;
+static bfd_boolean cr_operand;
 
 /* Names to recognize in a condition code.  This table is sorted.  */
 static const struct pd_reg cr_names[] =
@@ -700,14 +701,10 @@ ppc_parse_name (name, expr)
 
 /* The type of processor we are assembling for.  This is one or more
    of the PPC_OPCODE flags defined in opcode/ppc.h.  */
-static int ppc_cpu = 0;
-
-/* The size of the processor we are assembling for.  This is either
-   PPC_OPCODE_32 or PPC_OPCODE_64.  */
-static unsigned long ppc_size = PPC_OPCODE_32;
+static unsigned long ppc_cpu = 0;
 
-/* Whether to target xcoff64.  */
-static int ppc_xcoff64 = 0;
+/* Whether to target xcoff64/elf64.  */
+static unsigned int ppc_obj64 = BFD_DEFAULT_TARGET_SIZE == 64;
 
 /* Opcode hash table.  */
 static struct hash_control *ppc_hash;
@@ -724,12 +721,12 @@ static flagword ppc_flags = 0;
 
 /* Whether this is Solaris or not.  */
 #ifdef TARGET_SOLARIS_COMMENT
-#define SOLARIS_P true
+#define SOLARIS_P TRUE
 #else
-#define SOLARIS_P false
+#define SOLARIS_P FALSE
 #endif
 
-static boolean msolaris = SOLARIS_P;
+static bfd_boolean msolaris = SOLARIS_P;
 #endif
 
 #ifdef OBJ_XCOFF
@@ -796,17 +793,31 @@ static segT ppc_current_section;
 
 #ifdef OBJ_ELF
 symbolS *GOT_symbol;           /* Pre-defined "_GLOBAL_OFFSET_TABLE" */
+#define PPC_APUINFO_ISEL       0x40
+#define PPC_APUINFO_PMR                0x41
+#define PPC_APUINFO_RFMCI      0x42
+#define PPC_APUINFO_CACHELCK   0x43
+#define PPC_APUINFO_SPE                0x100
+#define PPC_APUINFO_EFS                0x101
+#define PPC_APUINFO_BRLOCK     0x102
+
+/*
+ * We keep a list of APUinfo
+ */
+unsigned long *ppc_apuinfo_list;
+unsigned int ppc_apuinfo_num;
+unsigned int ppc_apuinfo_num_alloc;
 #endif /* OBJ_ELF */
 \f
 #ifdef OBJ_ELF
-CONST char *md_shortopts = "b:l:usm:K:VQ:";
+const char *const md_shortopts = "b:l:usm:K:VQ:";
 #else
-CONST char *md_shortopts = "um:";
+const char *const md_shortopts = "um:";
 #endif
-struct option md_longopts[] = {
+const struct option md_longopts[] = {
   {NULL, no_argument, NULL, 0}
 };
-size_t md_longopts_size = sizeof (md_longopts);
+const size_t md_longopts_size = sizeof (md_longopts);
 
 int
 md_parse_option (c, arg)
@@ -861,65 +872,115 @@ md_parse_option (c, arg)
       /* a64 and a32 determine whether to use XCOFF64 or XCOFF32.  */
     case 'a':
       if (strcmp (arg, "64") == 0)
-       ppc_xcoff64 = 1;
+       {
+#ifdef BFD64
+         ppc_obj64 = 1;
+#else
+         as_fatal (_("%s unsupported"), "-a64");
+#endif
+       }
       else if (strcmp (arg, "32") == 0)
-       ppc_xcoff64 = 0;
+       ppc_obj64 = 0;
       else
        return 0;
       break;
 
     case 'm':
-      /* Most CPU's are 32 bit.  Exceptions are listed below.  */
-      ppc_size = PPC_OPCODE_32;
-
       /* -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_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;
-      /* -m601 means to assemble for the Motorola PowerPC 601, which includes
+       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_601;
+       ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
+                  | PPC_OPCODE_601 | PPC_OPCODE_32);
       /* -mppc, -mppc32, -m603, and -m604 mean to assemble for the
-        Motorola PowerPC 603/604.  */
+        PowerPC 603/604.  */
       else if (strcmp (arg, "ppc") == 0
               || strcmp (arg, "ppc32") == 0
-              || strcmp (arg, "403") == 0
-              || strcmp (arg, "405") == 0
               || strcmp (arg, "603") == 0
               || strcmp (arg, "604") == 0)
-       ppc_cpu = PPC_OPCODE_PPC;
-      else if (strcmp (arg, "7400") == 0)
-       ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_ALTIVEC;
+       ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32;
+      /* -m403 and -m405 mean to assemble for the PowerPC 403/405.  */
+      else if (strcmp (arg, "403") == 0
+              || strcmp (arg, "405") == 0)
+       ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
+                  | PPC_OPCODE_403 | PPC_OPCODE_32);
+      else if (strcmp (arg, "440") == 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, "altivec") == 0)
+       {
+         if (ppc_cpu == 0)
+           ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_ALTIVEC;
+         else
+           ppc_cpu |= PPC_OPCODE_ALTIVEC;
+       }
+      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);
+       }
+      else if (strcmp (arg, "spe") == 0)
+       {
+         if (ppc_cpu == 0)
+           ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_SPE | PPC_OPCODE_EFS;
+         else
+           ppc_cpu |= 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_size = PPC_OPCODE_64;
+         ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64;
        }
       else if (strcmp (arg, "ppc64bridge") == 0)
        {
-         ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_64_BRIDGE;
-         ppc_size = PPC_OPCODE_64;
+         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;
+       }
+      /* -mbooke64 means enable 64-bit BookE support.  */
+      else if (strcmp (arg, "booke64") == 0)
+       {
+         ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE
+                    | PPC_OPCODE_BOOKE64 | PPC_OPCODE_64);
+       }
+      else if (strcmp (arg, "power4") == 0)
+       {
+         ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
+                    | PPC_OPCODE_64 | PPC_OPCODE_POWER4);
        }
       /* -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_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;
+       ppc_cpu |= PPC_OPCODE_ANY;
 
       else if (strcmp (arg, "regnames") == 0)
-       reg_names_p = true;
+       reg_names_p = TRUE;
 
       else if (strcmp (arg, "no-regnames") == 0)
-       reg_names_p = false;
+       reg_names_p = FALSE;
 
 #ifdef OBJ_ELF
       /* -mrelocatable/-mrelocatable-lib -- warn about initializations
@@ -956,13 +1017,13 @@ md_parse_option (c, arg)
 
       else if (strcmp (arg, "solaris") == 0)
        {
-         msolaris = true;
+         msolaris = TRUE;
          ppc_comment_chars = ppc_solaris_comment_chars;
        }
 
       else if (strcmp (arg, "no-solaris") == 0)
        {
-         msolaris = false;
+         msolaris = FALSE;
          ppc_comment_chars = ppc_eabi_comment_chars;
        }
 #endif
@@ -1007,16 +1068,30 @@ md_show_usage (stream)
 {
   fprintf (stream, _("\
 PowerPC options:\n\
+-a32                   generate ELF32/XCOFF32\n\
+-a64                   generate ELF64/XCOFF64\n\
 -u                     ignored\n\
--mpwrx, -mpwr2         generate code for IBM POWER/2 (RIOS2)\n\
--mpwr                  generate code for IBM POWER (RIOS1)\n\
--m601                  generate code for Motorola PowerPC 601\n\
--mppc, -mppc32, -m403, -m405, -m603, -m604\n\
-                       generate code for Motorola PowerPC 603/604\n\
--mppc64, -m620         generate code for Motorola PowerPC 620\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, -m405           generate code for PowerPC 403/405\n\
+-m440                  generate code for PowerPC 440\n\
+-m7400, -m7410, -m7450, -m7455\n\
+                       generate code For PowerPC 7400/7410/7450/7455\n"));
+  fprintf (stream, _("\
+-mppc64, -m620         generate code for PowerPC 620/625/630\n\
 -mppc64bridge          generate code for PowerPC 64, including bridge insns\n\
+-mbooke64              generate code for 64-bit PowerPC BookE\n\
+-mbooke, mbooke32      generate code for 32-bit PowerPC BookE\n\
+-mpower4               generate code for Power4 architecture\n\
 -mcom                  generate code Power/PowerPC common instructions\n\
--many                  generate code for any architecture (PWR/PWRX/PPC)\n\
+-many                  generate code for any architecture (PWR/PWRX/PPC)\n"));
+  fprintf (stream, _("\
+-maltivec              generate code for AltiVec\n\
+-me500, -me500x2       generate code for Motorola e500 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"));
 #ifdef OBJ_ELF
@@ -1024,9 +1099,10 @@ PowerPC options:\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\n\
+-mlittle, -mlittle-endian, -l, -le\n\
                        generate code for a little endian machine\n\
--mbig, -mbig-endian    generate code for a big 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\
@@ -1042,17 +1118,24 @@ ppc_set_cpu ()
   const char *default_os  = TARGET_OS;
   const char *default_cpu = TARGET_CPU;
 
-  if (ppc_cpu == 0)
+  if ((ppc_cpu & ~PPC_OPCODE_ANY) == 0)
     {
-      if (strncmp (default_os, "aix", 3) == 0
-         && default_os[3] >= '4' && default_os[3] <= '9')
-       ppc_cpu = PPC_OPCODE_COMMON;
+      if (ppc_obj64)
+       ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | 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;
       else if (strncmp (default_os, "aix3", 4) == 0)
-       ppc_cpu = PPC_OPCODE_POWER;
+       ppc_cpu |= PPC_OPCODE_POWER | PPC_OPCODE_32;
       else if (strcmp (default_cpu, "rs6000") == 0)
-       ppc_cpu = PPC_OPCODE_POWER;
+       ppc_cpu |= PPC_OPCODE_POWER | PPC_OPCODE_32;
       else if (strncmp (default_cpu, "powerpc", 7) == 0)
-       ppc_cpu = PPC_OPCODE_PPC;
+       {
+         if (default_cpu[7] == '6' && default_cpu[8] == '4')
+           ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64;
+         else
+           ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32;
+       }
       else
        as_fatal (_("Unknown default cpu = %s, os = %s"),
                  default_cpu, default_os);
@@ -1086,16 +1169,13 @@ ppc_arch ()
 unsigned long
 ppc_mach ()
 {
-  return ppc_size == PPC_OPCODE_64 ? 620 : 0;
-}
-
-#ifdef OBJ_XCOFF
-int
-ppc_subseg_align ()
-{
-  return ppc_xcoff64 ? 3 : 2;
+  if (ppc_obj64)
+    return bfd_mach_ppc64;
+  else if (ppc_arch () == bfd_arch_rs6000)
+    return bfd_mach_rs6k;
+  else
+    return bfd_mach_ppc;
 }
-#endif
 
 extern char*
 ppc_target_format ()
@@ -1106,13 +1186,17 @@ ppc_target_format ()
 #elif TE_POWERMAC
   return "xcoff-powermac";
 #else
-  return ppc_xcoff64 ? "aixcoff64-rs6000" : "aixcoff-rs6000";
+#  ifdef TE_AIX5
+    return (ppc_obj64 ? "aix5coff64-rs6000" : "aixcoff-rs6000");
+#  else
+    return (ppc_obj64 ? "aixcoff64-rs6000" : "aixcoff-rs6000");
+#  endif
 #endif
 #endif
 #ifdef OBJ_ELF
   return (target_big_endian
-         ? (BFD_DEFAULT_TARGET_SIZE == 64 ? "elf64-powerpc" : "elf32-powerpc")
-         : (BFD_DEFAULT_TARGET_SIZE == 64 ? "elf64-powerpcle" : "elf32-powerpcle"));
+         ? (ppc_obj64 ? "elf64-powerpc" : "elf32-powerpc")
+         : (ppc_obj64 ? "elf64-powerpcle" : "elf32-powerpcle"));
 #endif
 }
 
@@ -1127,16 +1211,13 @@ md_begin ()
   const struct powerpc_opcode *op_end;
   const struct powerpc_macro *macro;
   const struct powerpc_macro *macro_end;
-  boolean dup_insn = false;
+  bfd_boolean dup_insn = FALSE;
 
   ppc_set_cpu ();
 
-#ifdef OBJ_ELF
-  /* If we're going to generate a 64-bit ABI file, then we need
-     the 64-bit capable instructions.  */
-  if (BFD_DEFAULT_TARGET_SIZE == 64)
-    ppc_size = PPC_OPCODE_64;
+  ppc_cie_data_alignment = ppc_obj64 ? -8 : -4;
 
+#ifdef OBJ_ELF
   /* Set the ELF flags if desired.  */
   if (ppc_flags && !msolaris)
     bfd_set_private_flags (stdoutput, ppc_flags);
@@ -1150,10 +1231,22 @@ md_begin ()
     {
       know ((op->opcode & op->mask) == op->opcode);
 
-      if ((op->flags & ppc_cpu) != 0
+      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_size
-             || (ppc_cpu & PPC_OPCODE_64_BRIDGE) != 0))
+             || ((op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64))
+                 == (ppc_cpu & (PPC_OPCODE_32 | PPC_OPCODE_64)))
+             || (ppc_cpu & PPC_OPCODE_64_BRIDGE) != 0)
+         /* Certain instructions (eg: extsw) do not exist in the
+            32-bit BookE instruction set, but they do exist in the
+            64-bit BookE instruction set, and other PPC instruction
+            sets.  Check to see if the opcode has the BOOKE64 flag set.
+            If it does make sure that the target CPU is not the BookE32.  */
+         && ((op->flags & PPC_OPCODE_BOOKE64) == 0
+             || (ppc_cpu & PPC_OPCODE_BOOKE64) == PPC_OPCODE_BOOKE64
+             || (ppc_cpu & PPC_OPCODE_BOOKE) == 0)
+         && ((op->flags & (PPC_OPCODE_POWER4 | PPC_OPCODE_NOPOWER4)) == 0
+             || ((op->flags & PPC_OPCODE_POWER4)
+                 == (ppc_cpu & PPC_OPCODE_POWER4))))
        {
          const char *retval;
 
@@ -1167,11 +1260,15 @@ md_begin ()
 
              as_bad (_("Internal assembler error for instruction %s"),
                      op->name);
-             dup_insn = true;
+             dup_insn = TRUE;
            }
        }
     }
 
+  if ((ppc_cpu & PPC_OPCODE_ANY) != 0)
+    for (op = powerpc_opcodes; op < op_end; op++)
+      hash_insert (ppc_hash, op->name, (PTR) op);
+
   /* Insert the macros into a hash table.  */
   ppc_macro_hash = hash_new ();
 
@@ -1186,7 +1283,7 @@ md_begin ()
          if (retval != (const char *) NULL)
            {
              as_bad (_("Internal assembler error for macro %s"), macro->name);
-             dup_insn = true;
+             dup_insn = TRUE;
            }
        }
     }
@@ -1222,6 +1319,66 @@ md_begin ()
 #endif
 }
 
+void
+ppc_cleanup ()
+{
+#ifdef OBJ_ELF
+  if (ppc_apuinfo_list == NULL)
+    return;
+
+  /* Ok, so write the section info out.  We have this layout:
+
+  byte data            what
+  ---- ----            ----
+  0    8               length of "APUinfo\0"
+  4    (n*4)           number of APU's (4 bytes each)
+  8    2               note type 2
+  12   "APUinfo\0"     name
+  20   APU#1           first APU's info
+  24   APU#2           second APU's info
+  ...  ...
+  */
+  {
+    char *p;
+    asection *seg = now_seg;
+    subsegT subseg = now_subseg;
+    asection *apuinfo_secp = (asection *) NULL;
+    unsigned int i;
+
+    /* Create the .PPC.EMB.apuinfo section.  */
+    apuinfo_secp = subseg_new (".PPC.EMB.apuinfo", 0);
+    bfd_set_section_flags (stdoutput,
+                          apuinfo_secp,
+                          SEC_HAS_CONTENTS | SEC_READONLY);
+
+    p = frag_more (4);
+    md_number_to_chars (p, (valueT) 8, 4);
+
+    p = frag_more (4);
+    md_number_to_chars (p, (valueT) ppc_apuinfo_num * 4, 4);
+
+    p = frag_more (4);
+    md_number_to_chars (p, (valueT) 2, 4);
+
+    p = frag_more (8);
+    strcpy (p, "APUinfo");
+
+    for (i = 0; i < ppc_apuinfo_num; i++)
+      {
+       p = frag_more (4);
+       md_number_to_chars (p, (valueT) ppc_apuinfo_list[i], 4);
+      }
+
+    frag_align (2, 0, 0);
+
+    /* We probably can't restore the current segment, for there likely
+       isn't one yet...  */
+    if (seg && subseg)
+      subseg_set (seg, subseg);
+  }
+#endif
+}
+
 /* Insert an operand value into an instruction.  */
 
 static unsigned long
@@ -1245,7 +1402,7 @@ ppc_insert_operand (insn, operand, val, file, line)
            max = (1 << (operand->bits - 1)) - 1;
          min = - (1 << (operand->bits - 1));
 
-         if (ppc_size == PPC_OPCODE_32)
+         if (!ppc_obj64)
            {
              /* Some people write 32 bit hex constants with the sign
                 extension done by hand.  This shouldn't really be
@@ -1287,7 +1444,7 @@ ppc_insert_operand (insn, operand, val, file, line)
       const char *errmsg;
 
       errmsg = NULL;
-      insn = (*operand->insert) (insn, (long) val, &errmsg);
+      insn = (*operand->insert) (insn, (long) val, ppc_cpu, &errmsg);
       if (errmsg != (const char *) NULL)
        as_bad_where (file, line, errmsg);
     }
@@ -1309,7 +1466,7 @@ ppc_elf_suffix (str_p, exp_p)
   struct map_bfd {
     char *string;
     int length;
-    bfd_reloc_code_real_type reloc;
+    int reloc;
   };
 
   char ident[20];
@@ -1317,65 +1474,99 @@ ppc_elf_suffix (str_p, exp_p)
   char *str2;
   int ch;
   int len;
-  struct map_bfd *ptr;
+  const struct map_bfd *ptr;
 
 #define MAP(str,reloc) { str, sizeof (str)-1, reloc }
 
-  static struct map_bfd mapping[] = {
-    MAP ("l",          BFD_RELOC_LO16),
-    MAP ("h",          BFD_RELOC_HI16),
-    MAP ("ha",         BFD_RELOC_HI16_S),
-    MAP ("brtaken",    BFD_RELOC_PPC_B16_BRTAKEN),
-    MAP ("brntaken",   BFD_RELOC_PPC_B16_BRNTAKEN),
-    MAP ("got",                BFD_RELOC_16_GOTOFF),
-    MAP ("got@l",      BFD_RELOC_LO16_GOTOFF),
-    MAP ("got@h",      BFD_RELOC_HI16_GOTOFF),
-    MAP ("got@ha",     BFD_RELOC_HI16_S_GOTOFF),
-    MAP ("fixup",      BFD_RELOC_CTOR),   /* warnings with -mrelocatable */
-    MAP ("plt",                BFD_RELOC_24_PLT_PCREL),
-    MAP ("pltrel24",   BFD_RELOC_24_PLT_PCREL),
-    MAP ("copy",       BFD_RELOC_PPC_COPY),
-    MAP ("globdat",    BFD_RELOC_PPC_GLOB_DAT),
-    MAP ("local24pc",  BFD_RELOC_PPC_LOCAL24PC),
-    MAP ("local",      BFD_RELOC_PPC_LOCAL24PC),
-    MAP ("pltrel",     BFD_RELOC_32_PLT_PCREL),
-    MAP ("plt@l",      BFD_RELOC_LO16_PLTOFF),
-    MAP ("plt@h",      BFD_RELOC_HI16_PLTOFF),
-    MAP ("plt@ha",     BFD_RELOC_HI16_S_PLTOFF),
-    MAP ("sdarel",     BFD_RELOC_GPREL16),
-    MAP ("sectoff",    BFD_RELOC_32_BASEREL),
-    MAP ("sectoff@l",  BFD_RELOC_LO16_BASEREL),
-    MAP ("sectoff@h",  BFD_RELOC_HI16_BASEREL),
-    MAP ("sectoff@ha", BFD_RELOC_HI16_S_BASEREL),
-    MAP ("naddr",      BFD_RELOC_PPC_EMB_NADDR32),
-    MAP ("naddr16",    BFD_RELOC_PPC_EMB_NADDR16),
-    MAP ("naddr@l",    BFD_RELOC_PPC_EMB_NADDR16_LO),
-    MAP ("naddr@h",    BFD_RELOC_PPC_EMB_NADDR16_HI),
-    MAP ("naddr@ha",   BFD_RELOC_PPC_EMB_NADDR16_HA),
-    MAP ("sdai16",     BFD_RELOC_PPC_EMB_SDAI16),
-    MAP ("sda2rel",    BFD_RELOC_PPC_EMB_SDA2REL),
-    MAP ("sda2i16",    BFD_RELOC_PPC_EMB_SDA2I16),
-    MAP ("sda21",      BFD_RELOC_PPC_EMB_SDA21),
-    MAP ("mrkref",     BFD_RELOC_PPC_EMB_MRKREF),
-    MAP ("relsect",    BFD_RELOC_PPC_EMB_RELSEC16),
-    MAP ("relsect@l",  BFD_RELOC_PPC_EMB_RELST_LO),
-    MAP ("relsect@h",  BFD_RELOC_PPC_EMB_RELST_HI),
-    MAP ("relsect@ha", BFD_RELOC_PPC_EMB_RELST_HA),
-    MAP ("bitfld",     BFD_RELOC_PPC_EMB_BIT_FLD),
-    MAP ("relsda",     BFD_RELOC_PPC_EMB_RELSDA),
-    MAP ("xgot",       BFD_RELOC_PPC_TOC16),
-#if BFD_DEFAULT_TARGET_SIZE == 64
-    MAP ("higher",     BFD_RELOC_PPC64_HIGHER),
-    MAP ("highera",    BFD_RELOC_PPC64_HIGHER_S),
-    MAP ("highest",    BFD_RELOC_PPC64_HIGHEST),
-    MAP ("highesta",   BFD_RELOC_PPC64_HIGHEST_S),
-    MAP ("tocbase",    BFD_RELOC_PPC64_TOC),
-    MAP ("toc",                BFD_RELOC_PPC_TOC16),
-    MAP ("toc@l",       BFD_RELOC_PPC64_TOC16_LO),
-    MAP ("toc@h",       BFD_RELOC_PPC64_TOC16_HI),
-    MAP ("toc@ha",      BFD_RELOC_PPC64_TOC16_HA),
-#endif
-    { (char *) 0,      0,      BFD_RELOC_UNUSED }
+  static const struct map_bfd mapping[] = {
+    MAP ("l",                  (int) BFD_RELOC_LO16),
+    MAP ("h",                  (int) BFD_RELOC_HI16),
+    MAP ("ha",                 (int) BFD_RELOC_HI16_S),
+    MAP ("brtaken",            (int) BFD_RELOC_PPC_B16_BRTAKEN),
+    MAP ("brntaken",           (int) BFD_RELOC_PPC_B16_BRNTAKEN),
+    MAP ("got",                        (int) BFD_RELOC_16_GOTOFF),
+    MAP ("got@l",              (int) BFD_RELOC_LO16_GOTOFF),
+    MAP ("got@h",              (int) BFD_RELOC_HI16_GOTOFF),
+    MAP ("got@ha",             (int) BFD_RELOC_HI16_S_GOTOFF),
+    MAP ("fixup",              (int) BFD_RELOC_CTOR),
+    MAP ("plt",                        (int) BFD_RELOC_24_PLT_PCREL),
+    MAP ("pltrel24",           (int) BFD_RELOC_24_PLT_PCREL),
+    MAP ("copy",               (int) BFD_RELOC_PPC_COPY),
+    MAP ("globdat",            (int) BFD_RELOC_PPC_GLOB_DAT),
+    MAP ("local24pc",          (int) BFD_RELOC_PPC_LOCAL24PC),
+    MAP ("local",              (int) BFD_RELOC_PPC_LOCAL24PC),
+    MAP ("pltrel",             (int) BFD_RELOC_32_PLT_PCREL),
+    MAP ("plt@l",              (int) BFD_RELOC_LO16_PLTOFF),
+    MAP ("plt@h",              (int) BFD_RELOC_HI16_PLTOFF),
+    MAP ("plt@ha",             (int) BFD_RELOC_HI16_S_PLTOFF),
+    MAP ("sdarel",             (int) BFD_RELOC_GPREL16),
+    MAP ("sectoff",            (int) BFD_RELOC_16_BASEREL),
+    MAP ("sectoff@l",          (int) BFD_RELOC_LO16_BASEREL),
+    MAP ("sectoff@h",          (int) BFD_RELOC_HI16_BASEREL),
+    MAP ("sectoff@ha",         (int) BFD_RELOC_HI16_S_BASEREL),
+    MAP ("naddr",              (int) BFD_RELOC_PPC_EMB_NADDR32),
+    MAP ("naddr16",            (int) BFD_RELOC_PPC_EMB_NADDR16),
+    MAP ("naddr@l",            (int) BFD_RELOC_PPC_EMB_NADDR16_LO),
+    MAP ("naddr@h",            (int) BFD_RELOC_PPC_EMB_NADDR16_HI),
+    MAP ("naddr@ha",           (int) BFD_RELOC_PPC_EMB_NADDR16_HA),
+    MAP ("sdai16",             (int) BFD_RELOC_PPC_EMB_SDAI16),
+    MAP ("sda2rel",            (int) BFD_RELOC_PPC_EMB_SDA2REL),
+    MAP ("sda2i16",            (int) BFD_RELOC_PPC_EMB_SDA2I16),
+    MAP ("sda21",              (int) BFD_RELOC_PPC_EMB_SDA21),
+    MAP ("mrkref",             (int) BFD_RELOC_PPC_EMB_MRKREF),
+    MAP ("relsect",            (int) BFD_RELOC_PPC_EMB_RELSEC16),
+    MAP ("relsect@l",          (int) BFD_RELOC_PPC_EMB_RELST_LO),
+    MAP ("relsect@h",          (int) BFD_RELOC_PPC_EMB_RELST_HI),
+    MAP ("relsect@ha",         (int) BFD_RELOC_PPC_EMB_RELST_HA),
+    MAP ("bitfld",             (int) BFD_RELOC_PPC_EMB_BIT_FLD),
+    MAP ("relsda",             (int) BFD_RELOC_PPC_EMB_RELSDA),
+    MAP ("xgot",               (int) BFD_RELOC_PPC_TOC16),
+    MAP ("tls",                        (int) BFD_RELOC_PPC_TLS),
+    MAP ("dtpmod",             (int) BFD_RELOC_PPC_DTPMOD),
+    MAP ("dtprel",             (int) BFD_RELOC_PPC_DTPREL),
+    MAP ("dtprel@l",           (int) BFD_RELOC_PPC_DTPREL16_LO),
+    MAP ("dtprel@h",           (int) BFD_RELOC_PPC_DTPREL16_HI),
+    MAP ("dtprel@ha",          (int) BFD_RELOC_PPC_DTPREL16_HA),
+    MAP ("tprel",              (int) BFD_RELOC_PPC_TPREL),
+    MAP ("tprel@l",            (int) BFD_RELOC_PPC_TPREL16_LO),
+    MAP ("tprel@h",            (int) BFD_RELOC_PPC_TPREL16_HI),
+    MAP ("tprel@ha",           (int) BFD_RELOC_PPC_TPREL16_HA),
+    MAP ("got@tlsgd",          (int) BFD_RELOC_PPC_GOT_TLSGD16),
+    MAP ("got@tlsgd@l",                (int) BFD_RELOC_PPC_GOT_TLSGD16_LO),
+    MAP ("got@tlsgd@h",                (int) BFD_RELOC_PPC_GOT_TLSGD16_HI),
+    MAP ("got@tlsgd@ha",       (int) BFD_RELOC_PPC_GOT_TLSGD16_HA),
+    MAP ("got@tlsld",          (int) BFD_RELOC_PPC_GOT_TLSLD16),
+    MAP ("got@tlsld@l",                (int) BFD_RELOC_PPC_GOT_TLSLD16_LO),
+    MAP ("got@tlsld@h",                (int) BFD_RELOC_PPC_GOT_TLSLD16_HI),
+    MAP ("got@tlsld@ha",       (int) BFD_RELOC_PPC_GOT_TLSLD16_HA),
+    MAP ("got@dtprel",         (int) BFD_RELOC_PPC_GOT_DTPREL16),
+    MAP ("got@dtprel@l",       (int) BFD_RELOC_PPC_GOT_DTPREL16_LO),
+    MAP ("got@dtprel@h",       (int) BFD_RELOC_PPC_GOT_DTPREL16_HI),
+    MAP ("got@dtprel@ha",      (int) BFD_RELOC_PPC_GOT_DTPREL16_HA),
+    MAP ("got@tprel",          (int) BFD_RELOC_PPC_GOT_TPREL16),
+    MAP ("got@tprel@l",                (int) BFD_RELOC_PPC_GOT_TPREL16_LO),
+    MAP ("got@tprel@h",                (int) BFD_RELOC_PPC_GOT_TPREL16_HI),
+    MAP ("got@tprel@ha",       (int) BFD_RELOC_PPC_GOT_TPREL16_HA),
+    /* The following are only valid for ppc64.  Negative values are
+       used instead of a flag.  */
+    MAP ("higher",             - (int) BFD_RELOC_PPC64_HIGHER),
+    MAP ("highera",            - (int) BFD_RELOC_PPC64_HIGHER_S),
+    MAP ("highest",            - (int) BFD_RELOC_PPC64_HIGHEST),
+    MAP ("highesta",           - (int) BFD_RELOC_PPC64_HIGHEST_S),
+    MAP ("tocbase",            - (int) BFD_RELOC_PPC64_TOC),
+    MAP ("toc",                        - (int) BFD_RELOC_PPC_TOC16),
+    MAP ("toc@l",              - (int) BFD_RELOC_PPC64_TOC16_LO),
+    MAP ("toc@h",              - (int) BFD_RELOC_PPC64_TOC16_HI),
+    MAP ("toc@ha",             - (int) BFD_RELOC_PPC64_TOC16_HA),
+    MAP ("dtprel@higher",      - (int) BFD_RELOC_PPC64_DTPREL16_HIGHER),
+    MAP ("dtprel@highera",     - (int) BFD_RELOC_PPC64_DTPREL16_HIGHERA),
+    MAP ("dtprel@highest",     - (int) BFD_RELOC_PPC64_DTPREL16_HIGHEST),
+    MAP ("dtprel@highesta",    - (int) BFD_RELOC_PPC64_DTPREL16_HIGHESTA),
+    MAP ("tprel@higher",       - (int) BFD_RELOC_PPC64_TPREL16_HIGHER),
+    MAP ("tprel@highera",      - (int) BFD_RELOC_PPC64_TPREL16_HIGHERA),
+    MAP ("tprel@highest",      - (int) BFD_RELOC_PPC64_TPREL16_HIGHEST),
+    MAP ("tprel@highesta",     - (int) BFD_RELOC_PPC64_TPREL16_HIGHESTA),
+    { (char *) 0, 0,           (int) BFD_RELOC_UNUSED }
   };
 
   if (*str++ != '@')
@@ -1398,12 +1589,22 @@ ppc_elf_suffix (str_p, exp_p)
        && len == ptr->length
        && memcmp (ident, ptr->string, ptr->length) == 0)
       {
-       if (exp_p->X_add_number != 0
-           && (ptr->reloc == BFD_RELOC_16_GOTOFF
-               || ptr->reloc == BFD_RELOC_LO16_GOTOFF
-               || ptr->reloc == BFD_RELOC_HI16_GOTOFF
-               || ptr->reloc == BFD_RELOC_HI16_S_GOTOFF))
-         as_warn (_("identifier+constant@got means identifier@got+constant"));
+       int reloc = ptr->reloc;
+
+       if (reloc < 0)
+         {
+           if (!ppc_obj64)
+             return BFD_RELOC_UNUSED;
+           reloc = -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"));
 
        /* Now check for identifier@suffix+constant.  */
        if (*str == '-' || *str == '+')
@@ -1424,17 +1625,16 @@ ppc_elf_suffix (str_p, exp_p)
          }
        *str_p = str;
 
-       if (BFD_DEFAULT_TARGET_SIZE == 64
-           && ptr->reloc == BFD_RELOC_PPC64_TOC
-           && exp_p->X_op == O_symbol)
+       if (reloc == (int) BFD_RELOC_PPC64_TOC
+           && exp_p->X_op == O_symbol
+           && strcmp (S_GET_NAME (exp_p->X_add_symbol), ".TOC.") == 0)
          {
-           /* This reloc type ignores the symbol.  Change the symbol
-              so that the dummy .TOC. symbol can be omitted from the
-              object file.  */
+           /* Change the symbol so that the dummy .TOC. symbol can be
+              omitted from the object file.  */
            exp_p->X_add_symbol = &abs_symbol;
          }
 
-       return ptr->reloc;
+       return (bfd_reloc_code_real_type) reloc;
       }
 
   return BFD_RELOC_UNUSED;
@@ -1643,7 +1843,7 @@ ppc_elf_validate_fix (fixp, seg)
          && fixp->fx_r_type != BFD_RELOC_HI16_GOTOFF
          && fixp->fx_r_type != BFD_RELOC_LO16_GOTOFF
          && fixp->fx_r_type != BFD_RELOC_HI16_S_GOTOFF
-         && fixp->fx_r_type != BFD_RELOC_32_BASEREL
+         && fixp->fx_r_type != BFD_RELOC_16_BASEREL
          && fixp->fx_r_type != BFD_RELOC_LO16_BASEREL
          && fixp->fx_r_type != BFD_RELOC_HI16_BASEREL
          && fixp->fx_r_type != BFD_RELOC_HI16_S_BASEREL
@@ -1667,24 +1867,50 @@ ppc_elf_validate_fix (fixp, seg)
     }
 }
 
-#if BFD_DEFAULT_TARGET_SIZE == 64
-/* Don't emit .TOC. symbol.  */
-int
-ppc_elf_frob_symbol (sym)
-     symbolS *sym;
+/* Prevent elf_frob_file_before_adjust removing a weak undefined
+   function descriptor sym if the corresponding code sym is used.  */
+
+void
+ppc_frob_file_before_adjust ()
 {
-  const char *name;
+  symbolS *symp;
+
+  if (!ppc_obj64)
+    return;
 
-  name = S_GET_NAME (sym);
-  if (name != NULL && strcmp (name, ".TOC.") == 0)
+  for (symp = symbol_rootP; symp; symp = symbol_next (symp))
     {
-      S_CLEAR_EXTERNAL (sym);
-      return 1;
+      const char *name;
+      char *dotname;
+      symbolS *dotsym;
+      size_t len;
+
+      name = S_GET_NAME (symp);
+      if (name[0] == '.')
+       continue;
+
+      if (! S_IS_WEAK (symp)
+         || S_IS_DEFINED (symp))
+       continue;
+
+      len = strlen (name) + 1;
+      dotname = xmalloc (len + 1);
+      dotname[0] = '.';
+      memcpy (dotname + 1, name, len);
+      dotsym = symbol_find (dotname);
+      free (dotname);
+      if (dotsym != NULL && (symbol_used_p (dotsym)
+                            || symbol_used_in_reloc_p (dotsym)))
+       {
+         symbol_mark_used (symp);
+       }
     }
 
-  return 0;
+  /* Don't emit .TOC. symbol.  */
+  symp = symbol_find (".TOC.");
+  if (symp != NULL)
+    symbol_remove (symp, &symbol_rootP, &symbol_lastP);
 }
-#endif
 #endif /* OBJ_ELF */
 \f
 #ifdef TE_PE
@@ -1785,6 +2011,40 @@ parse_toc_entry (toc_kind)
 #endif
 \f
 
+#ifdef OBJ_ELF
+#define APUID(a,v)     ((((a) & 0xffff) << 16) | ((v) & 0xffff))
+static void
+ppc_apuinfo_section_add (apu, version)
+      unsigned int apu, version;
+{
+  unsigned int i;
+
+  /* Check we don't already exist.  */
+  for (i = 0; i < ppc_apuinfo_num; i++)
+    if (ppc_apuinfo_list[i] == APUID (apu, version))
+      return;
+
+  if (ppc_apuinfo_num == ppc_apuinfo_num_alloc)
+    {
+      if (ppc_apuinfo_num_alloc == 0)
+       {
+         ppc_apuinfo_num_alloc = 4;
+         ppc_apuinfo_list = (unsigned long *)
+             xmalloc (sizeof (unsigned long) * ppc_apuinfo_num_alloc);
+       }
+      else
+       {
+         ppc_apuinfo_num_alloc += 4;
+         ppc_apuinfo_list = (unsigned long *) xrealloc (ppc_apuinfo_list,
+             sizeof (unsigned long) * ppc_apuinfo_num_alloc);
+       }
+    }
+  ppc_apuinfo_list[ppc_apuinfo_num++] = APUID (apu, version);
+}
+#undef APUID
+#endif
+\f
+
 /* We need to keep a list of fixups.  We can't simply generate them as
    we go, because that would require us to first create the frag, and
    that would screw up references to ``.''.  */
@@ -1864,6 +2124,8 @@ md_assemble (str)
       if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0)
        {
          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.  */
@@ -1880,10 +2142,16 @@ md_assemble (str)
                }
            }
 
+         /* Compute the number of expected operands.
+            Do not count fake operands.  */
+         for (num_operands_expected = 0, i = 0; opcode->operands[i]; i ++)
+           if ((powerpc_operands [opcode->operands[i]].flags & PPC_OPERAND_FAKE) == 0)
+             ++ num_operands_expected;
+
          /* If there are fewer operands in the line then are called
             for by the instruction, we want to skip the optional
             operand.  */
-         if (opcount < strlen (opcode->operands))
+         if (opcount < num_operands_expected)
            skip_optional = 1;
 
          break;
@@ -1909,14 +2177,13 @@ md_assemble (str)
          operand = &powerpc_operands[next_opindex];
          next_opindex = 0;
        }
-
       errmsg = NULL;
 
       /* If this is a fake operand, then we do not expect anything
         from the input.  */
       if ((operand->flags & PPC_OPERAND_FAKE) != 0)
        {
-         insn = (*operand->insert) (insn, 0L, &errmsg);
+         insn = (*operand->insert) (insn, 0L, ppc_cpu, &errmsg);
          if (errmsg != (const char *) NULL)
            as_bad (errmsg);
          continue;
@@ -1929,7 +2196,7 @@ md_assemble (str)
        {
          if (operand->insert)
            {
-             insn = (*operand->insert) (insn, 0L, &errmsg);
+             insn = (*operand->insert) (insn, 0L, ppc_cpu, &errmsg);
              if (errmsg != (const char *) NULL)
                as_bad (errmsg);
            }
@@ -2060,9 +2327,9 @@ md_assemble (str)
          if (! register_name (&ex))
            {
              if ((operand->flags & PPC_OPERAND_CR) != 0)
-               cr_operand = true;
+               cr_operand = TRUE;
              expression (&ex);
-             cr_operand = false;
+             cr_operand = FALSE;
            }
        }
 
@@ -2115,7 +2382,6 @@ md_assemble (str)
                  ex.X_add_number = SEX16 (PPC_HA (ex.X_add_number));
                break;
 
-#if BFD_DEFAULT_TARGET_SIZE == 64
              case BFD_RELOC_PPC64_HIGHER:
                if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
                  ex.X_add_number = PPC_HIGHER (ex.X_add_number);
@@ -2143,7 +2409,6 @@ md_assemble (str)
                else
                  ex.X_add_number = SEX16 (PPC_HIGHESTA (ex.X_add_number));
                break;
-#endif /* BFD_DEFAULT_TARGET_SIZE == 64 */
              }
 #endif /* OBJ_ELF */
          insn = ppc_insert_operand (insn, operand, ex.X_add_number,
@@ -2152,6 +2417,25 @@ md_assemble (str)
 #ifdef OBJ_ELF
       else if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
        {
+         /* Some TLS tweaks.  */
+         switch (reloc)
+           {
+           default:
+             break;
+           case BFD_RELOC_PPC_TLS:
+             insn = ppc_insert_operand (insn, operand, ppc_obj64 ? 13 : 2,
+                                        (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;
+           }
+
          /* For the absolute forms of branches, convert the PC
             relative form back into the absolute.  */
          if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
@@ -2175,9 +2459,8 @@ md_assemble (str)
                }
            }
 
-         if (BFD_DEFAULT_TARGET_SIZE == 64
-             && ppc_size == PPC_OPCODE_64
-             && (operand->flags & PPC_OPERAND_DS) != 0)
+         if (ppc_obj64
+             && (operand->flags & (PPC_OPERAND_DS | PPC_OPERAND_DQ)) != 0)
            {
              switch (reloc)
                {
@@ -2196,7 +2479,7 @@ md_assemble (str)
                case BFD_RELOC_LO16_PLTOFF:
                  reloc = BFD_RELOC_PPC64_PLT16_LO_DS;
                  break;
-               case BFD_RELOC_32_BASEREL:
+               case BFD_RELOC_16_BASEREL:
                  reloc = BFD_RELOC_PPC64_SECTOFF_DS;
                  break;
                case BFD_RELOC_LO16_BASEREL:
@@ -2214,6 +2497,23 @@ md_assemble (str)
                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;
@@ -2273,6 +2573,31 @@ md_assemble (str)
   if (*str != '\0')
     as_bad (_("junk at end of line: `%s'"), str);
 
+#ifdef OBJ_ELF
+  /* Do we need/want a APUinfo section? */
+  if (ppc_cpu & (PPC_OPCODE_SPE
+              | PPC_OPCODE_ISEL | PPC_OPCODE_EFS
+              | PPC_OPCODE_BRLOCK | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK
+              | PPC_OPCODE_RFMCI))
+    {
+      /* These are all version "1".  */
+      if (opcode->flags & PPC_OPCODE_SPE)
+       ppc_apuinfo_section_add (PPC_APUINFO_SPE, 1);
+      if (opcode->flags & PPC_OPCODE_ISEL)
+       ppc_apuinfo_section_add (PPC_APUINFO_ISEL, 1);
+      if (opcode->flags & PPC_OPCODE_EFS)
+       ppc_apuinfo_section_add (PPC_APUINFO_EFS, 1);
+      if (opcode->flags & PPC_OPCODE_BRLOCK)
+       ppc_apuinfo_section_add (PPC_APUINFO_BRLOCK, 1);
+      if (opcode->flags & PPC_OPCODE_PMR)
+       ppc_apuinfo_section_add (PPC_APUINFO_PMR, 1);
+      if (opcode->flags & PPC_OPCODE_CACHELCK)
+       ppc_apuinfo_section_add (PPC_APUINFO_CACHELCK, 1);
+      if (opcode->flags & PPC_OPCODE_RFMCI)
+       ppc_apuinfo_section_add (PPC_APUINFO_RFMCI, 1);
+    }
+#endif
+
   /* Write out the instruction.  */
   f = frag_more (4);
   md_number_to_chars (f, insn, 4);
@@ -2286,7 +2611,7 @@ md_assemble (str)
      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.  */
+     md_apply_fix3.  */
   for (i = 0; i < fc; i++)
     {
       const struct powerpc_operand *operand;
@@ -2326,12 +2651,10 @@ md_assemble (str)
            case BFD_RELOC_HI16:
            case BFD_RELOC_HI16_S:
 #ifdef OBJ_ELF
-#if BFD_DEFAULT_TARGET_SIZE == 64
            case BFD_RELOC_PPC64_HIGHER:
            case BFD_RELOC_PPC64_HIGHER_S:
            case BFD_RELOC_PPC64_HIGHEST:
            case BFD_RELOC_PPC64_HIGHEST_S:
-#endif
 #endif
              fixP->fx_no_overflow = 1;
              break;
@@ -2441,8 +2764,8 @@ ppc_section_letter (letter, ptr_msg)
   if (letter == 'e')
     return SHF_EXCLUDE;
 
-  *ptr_msg = _("Bad .section directive: want a,e,w,x,M,S in string");
-  return 0;
+  *ptr_msg = _("Bad .section directive: want a,e,w,x,M,S,G,T in string");
+  return -1;
 }
 
 int
@@ -2527,7 +2850,7 @@ ppc_byte (ignore)
 
 /* This is set if we are creating a .stabx symbol, since we don't want
    to handle symbol suffixes for such symbols.  */
-static boolean ppc_stab_symbol;
+static bfd_boolean ppc_stab_symbol;
 
 /* The .comm and .lcomm pseudo-ops for XCOFF.  XCOFF puts common
    symbols in the .bss segment as though they were local common
@@ -2696,6 +3019,7 @@ ppc_csect (ignore)
   char *name;
   char endc;
   symbolS *sym;
+  offsetT align;
 
   name = input_line_pointer;
   endc = get_symbol_end ();
@@ -2710,22 +3034,24 @@ ppc_csect (ignore)
       symbol_get_tc (sym)->class = XMC_PR;
     }
 
-  ppc_change_csect (sym);
-
+  align = 2;
   if (*input_line_pointer == ',')
     {
       ++input_line_pointer;
-      symbol_get_tc (sym)->align = get_absolute_expression ();
+      align = get_absolute_expression ();
     }
 
+  ppc_change_csect (sym, align);
+
   demand_empty_rest_of_line ();
 }
 
 /* Change to a different csect.  */
 
 static void
-ppc_change_csect (sym)
+ppc_change_csect (sym, align)
      symbolS *sym;
+     offsetT align;
 {
   if (S_IS_DEFINED (sym))
     subseg_set (S_GET_SEGMENT (sym), symbol_get_tc (sym)->subseg);
@@ -2735,11 +3061,14 @@ ppc_change_csect (sym)
       int after_toc;
       int hold_chunksize;
       symbolS *list;
+      int is_code;
+      segT sec;
 
       /* This is a new csect.  We need to look at the symbol class to
         figure out whether it should go in the text section or the
         data section.  */
       after_toc = 0;
+      is_code = 0;
       switch (symbol_get_tc (sym)->class)
        {
        case XMC_PR:
@@ -2754,6 +3083,7 @@ ppc_change_csect (sym)
          symbol_get_tc (sym)->subseg = ppc_text_subsegment;
          ++ppc_text_subsegment;
          list_ptr = &ppc_text_csects;
+         is_code = 1;
          break;
        case XMC_RW:
        case XMC_TC0:
@@ -2781,18 +3111,24 @@ ppc_change_csect (sym)
       hold_chunksize = chunksize;
       chunksize = 64;
 
-      subseg_new (segment_name (S_GET_SEGMENT (sym)),
-                 symbol_get_tc (sym)->subseg);
+      sec = subseg_new (segment_name (S_GET_SEGMENT (sym)),
+                       symbol_get_tc (sym)->subseg);
 
       chunksize = hold_chunksize;
 
       if (after_toc)
        ppc_after_toc_frag = frag_now;
 
+      record_alignment (sec, align);
+      if (is_code)
+       frag_align_code (align, 0);
+      else
+       frag_align (align, 0, 0);
+
       symbol_set_frag (sym, frag_now);
       S_SET_VALUE (sym, (valueT) frag_now_fix ());
 
-      symbol_get_tc (sym)->align = (ppc_xcoff64) ? 3 : 2;
+      symbol_get_tc (sym)->align = align;
       symbol_get_tc (sym)->output = 1;
       symbol_get_tc (sym)->within = sym;
 
@@ -2830,7 +3166,7 @@ ppc_section (type)
 
   sym = symbol_find_or_make (name);
 
-  ppc_change_csect (sym);
+  ppc_change_csect (sym, 2);
 
   demand_empty_rest_of_line ();
 }
@@ -2867,7 +3203,7 @@ ppc_named_section (ignore)
 
   sym = symbol_find_or_make (real_name);
 
-  ppc_change_csect (sym);
+  ppc_change_csect (sym, 2);
 
   demand_empty_rest_of_line ();
 }
@@ -2970,9 +3306,9 @@ ppc_stabx (ignore)
     }
   ++input_line_pointer;
 
-  ppc_stab_symbol = true;
+  ppc_stab_symbol = TRUE;
   sym = symbol_make (name);
-  ppc_stab_symbol = false;
+  ppc_stab_symbol = FALSE;
 
   symbol_get_tc (sym)->real_name = name;
 
@@ -3170,7 +3506,7 @@ ppc_function (ignore)
 /* The .bf pseudo-op.  This is just like a COFF C_FCN symbol named
    ".bf".  If the pseudo op .bi was seen before .bf, patch the .bi sym
    with the correct line number */
+
 static symbolS *saved_bi_sym = 0;
 
 static void
@@ -3191,12 +3527,12 @@ ppc_bf (ignore)
   SA_SET_SYM_LNNO (sym, coff_line_base);
 
   /* Line number for bi.  */
-  if (saved_bi_sym) 
+  if (saved_bi_sym)
     {
       S_SET_VALUE (saved_bi_sym, coff_n_line_nos);
       saved_bi_sym = 0;
     }
-  
+
 
   symbol_get_tc (sym)->output = 1;
 
@@ -3263,7 +3599,7 @@ ppc_biei (ei)
   symbol_get_tc (sym)->output = 1;
 
   /* Save bi.  */
-  if (ei) 
+  if (ei)
     saved_bi_sym = 0;
   else
     saved_bi_sym = sym;
@@ -3538,7 +3874,7 @@ ppc_vbyte (dummy)
    give to this location in the toc; this will be a symbol with class
    TC.  The rest of the arguments are N-byte values to actually put at
    this location in the TOC; often there is just one more argument, a
-   relocateable symbol reference.  The size of the value to store
+   relocatable symbol reference.  The size of the value to store
    depends on target word size.  A 32-bit target uses 4-byte values, a
    64-bit target uses 8-byte values.
 
@@ -3616,7 +3952,7 @@ ppc_tc (ignore)
     ++input_line_pointer;
 
   /* Align to a four/eight byte boundary.  */
-  align = BFD_DEFAULT_TARGET_SIZE == 64 && ppc_size == PPC_OPCODE_64 ? 3 : 2;
+  align = ppc_obj64 ? 3 : 2;
   frag_align (align, 0, 0);
   record_alignment (now_seg, align);
 #endif /* OBJ_ELF */
@@ -3626,12 +3962,17 @@ ppc_tc (ignore)
   else
     {
       ++input_line_pointer;
-      cons ((ppc_size == PPC_OPCODE_64) ? 8 : 4);
+      cons (ppc_obj64 ? 8 : 4);
     }
 }
 
 /* Pseudo-op .machine.  */
-/* FIXME: `.machine' is a nop for the moment.  */
+/* FIXME: `.machine' is a nop for the moment.  It would be nice to
+   accept this directive on the first line of input and set ppc_obj64
+   and the target format accordingly.  Unfortunately, the target
+   format is selected in output-file.c:output_file_create before we
+   even get to md_begin, so it's not possible without changing
+   as.c:main.  */
 
 static void
 ppc_machine (ignore)
@@ -3651,7 +3992,7 @@ ppc_is_toc_sym (sym)
 #endif
 #ifdef OBJ_ELF
   const char *sname = segment_name (S_GET_SEGMENT (sym));
-  if (BFD_DEFAULT_TARGET_SIZE == 64 && ppc_size == PPC_OPCODE_64)
+  if (ppc_obj64)
     return strcmp (sname, ".toc") == 0;
   else
     return strcmp (sname, ".got") == 0;
@@ -3696,11 +4037,11 @@ ppc_previous (ignore)
 
 /* pseudo-op: .pdata
    behaviour: predefined read only data section
-              double word aligned
+             double word aligned
    errors:    None
    warnings:  None
    initial:   .section .pdata "adr3"
-              a - don't know -- maybe a misprint
+             a - don't know -- maybe a misprint
              d - initialized data
              r - readable
              3 - double word aligned (that would be 4 byte boundary)
@@ -3732,11 +4073,11 @@ ppc_pdata (ignore)
 
 /* pseudo-op: .ydata
    behaviour: predefined read only data section
-              double word aligned
+             double word aligned
    errors:    None
    warnings:  None
    initial:   .section .ydata "drw3"
-              a - don't know -- maybe a misprint
+             a - don't know -- maybe a misprint
              d - initialized data
              r - readable
              3 - double word aligned (that would be 4 byte boundary)
@@ -3766,7 +4107,7 @@ ppc_ydata (ignore)
 
 /* pseudo-op: .reldata
    behaviour: predefined read write data section
-              double word aligned (4-byte)
+             double word aligned (4-byte)
              FIXME: relocation is applied to it
              FIXME: what's the difference between this and .data?
    errors:    None
@@ -3804,7 +4145,7 @@ ppc_reldata (ignore)
 
 /* pseudo-op: .rdata
    behaviour: predefined read only data section
-              double word aligned
+             double word aligned
    errors:    None
    warnings:  None
    initial:   .section .rdata "dr3"
@@ -3834,7 +4175,7 @@ ppc_rdata (ignore)
 
 /* pseudo-op: .ualong
    behaviour: much like .int, with the exception that no alignment is
-              performed.
+             performed.
              FIXME: test the alignment statement
    errors:    None
    warnings:  None  */
@@ -3849,7 +4190,7 @@ ppc_ualong (ignore)
 
 /* pseudo-op: .znop  <symbol name>
    behaviour: Issue a nop instruction
-              Issue a IMAGE_REL_PPC_IFGLUE relocation against it, using
+             Issue a IMAGE_REL_PPC_IFGLUE relocation against it, using
              the supplied symbol name.
    errors:    None
    warnings:  Missing symbol name  */
@@ -4411,7 +4752,7 @@ ppc_frob_label (sym)
    seen.  It tells ppc_adjust_symtab whether it needs to look through
    the symbols.  */
 
-static boolean ppc_saw_abs;
+static bfd_boolean ppc_saw_abs;
 
 /* Change the name of a symbol just before writing it out.  Set the
    real name if the .rename pseudo-op was used.  Otherwise, remove any
@@ -4434,6 +4775,10 @@ ppc_frob_symbol (sym)
              && S_GET_STORAGE_CLASS (sym) != C_FILE)))
     return 1;
 
+  /* This one will disappear anyway.  Don't make a csect sym for it.  */
+  if (sym == abs_section_sym)
+    return 1;
+
   if (symbol_get_tc (sym)->real_name != (char *) NULL)
     S_SET_NAME (sym, symbol_get_tc (sym)->real_name);
   else
@@ -4550,7 +4895,7 @@ ppc_frob_symbol (sym)
        {
          /* This is an absolute symbol.  The csect will be created by
             ppc_adjust_symtab.  */
-         ppc_saw_abs = true;
+         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;
@@ -4646,10 +4991,10 @@ ppc_frob_symbol (sym)
       /* We want the value to be the symbol index of the referenced
         csect symbol.  BFD will do that for us if we set the right
         flags.  */
-      S_SET_VALUE (sym,
-                  ((valueT)
-                   coffsymbol (symbol_get_bfdsym
-                               (symbol_get_tc (sym)->within))->native));
+      asymbol *bsym = symbol_get_bfdsym (symbol_get_tc (sym)->within);
+      combined_entry_type *c = coffsymbol (bsym)->native;
+
+      S_SET_VALUE (sym, (valueT) (size_t) c);
       coffsymbol (symbol_get_bfdsym (sym))->native->fix_value = 1;
     }
   else if (S_GET_STORAGE_CLASS (sym) == C_STSYM)
@@ -4718,7 +5063,7 @@ ppc_adjust_symtab ()
       coffsymbol (symbol_get_bfdsym (sym))->native[i].fix_scnlen = 1;
     }
 
-  ppc_saw_abs = false;
+  ppc_saw_abs = FALSE;
 }
 
 /* Set the VMA for a section.  This is called on all the sections in
@@ -4728,8 +5073,9 @@ void
 ppc_frob_section (sec)
      asection *sec;
 {
-  static bfd_size_type vma = 0;
+  static bfd_vma vma = 0;
 
+  vma = md_section_align (sec, vma);
   bfd_set_section_vma (stdoutput, sec, vma);
   vma += bfd_section_size (stdoutput, sec);
 }
@@ -4875,14 +5221,16 @@ int
 ppc_fix_adjustable (fix)
      fixS *fix;
 {
-  valueT val;
+  valueT val = resolve_symbol_value (fix->fx_addsy);
+  segT symseg = S_GET_SEGMENT (fix->fx_addsy);
+  TC_SYMFIELD_TYPE *tc;
+
+  if (symseg == absolute_section)
+    return 0;
 
-  resolve_symbol_value (fix->fx_addsy);
-  val = S_GET_VALUE (fix->fx_addsy);
   if (ppc_toc_csect != (symbolS *) NULL
-      && fix->fx_addsy != (symbolS *) NULL
       && fix->fx_addsy != ppc_toc_csect
-      && S_GET_SEGMENT (fix->fx_addsy) == data_section
+      && symseg == data_section
       && val >= ppc_toc_frag->fr_address
       && (ppc_after_toc_frag == (fragS *) NULL
          || val < ppc_after_toc_frag->fr_address))
@@ -4893,12 +5241,13 @@ ppc_fix_adjustable (fix)
           sy != (symbolS *) NULL;
           sy = symbol_next (sy))
        {
-         if (symbol_get_tc (sy)->class == XMC_TC0)
+         TC_SYMFIELD_TYPE *sy_tc = symbol_get_tc (sy);
+
+         if (sy_tc->class == XMC_TC0)
            continue;
-         if (symbol_get_tc (sy)->class != XMC_TC)
+         if (sy_tc->class != XMC_TC)
            break;
-         resolve_symbol_value (sy);
-         if (val == S_GET_VALUE (sy))
+         if (val == resolve_symbol_value (sy))
            {
              fix->fx_addsy = sy;
              fix->fx_addnumber = val - ppc_toc_frag->fr_address;
@@ -4911,23 +5260,24 @@ ppc_fix_adjustable (fix)
     }
 
   /* Possibly adjust the reloc to be against the csect.  */
-  if (fix->fx_addsy != (symbolS *) NULL
-      && symbol_get_tc (fix->fx_addsy)->subseg == 0
-      && symbol_get_tc (fix->fx_addsy)->class != XMC_TC0
-      && symbol_get_tc (fix->fx_addsy)->class != XMC_TC
-      && S_GET_SEGMENT (fix->fx_addsy) != bss_section
+  tc = symbol_get_tc (fix->fx_addsy);
+  if (tc->subseg == 0
+      && tc->class != XMC_TC0
+      && tc->class != XMC_TC
+      && symseg != bss_section
       /* Don't adjust if this is a reloc in the toc section.  */
-      && (S_GET_SEGMENT (fix->fx_addsy) != data_section
+      && (symseg != data_section
          || ppc_toc_csect == NULL
          || val < ppc_toc_frag->fr_address
          || (ppc_after_toc_frag != NULL
              && val >= ppc_after_toc_frag->fr_address)))
     {
       symbolS *csect;
+      symbolS *next_csect;
 
-      if (S_GET_SEGMENT (fix->fx_addsy) == text_section)
+      if (symseg == text_section)
        csect = ppc_text_csects;
-      else if (S_GET_SEGMENT (fix->fx_addsy) == data_section)
+      else if (symseg == data_section)
        csect = ppc_data_csects;
       else
        abort ();
@@ -4937,16 +5287,15 @@ ppc_fix_adjustable (fix)
 
       if (csect != (symbolS *) NULL)
        {
-         while (symbol_get_tc (csect)->next != (symbolS *) NULL
-                && (symbol_get_frag (symbol_get_tc (csect)->next)->fr_address
-                    <= val))
+         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) == S_GET_VALUE (fix->fx_addsy))
+             if (symbol_get_frag (csect)->fr_address == val
+                 && S_GET_VALUE (csect) == val)
                {
                  symbolS *scan;
 
@@ -4966,26 +5315,24 @@ ppc_fix_adjustable (fix)
                    break;
                }
 
-             csect = symbol_get_tc (csect)->next;
+             csect = next_csect;
            }
 
-         fix->fx_offset += (S_GET_VALUE (fix->fx_addsy)
-                            - symbol_get_frag (csect)->fr_address);
+         fix->fx_offset += val - symbol_get_frag (csect)->fr_address;
          fix->fx_addsy = csect;
        }
+      return 0;
     }
 
   /* Adjust a reloc against a .lcomm symbol to be against the base
      .lcomm.  */
-  if (fix->fx_addsy != (symbolS *) NULL
-      && S_GET_SEGMENT (fix->fx_addsy) == bss_section
+  if (symseg == bss_section
       && ! S_IS_EXTERNAL (fix->fx_addsy))
     {
-      resolve_symbol_value (symbol_get_frag (fix->fx_addsy)->fr_symbol);
-      fix->fx_offset +=
-       (S_GET_VALUE (fix->fx_addsy)
-        - S_GET_VALUE (symbol_get_frag (fix->fx_addsy)->fr_symbol));
-      fix->fx_addsy = symbol_get_frag (fix->fx_addsy)->fr_symbol;
+      symbolS *sy = symbol_get_frag (fix->fx_addsy)->fr_symbol;
+
+      fix->fx_offset += val - resolve_symbol_value (sy);
+      fix->fx_addsy = sy;
     }
 
   return 0;
@@ -5013,12 +5360,40 @@ ppc_force_relocation (fix)
                  <= fix->fx_frag->fr_address))))
     return 1;
 
-  return 0;
+  return generic_force_reloc (fix);
 }
 
 #endif /* OBJ_XCOFF */
 
 #ifdef OBJ_ELF
+/* If this function returns non-zero, it guarantees that a relocation
+   will be emitted for a fixup.  */
+
+int
+ppc_force_relocation (fix)
+     fixS *fix;
+{
+  /* Branch prediction relocations must force a relocation, as must
+     the vtable description relocs.  */
+  switch (fix->fx_r_type)
+    {
+    case BFD_RELOC_PPC_B16_BRTAKEN:
+    case BFD_RELOC_PPC_B16_BRNTAKEN:
+    case BFD_RELOC_PPC_BA16_BRTAKEN:
+    case BFD_RELOC_PPC_BA16_BRNTAKEN:
+    case BFD_RELOC_PPC64_TOC:
+      return 1;
+    default:
+      break;
+    }
+
+  if (fix->fx_r_type >= BFD_RELOC_PPC_TLS
+      && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA)
+    return 1;
+
+  return generic_force_reloc (fix);
+}
+
 int
 ppc_fix_adjustable (fix)
      fixS *fix;
@@ -5030,8 +5405,8 @@ ppc_fix_adjustable (fix)
          && fix->fx_r_type != BFD_RELOC_GPREL16
          && fix->fx_r_type != BFD_RELOC_VTABLE_INHERIT
          && fix->fx_r_type != BFD_RELOC_VTABLE_ENTRY
-         && ! S_IS_EXTERNAL (fix->fx_addsy)
-         && ! S_IS_WEAK (fix->fx_addsy)
+         && !(fix->fx_r_type >= BFD_RELOC_PPC_TLS
+              && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA)
          && (fix->fx_pcrel
              || (fix->fx_subsy != NULL
                  && (S_GET_SEGMENT (fix->fx_subsy)
@@ -5049,79 +5424,58 @@ ppc_fix_adjustable (fix)
    that, we determine the correct reloc code and put it back in the
    fixup.  */
 
-int
-md_apply_fix3 (fixp, valuep, seg)
-     fixS *fixp;
-     valueT *valuep;
+void
+md_apply_fix3 (fixP, valP, seg)
+     fixS *fixP;
+     valueT * valP;
      segT seg ATTRIBUTE_UNUSED;
 {
-  valueT value;
+  valueT value = * valP;
 
 #ifdef OBJ_ELF
-  value = *valuep;
-  if (fixp->fx_addsy != NULL)
+  if (fixP->fx_addsy != NULL)
     {
-      /* `*valuep' may contain the value of the symbol on which the reloc
-        will be based; we have to remove it.  */
-      if (symbol_used_in_reloc_p (fixp->fx_addsy)
-         && S_GET_SEGMENT (fixp->fx_addsy) != absolute_section
-         && S_GET_SEGMENT (fixp->fx_addsy) != undefined_section
-         && ! bfd_is_com_section (S_GET_SEGMENT (fixp->fx_addsy)))
-       value -= S_GET_VALUE (fixp->fx_addsy);
-
-      /* FIXME: Why '+'?  Better yet, what exactly is '*valuep'
-        supposed to be?  I think this is related to various similar
-        FIXMEs in tc-i386.c and tc-sparc.c.  */
-      if (fixp->fx_pcrel)
-       value += fixp->fx_frag->fr_address + fixp->fx_where;
+      /* Hack around bfd_install_relocation brain damage.  */
+      if (fixP->fx_pcrel)
+       value += fixP->fx_frag->fr_address + fixP->fx_where;
     }
   else
-    {
-      fixp->fx_done = 1;
-    }
+    fixP->fx_done = 1;
 #else
-  /* FIXME FIXME FIXME: The value we are passed in *valuep includes
+  /* FIXME FIXME FIXME: The value we are passed in *valP includes
      the symbol values.  Since we are using BFD_ASSEMBLER, if we are
      doing this relocation the code in write.c is going to call
      bfd_install_relocation, which is also going to use the symbol
      value.  That means that if the reloc is fully resolved we want to
-     use *valuep since bfd_install_relocation is not being used.
+     use *valP since bfd_install_relocation is not being used.
      However, if the reloc is not fully resolved we do not want to use
-     *valuep, and must use fx_offset instead.  However, if the reloc
-     is PC relative, we do want to use *valuep since it includes the
+     *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.  */
-  if (fixp->fx_addsy == (symbolS *) NULL)
-    {
-      value = *valuep;
-      fixp->fx_done = 1;
-    }
-  else if (fixp->fx_pcrel)
-    value = *valuep;
+  if (fixP->fx_addsy == (symbolS *) NULL)
+    fixP->fx_done = 1;
+
+  else if (fixP->fx_pcrel)
+    ;
+
   else
+    value = fixP->fx_offset;
+#endif
+
+  if (fixP->fx_subsy != (symbolS *) NULL)
     {
-      value = fixp->fx_offset;
-      if (fixp->fx_subsy != (symbolS *) NULL)
-       {
-         if (S_GET_SEGMENT (fixp->fx_subsy) == absolute_section)
-           value -= S_GET_VALUE (fixp->fx_subsy);
-         else
-           {
-             /* We can't actually support subtracting a symbol.  */
-             as_bad_where (fixp->fx_file, fixp->fx_line,
-                           _("expression too complex"));
-           }
-       }
+      /* We can't actually support subtracting a symbol.  */
+      as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
     }
-#endif
 
-  if ((int) fixp->fx_r_type >= (int) BFD_RELOC_UNUSED)
+  if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
     {
       int opindex;
       const struct powerpc_operand *operand;
       char *where;
       unsigned long insn;
 
-      opindex = (int) fixp->fx_r_type - (int) BFD_RELOC_UNUSED;
+      opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
 
       operand = &powerpc_operands[opindex];
 
@@ -5133,39 +5487,37 @@ md_apply_fix3 (fixp, valuep, seg)
       if ((operand->flags & PPC_OPERAND_PARENS) != 0
          && operand->bits == 16
          && operand->shift == 0
-         && operand->insert == NULL
-         && 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
-         && S_GET_SEGMENT (fixp->fx_addsy) != bss_section)
+         && (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
+         && S_GET_SEGMENT (fixP->fx_addsy) != bss_section)
        {
-         value = fixp->fx_offset;
-         fixp->fx_done = 1;
+         value = fixP->fx_offset;
+         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;
+      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);
       insn = ppc_insert_operand (insn, operand, (offsetT) value,
-                                fixp->fx_file, fixp->fx_line);
+                                fixP->fx_file, fixP->fx_line);
       if (target_big_endian)
        bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
       else
        bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
 
-      if (fixp->fx_done)
-       {
-         /* Nothing else to do here.  */
-         return 1;
-       }
+      if (fixP->fx_done)
+       /* Nothing else to do here.  */
+       return;
 
-      assert (fixp->fx_addsy != NULL);
+      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
@@ -5173,35 +5525,59 @@ md_apply_fix3 (fixp, valuep, seg)
       if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
          && operand->bits == 26
          && operand->shift == 0)
-       fixp->fx_r_type = BFD_RELOC_PPC_B26;
+       fixP->fx_r_type = BFD_RELOC_PPC_B26;
       else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
          && operand->bits == 16
          && operand->shift == 0)
-       fixp->fx_r_type = BFD_RELOC_PPC_B16;
+       {
+         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_ABSOLUTE) != 0
               && operand->bits == 26
               && operand->shift == 0)
-       fixp->fx_r_type = BFD_RELOC_PPC_BA26;
+       fixP->fx_r_type = BFD_RELOC_PPC_BA26;
       else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0
               && operand->bits == 16
               && operand->shift == 0)
-       fixp->fx_r_type = BFD_RELOC_PPC_BA16;
+       {
+         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->bits == 16
-              && operand->shift == 0
-              && ppc_is_toc_sym (fixp->fx_addsy))
+              && operand->shift == 0)
        {
-         fixp->fx_r_type = BFD_RELOC_PPC_TOC16;
+         if (ppc_is_toc_sym (fixP->fx_addsy))
+           {
+             fixP->fx_r_type = BFD_RELOC_PPC_TOC16;
 #ifdef OBJ_ELF
-         if (BFD_DEFAULT_TARGET_SIZE == 64
-             && ppc_size == PPC_OPCODE_64
-             && (operand->flags & PPC_OPERAND_DS) != 0)
-           fixp->fx_r_type = BFD_RELOC_PPC64_TOC16_DS;
+             if (ppc_obj64
+                 && (operand->flags & PPC_OPERAND_DS) != 0)
+               fixP->fx_r_type = BFD_RELOC_PPC64_TOC16_DS;
 #endif
-         fixp->fx_size = 2;
+           }
+         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;
+           fixP->fx_where += 2;
        }
 #endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */
       else
@@ -5211,50 +5587,49 @@ md_apply_fix3 (fixp, valuep, seg)
 
          /* 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,
+         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,
+           as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("unsupported relocation against %s"),
-                         S_GET_NAME (fixp->fx_addsy));
-         fixp->fx_done = 1;
-         return 1;
+                         S_GET_NAME (fixP->fx_addsy));
+         fixP->fx_done = 1;
+         return;
        }
     }
   else
     {
 #ifdef OBJ_ELF
-      ppc_elf_validate_fix (fixp, seg);
+      ppc_elf_validate_fix (fixP, seg);
 #endif
-      switch (fixp->fx_r_type)
+      switch (fixP->fx_r_type)
        {
        case BFD_RELOC_CTOR:
-         if (BFD_DEFAULT_TARGET_SIZE == 64 && ppc_size == PPC_OPCODE_64)
+         if (ppc_obj64)
            goto ctor64;
          /* fall through */
 
        case BFD_RELOC_32:
-         if (fixp->fx_pcrel)
-           fixp->fx_r_type = BFD_RELOC_32_PCREL;
+         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_32_BASEREL:
        case BFD_RELOC_PPC_EMB_NADDR32:
-         md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
+         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;
+         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,
+         md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
                              value, 8);
          break;
 
@@ -5266,6 +5641,7 @@ md_apply_fix3 (fixp, valuep, seg)
        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:
@@ -5283,26 +5659,24 @@ md_apply_fix3 (fixp, valuep, seg)
        case BFD_RELOC_PPC_EMB_RELSDA:
        case BFD_RELOC_PPC_TOC16:
 #ifdef OBJ_ELF
-#if BFD_DEFAULT_TARGET_SIZE == 64
        case BFD_RELOC_PPC64_TOC16_LO:
        case BFD_RELOC_PPC64_TOC16_HI:
        case BFD_RELOC_PPC64_TOC16_HA:
 #endif
-#endif
-         if (fixp->fx_pcrel)
+         if (fixP->fx_pcrel)
            {
-             if (fixp->fx_addsy != NULL)
-               as_bad_where (fixp->fx_file, fixp->fx_line,
+             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));
+                             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,
+               as_bad_where (fixP->fx_file, fixP->fx_line,
                              _("cannot emit PC relative %s relocation"),
-                             bfd_get_reloc_code_name (fixp->fx_r_type));
+                             bfd_get_reloc_code_name (fixP->fx_r_type));
            }
 
-         md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
+         md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
                              value, 2);
          break;
 
@@ -5310,46 +5684,45 @@ md_apply_fix3 (fixp, valuep, seg)
             lis %r3,(L1-L2)@ha
             where L1 and L2 are defined later.  */
        case BFD_RELOC_HI16:
-         if (fixp->fx_pcrel)
+         if (fixP->fx_pcrel)
            abort ();
-         md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
+         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)
+         if (fixP->fx_pcrel)
            abort ();
-         md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
+         md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
                              PPC_HA (value), 2);
          break;
 
 #ifdef OBJ_ELF
-#if BFD_DEFAULT_TARGET_SIZE == 64
        case BFD_RELOC_PPC64_HIGHER:
-         if (fixp->fx_pcrel)
+         if (fixP->fx_pcrel)
            abort ();
-         md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
+         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)
+         if (fixP->fx_pcrel)
            abort ();
-         md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
+         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)
+         if (fixP->fx_pcrel)
            abort ();
-         md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
+         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)
+         if (fixP->fx_pcrel)
            abort ();
-         md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
+         md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
                              PPC_HIGHESTA (value), 2);
          break;
 
@@ -5364,67 +5737,119 @@ md_apply_fix3 (fixp, valuep, seg)
        case BFD_RELOC_PPC64_TOC16_LO_DS:
        case BFD_RELOC_PPC64_PLTGOT16_DS:
        case BFD_RELOC_PPC64_PLTGOT16_LO_DS:
-         if (fixp->fx_pcrel)
+         if (fixP->fx_pcrel)
            abort ();
          {
-           unsigned char *where = fixp->fx_frag->fr_literal + fixp->fx_where;
-           unsigned long val;
+           unsigned char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
+           unsigned long val, mask;
 
            if (target_big_endian)
-             val = bfd_getb16 (where);
+             val = bfd_getb32 (where - 2);
            else
-             val = bfd_getl16 (where);
-           val |= (value & 0xfffc);
+             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;
-#endif
+
+       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_DTPMOD:
+       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:
+       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_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_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_PPC64_TPREL16_DS:
+       case BFD_RELOC_PPC64_TPREL16_LO_DS:
+       case BFD_RELOC_PPC64_TPREL16_HIGHER:
+       case BFD_RELOC_PPC64_TPREL16_HIGHERA:
+       case BFD_RELOC_PPC64_TPREL16_HIGHEST:
+       case BFD_RELOC_PPC64_TPREL16_HIGHESTA:
+       case BFD_RELOC_PPC64_DTPREL16_DS:
+       case BFD_RELOC_PPC64_DTPREL16_LO_DS:
+       case BFD_RELOC_PPC64_DTPREL16_HIGHER:
+       case BFD_RELOC_PPC64_DTPREL16_HIGHERA:
+       case BFD_RELOC_PPC64_DTPREL16_HIGHEST:
+       case BFD_RELOC_PPC64_DTPREL16_HIGHESTA:
+         break;
 #endif
          /* Because SDA21 modifies the register field, the size is set to 4
             bytes, rather than 2, so offset it here appropriately.  */
        case BFD_RELOC_PPC_EMB_SDA21:
-         if (fixp->fx_pcrel)
+         if (fixP->fx_pcrel)
            abort ();
 
-         md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where
+         md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where
                              + ((target_big_endian) ? 2 : 0),
                              value, 2);
          break;
 
        case BFD_RELOC_8:
-         if (fixp->fx_pcrel)
+         if (fixP->fx_pcrel)
            abort ();
 
-         md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
+         md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
                              value, 1);
          break;
 
        case BFD_RELOC_24_PLT_PCREL:
        case BFD_RELOC_PPC_LOCAL24PC:
-         if (!fixp->fx_pcrel && !fixp->fx_done)
+         if (!fixP->fx_pcrel && !fixP->fx_done)
            abort ();
 
-         if (fixp->fx_done)
+         if (fixP->fx_done)
            {
              char *where;
              unsigned long insn;
 
              /* Fetch the instruction, insert the fully resolved operand
                 value, and stuff the instruction back again.  */
-             where = fixp->fx_frag->fr_literal + fixp->fx_where;
+             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 ((value & 3) != 0)
-               as_bad_where (fixp->fx_file, fixp->fx_line,
+               as_bad_where (fixP->fx_file, fixP->fx_line,
                              _("must branch to an address a multiple of 4"));
              if ((offsetT) value < -0x40000000
                  || (offsetT) value >= 0x40000000)
-               as_bad_where (fixp->fx_file, fixp->fx_line,
+               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);
@@ -5436,53 +5861,49 @@ md_apply_fix3 (fixp, valuep, seg)
          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);
+         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;
 
        case BFD_RELOC_VTABLE_ENTRY:
-         fixp->fx_done = 0;
+         fixP->fx_done = 0;
          break;
 
 #ifdef OBJ_ELF
-#if BFD_DEFAULT_TARGET_SIZE == 64
          /* Generated by reference to `sym@tocbase'.  The sym is
             ignored by the linker.  */
        case BFD_RELOC_PPC64_TOC:
-         fixp->fx_done = 0;
+         fixP->fx_done = 0;
          break;
-#endif
 #endif
        default:
          fprintf (stderr,
-                  _("Gas failure, reloc value %d\n"), fixp->fx_r_type);
+                  _("Gas failure, reloc value %d\n"), fixP->fx_r_type);
          fflush (stderr);
          abort ();
        }
     }
 
 #ifdef OBJ_ELF
-  fixp->fx_addnumber = value;
+  fixP->fx_addnumber = value;
 #else
-  if (fixp->fx_r_type != BFD_RELOC_PPC_TOC16)
-    fixp->fx_addnumber = 0;
+  if (fixP->fx_r_type != BFD_RELOC_PPC_TOC16)
+    fixP->fx_addnumber = 0;
   else
     {
 #ifdef TE_PE
-      fixp->fx_addnumber = 0;
+      fixP->fx_addnumber = 0;
 #else
       /* We want to use the offset within the data segment of the
         symbol, not the actual VMA of the symbol.  */
-      fixp->fx_addnumber =
-       - bfd_get_section_vma (stdoutput, S_GET_SEGMENT (fixp->fx_addsy));
+      fixP->fx_addnumber =
+       - bfd_get_section_vma (stdoutput, S_GET_SEGMENT (fixP->fx_addsy));
 #endif
     }
 #endif
-
-  return 1;
 }
 
 /* Generate a reloc for a fixup.  */
@@ -5511,3 +5932,49 @@ tc_gen_reloc (seg, fixp)
 
   return reloc;
 }
+
+void
+ppc_cfi_frame_initial_instructions ()
+{
+  cfi_add_CFA_def_cfa (1, 0);
+}
+
+int
+tc_ppc_regname_to_dw2regnum (const char *regname)
+{
+  unsigned int regnum = -1;
+  unsigned int i;
+  const char *p;
+  char *q;
+  static struct { char *name; int dw2regnum; } regnames[] =
+    {
+      { "sp", 1 }, { "r.sp", 1 }, { "rtoc", 2 }, { "r.toc", 2 },
+      { "mq", 64 }, { "lr", 65 }, { "ctr", 66 }, { "ap", 67 },
+      { "cc", 68 }, { "xer", 76 }, { "vrsave", 109 }, { "vscr", 110 },
+      { "spe_acc", 111 }, { "spefscr", 112 }
+    };
+
+  for (i = 0; i < ARRAY_SIZE (regnames); ++i)
+    if (strcmp (regnames[i].name, regname) == 0)
+      return regnames[i].dw2regnum;
+
+  if (regname[0] == 'r' || regname[0] == 'f' || regname[0] == 'v')
+    {
+      p = regname + 1 + (regname[1] == '.');
+      regnum = strtoul (p, &q, 10);
+      if (p == q || *q || regnum >= 32)
+       return -1;
+      if (regname[0] == 'f')
+        regnum += 32;
+      else if (regname[0] == 'v')
+        regnum += 77;
+    }
+  else if (regname[0] == 'c' && regname[1] == 'r')
+    {
+      p = regname + 2 + (regname[2] == '.');
+      if (p[0] < '0' || p[0] > '7' || p[1])
+        return -1;
+      regnum = p[0] - '0' + 68;
+    }
+  return regnum;
+}
This page took 0.057639 seconds and 4 git commands to generate.