Add CRX insns: pushx, popx
[deliverable/binutils-gdb.git] / gas / config / tc-ppc.c
index aca3d22a3bdfdacf26f916e7b7794af07802450f..7bc70113ff940913f09eaf995d3ee7e84d4bc250 100644 (file)
@@ -1,5 +1,6 @@
 /* tc-ppc.c -- Assemble for the PowerPC or POWER (RS/6000)
-   Copyright (C) 1994, 95, 96, 97, 98, 1999 Free Software Foundation, Inc.
+   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+   2004 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of GAS, the GNU Assembler.
    You should have received a copy of the GNU General Public License
    along with GAS; see the file COPYING.  If not, write to the Free
    Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA. */
+   02111-1307, USA.  */
 
 #include <stdio.h>
-#include <ctype.h>
 #include "as.h"
+#include "safe-ctype.h"
 #include "subsegs.h"
-
+#include "dw2gencfi.h"
 #include "opcode/ppc.h"
 
 #ifdef OBJ_ELF
 #include "elf/ppc.h"
+#include "dwarf2dbg.h"
 #endif
 
 #ifdef TE_PE
@@ -45,23 +47,57 @@ 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
 
-static boolean reg_names_p = TARGET_REG_NAMES_P;
+/* Macros for calculating LO, HI, HA, HIGHER, HIGHERA, HIGHEST,
+   HIGHESTA.  */
+
+/* #lo(value) denotes the least significant 16 bits of the indicated.  */
+#define PPC_LO(v) ((v) & 0xffff)
+
+/* #hi(value) denotes bits 16 through 31 of the indicated value.  */
+#define PPC_HI(v) (((v) >> 16) & 0xffff)
+
+/* #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) PPC_HI ((v) + 0x8000)
+
+/* #higher(value) denotes bits 32 through 47 of the indicated value.  */
+#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) PPC_HIGHER ((v) + 0x8000)
+
+/* #highest(value) denotes bits 48 through 63 of the indicated value.  */
+#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.  */
+#define PPC_HIGHESTA(v) PPC_HIGHEST ((v) + 0x8000)
+
+#define SEX16(val) ((((val) & 0xffff) ^ 0x8000) - 0x8000)
 
-static boolean register_name PARAMS ((expressionS *));
+static bfd_boolean reg_names_p = TARGET_REG_NAMES_P;
+
+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,
           offsetT val, char *file, unsigned int line));
 static void ppc_macro PARAMS ((char *str, const struct powerpc_macro *macro));
 static void ppc_byte PARAMS ((int));
+
+#if defined (OBJ_XCOFF) || defined (OBJ_ELF)
 static int ppc_is_toc_sym PARAMS ((symbolS *sym));
 static void ppc_tc PARAMS ((int));
+static void ppc_machine PARAMS ((int));
+#endif
 
 #ifdef OBJ_XCOFF
 static void ppc_comm PARAMS ((int));
@@ -75,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));
@@ -94,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
@@ -145,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.  */
 
@@ -181,12 +225,15 @@ const pseudo_typeS md_pseudo_table[] =
   { "text",    ppc_section,    't' },
   { "toc",     ppc_toc,        0 },
   { "long",    ppc_xcoff_cons, 2 },
+  { "llong",   ppc_xcoff_cons, 3 },
   { "word",    ppc_xcoff_cons, 1 },
   { "short",   ppc_xcoff_cons, 1 },
   { "vbyte",    ppc_vbyte,     0 },
 #endif
 
 #ifdef OBJ_ELF
+  { "llong",   ppc_elf_cons,   8 },
+  { "quad",    ppc_elf_cons,   8 },
   { "long",    ppc_elf_cons,   4 },
   { "word",    ppc_elf_cons,   2 },
   { "short",   ppc_elf_cons,   2 },
@@ -196,7 +243,7 @@ const pseudo_typeS md_pseudo_table[] =
 #endif
 
 #ifdef TE_PE
-  /* Pseudo-ops specific to the Windows NT PowerPC PE (coff) format */
+  /* Pseudo-ops specific to the Windows NT PowerPC PE (coff) format */
   { "previous", ppc_previous,   0 },
   { "pdata",    ppc_pdata,      0 },
   { "ydata",    ppc_ydata,      0 },
@@ -211,16 +258,18 @@ const pseudo_typeS md_pseudo_table[] =
   { "tocd",     ppc_pe_tocd,    0 },
 #endif
 
-  /* This pseudo-op is used even when not generating XCOFF output.  */
+#if defined (OBJ_XCOFF) || defined (OBJ_ELF)
   { "tc",      ppc_tc,         0 },
+  { "machine",  ppc_machine,    0 },
+#endif
 
   { NULL,      NULL,           0 }
 };
 
 \f
-/* Predefined register names if -mregnames (or default for Windows NT).  */
-/* In general, there are lots of them, in an attempt to be compatible */
-/* with a number of other Windows NT assemblers.                      */
+/* Predefined register names if -mregnames (or default for Windows NT).
+   In general, there are lots of them, in an attempt to be compatible
+   with a number of other Windows NT assemblers.  */
 
 /* Structure to hold information about predefined registers.  */
 struct pd_reg
@@ -235,11 +284,14 @@ struct pd_reg
    1. r<reg_num> which has the value <reg_num>.
    2. r.<reg_num> which has the value <reg_num>.
 
-
    Each floating point register has predefined names of the form:
    1. f<reg_num> which has the value <reg_num>.
    2. f.<reg_num> which has the value <reg_num>.
 
+   Each vector unit register has predefined names of the form:
+   1. v<reg_num> which has the value <reg_num>.
+   2. v.<reg_num> which has the value <reg_num>.
+
    Each condition register has predefined names of the form:
    1. cr<reg_num> which has the value <reg_num>.
    2. cr.<reg_num> which has the value <reg_num>.
@@ -259,7 +311,7 @@ struct pd_reg
    srr0           has the value 26
    srr1           has the value 27
 
-   The table is sorted. Suitable for searching by a binary search. */
+   The table is sorted. Suitable for searching by a binary search.  */
 
 static const struct pd_reg pre_defined_registers[] =
 {
@@ -288,70 +340,70 @@ static const struct pd_reg pre_defined_registers[] =
   { "dsisr", 18 },  /* Data Storage Interrupt Status Register */
 
   { "f.0", 0 },     /* Floating point registers */
-  { "f.1", 1 }, 
-  { "f.10", 10 }, 
-  { "f.11", 11 }, 
-  { "f.12", 12 }, 
-  { "f.13", 13 }, 
-  { "f.14", 14 }, 
-  { "f.15", 15 }, 
-  { "f.16", 16 }, 
-  { "f.17", 17 }, 
-  { "f.18", 18 }, 
-  { "f.19", 19 }, 
-  { "f.2", 2 }, 
-  { "f.20", 20 }, 
-  { "f.21", 21 }, 
-  { "f.22", 22 }, 
-  { "f.23", 23 }, 
-  { "f.24", 24 }, 
-  { "f.25", 25 }, 
-  { "f.26", 26 }, 
-  { "f.27", 27 }, 
-  { "f.28", 28 }, 
-  { "f.29", 29 }, 
-  { "f.3", 3 }, 
+  { "f.1", 1 },
+  { "f.10", 10 },
+  { "f.11", 11 },
+  { "f.12", 12 },
+  { "f.13", 13 },
+  { "f.14", 14 },
+  { "f.15", 15 },
+  { "f.16", 16 },
+  { "f.17", 17 },
+  { "f.18", 18 },
+  { "f.19", 19 },
+  { "f.2", 2 },
+  { "f.20", 20 },
+  { "f.21", 21 },
+  { "f.22", 22 },
+  { "f.23", 23 },
+  { "f.24", 24 },
+  { "f.25", 25 },
+  { "f.26", 26 },
+  { "f.27", 27 },
+  { "f.28", 28 },
+  { "f.29", 29 },
+  { "f.3", 3 },
   { "f.30", 30 },
   { "f.31", 31 },
-  { "f.4", 4 }, 
-  { "f.5", 5 }, 
-  { "f.6", 6 }, 
-  { "f.7", 7 }, 
-  { "f.8", 8 }, 
-  { "f.9", 9 }, 
-
-  { "f0", 0 }, 
-  { "f1", 1 }, 
-  { "f10", 10 }, 
-  { "f11", 11 }, 
-  { "f12", 12 }, 
-  { "f13", 13 }, 
-  { "f14", 14 }, 
-  { "f15", 15 }, 
-  { "f16", 16 }, 
-  { "f17", 17 }, 
-  { "f18", 18 }, 
-  { "f19", 19 }, 
-  { "f2", 2 }, 
-  { "f20", 20 }, 
-  { "f21", 21 }, 
-  { "f22", 22 }, 
-  { "f23", 23 }, 
-  { "f24", 24 }, 
-  { "f25", 25 }, 
-  { "f26", 26 }, 
-  { "f27", 27 }, 
-  { "f28", 28 }, 
-  { "f29", 29 }, 
-  { "f3", 3 }, 
+  { "f.4", 4 },
+  { "f.5", 5 },
+  { "f.6", 6 },
+  { "f.7", 7 },
+  { "f.8", 8 },
+  { "f.9", 9 },
+
+  { "f0", 0 },
+  { "f1", 1 },
+  { "f10", 10 },
+  { "f11", 11 },
+  { "f12", 12 },
+  { "f13", 13 },
+  { "f14", 14 },
+  { "f15", 15 },
+  { "f16", 16 },
+  { "f17", 17 },
+  { "f18", 18 },
+  { "f19", 19 },
+  { "f2", 2 },
+  { "f20", 20 },
+  { "f21", 21 },
+  { "f22", 22 },
+  { "f23", 23 },
+  { "f24", 24 },
+  { "f25", 25 },
+  { "f26", 26 },
+  { "f27", 27 },
+  { "f28", 28 },
+  { "f29", 29 },
+  { "f3", 3 },
   { "f30", 30 },
   { "f31", 31 },
-  { "f4", 4 }, 
-  { "f5", 5 }, 
-  { "f6", 6 }, 
-  { "f7", 7 }, 
-  { "f8", 8 }, 
-  { "f9", 9 }, 
+  { "f4", 4 },
+  { "f5", 5 },
+  { "f6", 6 },
+  { "f7", 7 },
+  { "f8", 8 },
+  { "f9", 9 },
 
   { "fpscr", 0 },
 
@@ -438,11 +490,77 @@ static const struct pd_reg pre_defined_registers[] =
   { "srr0", 26 }, /* Machine Status Save/Restore Register 0 */
   { "srr1", 27 }, /* Machine Status Save/Restore Register 1 */
 
+  { "v.0", 0 },     /* Vector registers */
+  { "v.1", 1 },
+  { "v.10", 10 },
+  { "v.11", 11 },
+  { "v.12", 12 },
+  { "v.13", 13 },
+  { "v.14", 14 },
+  { "v.15", 15 },
+  { "v.16", 16 },
+  { "v.17", 17 },
+  { "v.18", 18 },
+  { "v.19", 19 },
+  { "v.2", 2 },
+  { "v.20", 20 },
+  { "v.21", 21 },
+  { "v.22", 22 },
+  { "v.23", 23 },
+  { "v.24", 24 },
+  { "v.25", 25 },
+  { "v.26", 26 },
+  { "v.27", 27 },
+  { "v.28", 28 },
+  { "v.29", 29 },
+  { "v.3", 3 },
+  { "v.30", 30 },
+  { "v.31", 31 },
+  { "v.4", 4 },
+  { "v.5", 5 },
+  { "v.6", 6 },
+  { "v.7", 7 },
+  { "v.8", 8 },
+  { "v.9", 9 },
+
+  { "v0", 0 },
+  { "v1", 1 },
+  { "v10", 10 },
+  { "v11", 11 },
+  { "v12", 12 },
+  { "v13", 13 },
+  { "v14", 14 },
+  { "v15", 15 },
+  { "v16", 16 },
+  { "v17", 17 },
+  { "v18", 18 },
+  { "v19", 19 },
+  { "v2", 2 },
+  { "v20", 20 },
+  { "v21", 21 },
+  { "v22", 22 },
+  { "v23", 23 },
+  { "v24", 24 },
+  { "v25", 25 },
+  { "v26", 26 },
+  { "v27", 27 },
+  { "v28", 28 },
+  { "v29", 29 },
+  { "v3", 3 },
+  { "v30", 30 },
+  { "v31", 31 },
+  { "v4", 4 },
+  { "v5", 5 },
+  { "v6", 6 },
+  { "v7", 7 },
+  { "v8", 8 },
+  { "v9", 9 },
+
   { "xer", 1 },
 
 };
 
-#define REG_NAME_CNT   (sizeof(pre_defined_registers) / sizeof(struct pd_reg))
+#define REG_NAME_CNT   (sizeof (pre_defined_registers) / sizeof (struct pd_reg))
 
 /* Given NAME, find the register number associated with that name, return
    the integer value associated with the given name or -1 on failure.  */
@@ -479,7 +597,7 @@ reg_name_search (regs, regcount, name)
 }
 
 /*
- * Summary of register_name().
+ * Summary of register_name.
  *
  * in: Input_line_pointer points to 1st char of operand.
  *
@@ -490,7 +608,7 @@ reg_name_search (regs, regcount, name)
  *      original state.
  */
 
-static boolean
+static bfd_boolean
 register_name (expressionP)
      expressionS *expressionP;
 {
@@ -499,36 +617,35 @@ register_name (expressionP)
   char *start;
   char c;
 
-  /* Find the spelling of the operand */
+  /* Find the spelling of the operand */
   start = name = input_line_pointer;
-  if (name[0] == '%' && isalpha (name[1]))
+  if (name[0] == '%' && ISALPHA (name[1]))
     name = ++input_line_pointer;
 
-  else if (!reg_names_p || !isalpha (name[0]))
-    return false;
+  else if (!reg_names_p || !ISALPHA (name[0]))
+    return FALSE;
 
   c = get_symbol_end ();
   reg_number = reg_name_search (pre_defined_registers, REG_NAME_CNT, name);
 
-  /* look to see if it's in the register table */
-  if (reg_number >= 0) 
+  /* Put back the delimiting char.  */
+  *input_line_pointer = c;
+
+  /* Look to see if it's in the register table.  */
+  if (reg_number >= 0)
     {
       expressionP->X_op = O_register;
       expressionP->X_add_number = reg_number;
-      
-      /* make the rest nice */
+
+      /* Make the rest nice.  */
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol = NULL;
-      *input_line_pointer = c;   /* put back the delimiting char */
-      return true;
-    }
-  else
-    {
-      /* reset the line as if we had not done anything */
-      *input_line_pointer = c;   /* put back the delimiting char */
-      input_line_pointer = start; /* reset input_line pointer */
-      return false;
+      return TRUE;
     }
+
+  /* Reset the line as if we had not done anything.  */
+  input_line_pointer = start;
+  return FALSE;
 }
 \f
 /* This function is called for each symbol seen in an expression.  It
@@ -536,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[] =
@@ -584,11 +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;
+static unsigned long ppc_cpu = 0;
 
-/* The size of the processor we are assembling for.  This is either
-   PPC_OPCODE_32 or PPC_OPCODE_64.  */
-static int ppc_size = PPC_OPCODE_32;
+/* Whether to target xcoff64/elf64.  */
+static unsigned int ppc_obj64 = BFD_DEFAULT_TARGET_SIZE == 64;
 
 /* Opcode hash table.  */
 static struct hash_control *ppc_hash;
@@ -597,20 +713,20 @@ static struct hash_control *ppc_hash;
 static struct hash_control *ppc_macro_hash;
 
 #ifdef OBJ_ELF
-/* What type of shared library support to use */
-static enum { SHLIB_NONE, SHLIB_PIC, SHILB_MRELOCATABLE } shlib = SHLIB_NONE;
+/* What type of shared library support to use */
+static enum { SHLIB_NONE, SHLIB_PIC, SHLIB_MRELOCATABLE } shlib = SHLIB_NONE;
 
-/* Flags to set in the elf header */
+/* Flags to set in the elf header */
 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
@@ -669,7 +785,7 @@ static segT reldata_section;
 static segT rdata_section;
 static segT tocdata_section;
 
-/* The current section and the previous section. See ppc_previous. */
+/* The current section and the previous section. See ppc_previous.  */
 static segT ppc_previous_section;
 static segT ppc_current_section;
 
@@ -677,17 +793,132 @@ 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);
+
+
+/* Handle -m options that set cpu type, and .machine arg.  */
+
+static int
+parse_cpu (const char *arg)
+{
+  /* -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;
+  /* -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_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;
+    }
+  /* -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_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;
+
+  return 1;
+}
 
 int
 md_parse_option (c, arg)
@@ -704,7 +935,7 @@ md_parse_option (c, arg)
 #ifdef OBJ_ELF
     case 'l':
       /* Solaris as takes -le (presumably for little endian).  For completeness
-         sake, recognize -be also.  */
+        sake, recognize -be also.  */
       if (strcmp (arg, "e") == 0)
        {
          target_big_endian = 0;
@@ -727,7 +958,7 @@ md_parse_option (c, arg)
       break;
 
     case 'K':
-      /* Recognize -K PIC */
+      /* Recognize -K PIC */
       if (strcmp (arg, "PIC") == 0 || strcmp (arg, "pic") == 0)
        {
          shlib = SHLIB_PIC;
@@ -739,73 +970,54 @@ md_parse_option (c, arg)
       break;
 #endif
 
-    case 'm':
-      /* -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;
-      /* -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
-         instructions that are holdovers from the Power. */
-      else if (strcmp (arg, "601") == 0)
-       ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_601;
-      /* -mppc, -mppc32, -m603, and -m604 mean to assemble for the
-         Motorola PowerPC 603/604.  */
-      else if (strcmp (arg, "ppc") == 0
-              || strcmp (arg, "ppc32") == 0
-              || strcmp (arg, "403") == 0
-              || strcmp (arg, "603") == 0
-              || strcmp (arg, "604") == 0)
-       ppc_cpu = PPC_OPCODE_PPC;
-      /* -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;
-       }
-      else if (strcmp (arg, "ppc64bridge") == 0)
+      /* a64 and a32 determine whether to use XCOFF64 or XCOFF32.  */
+    case 'a':
+      if (strcmp (arg, "64") == 0)
        {
-         ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_64_BRIDGE;
-         ppc_size = PPC_OPCODE_64;
+#ifdef BFD64
+         ppc_obj64 = 1;
+#else
+         as_fatal (_("%s unsupported"), "-a64");
+#endif
        }
-      /* -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;
-      /* -many means to assemble for any architecture (PWR/PWRX/PPC).  */
-      else if (strcmp (arg, "any") == 0)
-       ppc_cpu = PPC_OPCODE_ANY;
+      else if (strcmp (arg, "32") == 0)
+       ppc_obj64 = 0;
+      else
+       return 0;
+      break;
+
+    case 'm':
+      if (parse_cpu (arg))
+       ;
 
       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 that require relocation */
+      /* -mrelocatable/-mrelocatable-lib -- warn about initializations
+        that require relocation.  */
       else if (strcmp (arg, "relocatable") == 0)
        {
-         shlib = SHILB_MRELOCATABLE;
+         shlib = SHLIB_MRELOCATABLE;
          ppc_flags |= EF_PPC_RELOCATABLE;
        }
 
       else if (strcmp (arg, "relocatable-lib") == 0)
        {
-         shlib = SHILB_MRELOCATABLE;
+         shlib = SHLIB_MRELOCATABLE;
          ppc_flags |= EF_PPC_RELOCATABLE_LIB;
        }
 
-      /* -memb, set embedded bit */
+      /* -memb, set embedded bit */
       else if (strcmp (arg, "emb") == 0)
        ppc_flags |= EF_PPC_EMB;
 
-      /* -mlittle/-mbig set the endianess */
-      else if (strcmp (arg, "little") == 0 || strcmp (arg, "little-endian") == 0)
+      /* -mlittle/-mbig set the endianess.  */
+      else if (strcmp (arg, "little") == 0
+              || strcmp (arg, "little-endian") == 0)
        {
          target_big_endian = 0;
          set_target_endian = 1;
@@ -819,13 +1031,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
@@ -868,28 +1080,43 @@ void
 md_show_usage (stream)
      FILE *stream;
 {
-  fprintf(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, -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
-  fprintf(stream, _("\
+  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\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\
@@ -905,20 +1132,27 @@ 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;
-      else if (strcmp (default_cpu, "powerpc") == 0
-              || strcmp (default_cpu, "powerpcle") == 0)
-       ppc_cpu = PPC_OPCODE_PPC;
+       ppc_cpu |= PPC_OPCODE_POWER | PPC_OPCODE_32;
+      else if (strncmp (default_cpu, "powerpc", 7) == 0)
+       {
+         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);
+       as_fatal (_("Unknown default cpu = %s, os = %s"),
+                 default_cpu, default_os);
     }
 }
 
@@ -938,8 +1172,7 @@ ppc_arch ()
     {
       if (strcmp (default_cpu, "rs6000") == 0)
        return bfd_arch_rs6000;
-      else if (strcmp (default_cpu, "powerpc") == 0
-              || strcmp (default_cpu, "powerpcle") == 0)
+      else if (strncmp (default_cpu, "powerpc", 7) == 0)
        return bfd_arch_powerpc;
     }
 
@@ -947,26 +1180,56 @@ ppc_arch ()
   return bfd_arch_unknown;
 }
 
-/* This function is called when the assembler starts up.  It is called
-   after the options have been parsed and the output file has been
-   opened.  */
+unsigned long
+ppc_mach ()
+{
+  if (ppc_obj64)
+    return bfd_mach_ppc64;
+  else if (ppc_arch () == bfd_arch_rs6000)
+    return bfd_mach_rs6k;
+  else
+    return bfd_mach_ppc;
+}
 
-void
-md_begin ()
+extern char*
+ppc_target_format ()
+{
+#ifdef OBJ_COFF
+#ifdef TE_PE
+  return target_big_endian ? "pe-powerpc" : "pe-powerpcle";
+#elif TE_POWERMAC
+  return "xcoff-powermac";
+#else
+#  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
+         ? (ppc_obj64 ? "elf64-powerpc" : "elf32-powerpc")
+         : (ppc_obj64 ? "elf64-powerpcle" : "elf32-powerpcle"));
+#endif
+}
+
+/* Insert opcodes and macros into hash tables.  Called at startup and
+   for .cpu pseudo.  */
+
+static void
+ppc_setup_opcodes (void)
 {
   register const struct powerpc_opcode *op;
   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
-  /* Set the ELF flags if desired. */
-  if (ppc_flags && !msolaris)
-    bfd_set_private_flags (stdoutput, ppc_flags);
-#endif
+  if (ppc_hash != NULL)
+    hash_die (ppc_hash);
+  if (ppc_macro_hash != NULL)
+    hash_die (ppc_macro_hash);
 
   /* Insert the opcodes into a hash table.  */
   ppc_hash = hash_new ();
@@ -976,27 +1239,44 @@ 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;
 
          retval = hash_insert (ppc_hash, op->name, (PTR) op);
-         if (retval != (const char *) NULL)
+         if (retval != NULL)
            {
-             /* Ignore Power duplicates for -m601 */
+             /* Ignore Power duplicates for -m601 */
              if ((ppc_cpu & PPC_OPCODE_601) != 0
                  && (op->flags & PPC_OPCODE_POWER) != 0)
                continue;
 
-             as_bad (_("Internal assembler error for instruction %s"), op->name);
-             dup_insn = true;
+             as_bad (_("Internal assembler error for instruction %s"),
+                     op->name);
+             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 ();
 
@@ -1011,15 +1291,36 @@ md_begin ()
          if (retval != (const char *) NULL)
            {
              as_bad (_("Internal assembler error for macro %s"), macro->name);
-             dup_insn = true;
+             dup_insn = TRUE;
            }
        }
     }
 
   if (dup_insn)
     abort ();
+}
 
-  /* Tell the main code what the endianness is if it is not overidden by the user.  */
+/* This function is called when the assembler starts up.  It is called
+   after the options have been parsed and the output file has been
+   opened.  */
+
+void
+md_begin ()
+{
+  ppc_set_cpu ();
+
+  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);
+#endif
+
+  ppc_setup_opcodes ();
+
+  /* Tell the main code what the endianness is if it is not overridden
+     by the user.  */
   if (!set_target_endian)
     {
       set_target_endian = 1;
@@ -1041,11 +1342,71 @@ md_begin ()
 #ifdef TE_PE
 
   ppc_current_section = text_section;
-  ppc_previous_section = 0;  
+  ppc_previous_section = 0;
 
 #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
@@ -1069,15 +1430,15 @@ 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
                 valid, but, to permit this code to assemble on a 64
                 bit host, we sign extend the 32 bit value.  */
              if (val > 0
-                 && (val & 0x80000000) != 0
-                 && (val & 0xffffffff) == val)
+                 && (val & (offsetT) 0x80000000) != 0
+                 && (val & (offsetT) 0xffffffff) == val)
                {
                  val -= 0x80000000;
                  val -= 0x80000000;
@@ -1096,17 +1457,7 @@ ppc_insert_operand (insn, operand, val, file, line)
        test = val;
 
       if (test < (offsetT) min || test > (offsetT) max)
-       {
-         const char *err =
-           _("operand out of range (%s not between %ld and %ld)");
-         char buf[100];
-
-         sprint_value (buf, test);
-         if (file == (char *) NULL)
-           as_bad (err, buf, min, max);
-         else
-           as_bad_where (file, line, err, buf, min, max);
-       }
+       as_bad_value_out_of_range (_("operand"), test, (offsetT) min, (offsetT) max, file, line);
     }
 
   if (operand->insert)
@@ -1114,9 +1465,9 @@ 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 (errmsg);
+       as_bad_where (file, line, errmsg);
     }
   else
     insn |= (((long) val & ((1 << operand->bits) - 1))
@@ -1135,8 +1486,10 @@ ppc_elf_suffix (str_p, exp_p)
 {
   struct map_bfd {
     char *string;
-    int length;
-    bfd_reloc_code_real_type reloc;
+    unsigned int length : 8;
+    unsigned int valid32 : 1;
+    unsigned int valid64 : 1;
+    unsigned int reloc;
   };
 
   char ident[20];
@@ -1144,55 +1497,99 @@ ppc_elf_suffix (str_p, exp_p)
   char *str2;
   int ch;
   int len;
-  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),
-
-    { (char *)0,       0,      BFD_RELOC_UNUSED }
+  const struct map_bfd *ptr;
+
+#define MAP(str, reloc)   { str, sizeof (str) - 1, 1, 1, reloc }
+#define MAP32(str, reloc) { str, sizeof (str) - 1, 1, 0, reloc }
+#define MAP64(str, reloc) { str, sizeof (str) - 1, 0, 1, reloc }
+
+  static const 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 ("plt@l",              BFD_RELOC_LO16_PLTOFF),
+    MAP ("plt@h",              BFD_RELOC_HI16_PLTOFF),
+    MAP ("plt@ha",             BFD_RELOC_HI16_S_PLTOFF),
+    MAP ("copy",               BFD_RELOC_PPC_COPY),
+    MAP ("globdat",            BFD_RELOC_PPC_GLOB_DAT),
+    MAP ("sectoff",            BFD_RELOC_16_BASEREL),
+    MAP ("sectoff@l",          BFD_RELOC_LO16_BASEREL),
+    MAP ("sectoff@h",          BFD_RELOC_HI16_BASEREL),
+    MAP ("sectoff@ha",         BFD_RELOC_HI16_S_BASEREL),
+    MAP ("tls",                        BFD_RELOC_PPC_TLS),
+    MAP ("dtpmod",             BFD_RELOC_PPC_DTPMOD),
+    MAP ("dtprel",             BFD_RELOC_PPC_DTPREL),
+    MAP ("dtprel@l",           BFD_RELOC_PPC_DTPREL16_LO),
+    MAP ("dtprel@h",           BFD_RELOC_PPC_DTPREL16_HI),
+    MAP ("dtprel@ha",          BFD_RELOC_PPC_DTPREL16_HA),
+    MAP ("tprel",              BFD_RELOC_PPC_TPREL),
+    MAP ("tprel@l",            BFD_RELOC_PPC_TPREL16_LO),
+    MAP ("tprel@h",            BFD_RELOC_PPC_TPREL16_HI),
+    MAP ("tprel@ha",           BFD_RELOC_PPC_TPREL16_HA),
+    MAP ("got@tlsgd",          BFD_RELOC_PPC_GOT_TLSGD16),
+    MAP ("got@tlsgd@l",                BFD_RELOC_PPC_GOT_TLSGD16_LO),
+    MAP ("got@tlsgd@h",                BFD_RELOC_PPC_GOT_TLSGD16_HI),
+    MAP ("got@tlsgd@ha",       BFD_RELOC_PPC_GOT_TLSGD16_HA),
+    MAP ("got@tlsld",          BFD_RELOC_PPC_GOT_TLSLD16),
+    MAP ("got@tlsld@l",                BFD_RELOC_PPC_GOT_TLSLD16_LO),
+    MAP ("got@tlsld@h",                BFD_RELOC_PPC_GOT_TLSLD16_HI),
+    MAP ("got@tlsld@ha",       BFD_RELOC_PPC_GOT_TLSLD16_HA),
+    MAP ("got@dtprel",         BFD_RELOC_PPC_GOT_DTPREL16),
+    MAP ("got@dtprel@l",       BFD_RELOC_PPC_GOT_DTPREL16_LO),
+    MAP ("got@dtprel@h",       BFD_RELOC_PPC_GOT_DTPREL16_HI),
+    MAP ("got@dtprel@ha",      BFD_RELOC_PPC_GOT_DTPREL16_HA),
+    MAP ("got@tprel",          BFD_RELOC_PPC_GOT_TPREL16),
+    MAP ("got@tprel@l",                BFD_RELOC_PPC_GOT_TPREL16_LO),
+    MAP ("got@tprel@h",                BFD_RELOC_PPC_GOT_TPREL16_HI),
+    MAP ("got@tprel@ha",       BFD_RELOC_PPC_GOT_TPREL16_HA),
+    MAP32 ("fixup",            BFD_RELOC_CTOR),
+    MAP32 ("plt",              BFD_RELOC_24_PLT_PCREL),
+    MAP32 ("pltrel24",         BFD_RELOC_24_PLT_PCREL),
+    MAP32 ("local24pc",                BFD_RELOC_PPC_LOCAL24PC),
+    MAP32 ("local",            BFD_RELOC_PPC_LOCAL24PC),
+    MAP32 ("pltrel",           BFD_RELOC_32_PLT_PCREL),
+    MAP32 ("sdarel",           BFD_RELOC_GPREL16),
+    MAP32 ("naddr",            BFD_RELOC_PPC_EMB_NADDR32),
+    MAP32 ("naddr16",          BFD_RELOC_PPC_EMB_NADDR16),
+    MAP32 ("naddr@l",          BFD_RELOC_PPC_EMB_NADDR16_LO),
+    MAP32 ("naddr@h",          BFD_RELOC_PPC_EMB_NADDR16_HI),
+    MAP32 ("naddr@ha",         BFD_RELOC_PPC_EMB_NADDR16_HA),
+    MAP32 ("sdai16",           BFD_RELOC_PPC_EMB_SDAI16),
+    MAP32 ("sda2rel",          BFD_RELOC_PPC_EMB_SDA2REL),
+    MAP32 ("sda2i16",          BFD_RELOC_PPC_EMB_SDA2I16),
+    MAP32 ("sda21",            BFD_RELOC_PPC_EMB_SDA21),
+    MAP32 ("mrkref",           BFD_RELOC_PPC_EMB_MRKREF),
+    MAP32 ("relsect",          BFD_RELOC_PPC_EMB_RELSEC16),
+    MAP32 ("relsect@l",                BFD_RELOC_PPC_EMB_RELST_LO),
+    MAP32 ("relsect@h",                BFD_RELOC_PPC_EMB_RELST_HI),
+    MAP32 ("relsect@ha",       BFD_RELOC_PPC_EMB_RELST_HA),
+    MAP32 ("bitfld",           BFD_RELOC_PPC_EMB_BIT_FLD),
+    MAP32 ("relsda",           BFD_RELOC_PPC_EMB_RELSDA),
+    MAP32 ("xgot",             BFD_RELOC_PPC_TOC16),
+    MAP64 ("higher",           BFD_RELOC_PPC64_HIGHER),
+    MAP64 ("highera",          BFD_RELOC_PPC64_HIGHER_S),
+    MAP64 ("highest",          BFD_RELOC_PPC64_HIGHEST),
+    MAP64 ("highesta",         BFD_RELOC_PPC64_HIGHEST_S),
+    MAP64 ("tocbase",          BFD_RELOC_PPC64_TOC),
+    MAP64 ("toc",              BFD_RELOC_PPC_TOC16),
+    MAP64 ("toc@l",            BFD_RELOC_PPC64_TOC16_LO),
+    MAP64 ("toc@h",            BFD_RELOC_PPC64_TOC16_HI),
+    MAP64 ("toc@ha",           BFD_RELOC_PPC64_TOC16_HA),
+    MAP64 ("dtprel@higher",    BFD_RELOC_PPC64_DTPREL16_HIGHER),
+    MAP64 ("dtprel@highera",   BFD_RELOC_PPC64_DTPREL16_HIGHERA),
+    MAP64 ("dtprel@highest",   BFD_RELOC_PPC64_DTPREL16_HIGHEST),
+    MAP64 ("dtprel@highesta",  BFD_RELOC_PPC64_DTPREL16_HIGHESTA),
+    MAP64 ("tprel@higher",     BFD_RELOC_PPC64_TPREL16_HIGHER),
+    MAP64 ("tprel@highera",    BFD_RELOC_PPC64_TPREL16_HIGHERA),
+    MAP64 ("tprel@highest",    BFD_RELOC_PPC64_TPREL16_HIGHEST),
+    MAP64 ("tprel@highesta",   BFD_RELOC_PPC64_TPREL16_HIGHESTA),
+    { (char *) 0, 0, 0, 0,     BFD_RELOC_UNUSED }
   };
 
   if (*str++ != '@')
@@ -1200,10 +1597,10 @@ ppc_elf_suffix (str_p, exp_p)
 
   for (ch = *str, str2 = ident;
        (str2 < ident + sizeof (ident) - 1
-       && (isalnum (ch) || ch == '@'));
+       && (ISALNUM (ch) || ch == '@'));
        ch = *++str)
     {
-      *str2++ = (islower (ch)) ? ch : tolower (ch);
+      *str2++ = TOLOWER (ch);
     }
 
   *str2 = '\0';
@@ -1213,16 +1610,20 @@ ppc_elf_suffix (str_p, exp_p)
   for (ptr = &mapping[0]; ptr->length > 0; ptr++)
     if (ch == ptr->string[0]
        && len == ptr->length
-       && memcmp (ident, ptr->string, ptr->length) == 0)
+       && memcmp (ident, ptr->string, ptr->length) == 0
+       && (ppc_obj64 ? ptr->valid64 : ptr->valid32))
       {
-       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"));
-
-       /* Now check for identifier@suffix+constant */
+       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"));
+
+       /* Now check for identifier@suffix+constant.  */
        if (*str == '-' || *str == '+')
          {
            char *orig_line = input_line_pointer;
@@ -1239,20 +1640,28 @@ ppc_elf_suffix (str_p, exp_p)
            if (&input_line_pointer != str_p)
              input_line_pointer = orig_line;
          }
-
        *str_p = str;
-       return ptr->reloc;
+
+       if (reloc == (int) BFD_RELOC_PPC64_TOC
+           && exp_p->X_op == O_symbol
+           && strcmp (S_GET_NAME (exp_p->X_add_symbol), ".TOC.") == 0)
+         {
+           /* Change the symbol so that the dummy .TOC. symbol can be
+              omitted from the object file.  */
+           exp_p->X_add_symbol = &abs_symbol;
+         }
+
+       return (bfd_reloc_code_real_type) reloc;
       }
 
   return BFD_RELOC_UNUSED;
 }
 
-/* Like normal .long/.short/.word, except support @got, etc. */
-/* clobbers input_line_pointer, checks */
-/* end-of-line. */
+/* Like normal .long/.short/.word, except support @got, etc.
+   Clobbers input_line_pointer, checks end-of-line.  */
 static void
 ppc_elf_cons (nbytes)
-     register int nbytes;      /* 1=.byte, 2=.word, 4=.long */
+     register int nbytes;      /* 1=.byte, 2=.word, 4=.long, 8=.llong.  */
 {
   expressionS exp;
   bfd_reloc_code_real_type reloc;
@@ -1268,20 +1677,31 @@ ppc_elf_cons (nbytes)
       expression (&exp);
       if (exp.X_op == O_symbol
          && *input_line_pointer == '@'
-         && (reloc = ppc_elf_suffix (&input_line_pointer, &exp)) != BFD_RELOC_UNUSED)
+         && (reloc = ppc_elf_suffix (&input_line_pointer,
+                                     &exp)) != BFD_RELOC_UNUSED)
        {
-         reloc_howto_type *reloc_howto = bfd_reloc_type_lookup (stdoutput, reloc);
-         int size = bfd_get_reloc_size (reloc_howto);
+         reloc_howto_type *reloc_howto;
+         int size;
 
-         if (size > nbytes)
-           as_bad (_("%s relocations do not fit in %d bytes\n"), reloc_howto->name, nbytes);
+         reloc_howto = bfd_reloc_type_lookup (stdoutput, reloc);
+         size = bfd_get_reloc_size (reloc_howto);
 
+         if (size > nbytes)
+           {
+             as_bad (_("%s relocations do not fit in %d bytes\n"),
+                     reloc_howto->name, nbytes);
+           }
          else
            {
-             register char *p = frag_more ((int) nbytes);
-             int offset = nbytes - size;
-
-             fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size, &exp, 0, reloc);
+             char *p;
+             int offset;
+
+             p = frag_more (nbytes);
+             offset = 0;
+             if (target_big_endian)
+               offset = nbytes - size;
+             fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size,
+                          &exp, 0, reloc);
            }
        }
       else
@@ -1289,7 +1709,8 @@ ppc_elf_cons (nbytes)
     }
   while (*input_line_pointer++ == ',');
 
-  input_line_pointer--;                /* Put terminator back into stream. */
+  /* Put terminator back into stream.  */
+  input_line_pointer--;
   demand_empty_rest_of_line ();
 }
 
@@ -1301,17 +1722,17 @@ ppc_elf_rdata (xxx)
   char *save_line = input_line_pointer;
   static char section[] = ".rodata\n";
 
-  /* Just pretend this is .section .rodata */
+  /* Just pretend this is .section .rodata  */
   input_line_pointer = section;
   obj_elf_section (xxx);
 
   input_line_pointer = save_line;
 }
 
-/* Pseudo op to make file scope bss items */
+/* Pseudo op to make file scope bss items */
 static void
-ppc_elf_lcomm(xxx)
-     int xxx;
+ppc_elf_lcomm (xxx)
+     int xxx ATTRIBUTE_UNUSED;
 {
   register char *name;
   register char c;
@@ -1327,7 +1748,7 @@ ppc_elf_lcomm(xxx)
   name = input_line_pointer;
   c = get_symbol_end ();
 
-  /* just after name is now '\0' */
+  /* just after name is now '\0' */
   p = input_line_pointer;
   *p = c;
   SKIP_WHITESPACE ();
@@ -1383,12 +1804,12 @@ ppc_elf_lcomm(xxx)
       return;
     }
 
-  /* allocate_bss: */
+  /* Allocate_bss.  */
   old_sec = now_seg;
   old_subsec = now_subseg;
   if (align)
     {
-      /* convert to a power of 2 alignment */
+      /* Convert to a power of 2 alignment.  */
       for (align2 = 0; (align & 1) == 0; align >>= 1, ++align2);
       if (align != 1)
        {
@@ -1433,21 +1854,21 @@ ppc_elf_validate_fix (fixp, seg)
     case SHLIB_PIC:
       return;
 
-    case SHILB_MRELOCATABLE:
+    case SHLIB_MRELOCATABLE:
       if (fixp->fx_r_type <= BFD_RELOC_UNUSED
          && fixp->fx_r_type != BFD_RELOC_16_GOTOFF
          && fixp->fx_r_type != BFD_RELOC_HI16_GOTOFF
          && fixp->fx_r_type != BFD_RELOC_LO16_GOTOFF
          && fixp->fx_r_type != BFD_RELOC_HI16_S_GOTOFF
-         && 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
+         && (seg->flags & SEC_LOAD) != 0
          && strcmp (segment_name (seg), ".got2") != 0
          && strcmp (segment_name (seg), ".dtors") != 0
          && strcmp (segment_name (seg), ".ctors") != 0
          && strcmp (segment_name (seg), ".fixup") != 0
-         && strcmp (segment_name (seg), ".stab") != 0
          && strcmp (segment_name (seg), ".gcc_except_table") != 0
          && strcmp (segment_name (seg), ".eh_frame") != 0
          && strcmp (segment_name (seg), ".ex_shared") != 0)
@@ -1462,12 +1883,56 @@ ppc_elf_validate_fix (fixp, seg)
       return;
     }
 }
+
+/* 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 ()
+{
+  symbolS *symp;
+
+  if (!ppc_obj64)
+    return;
+
+  for (symp = symbol_rootP; symp; symp = symbol_next (symp))
+    {
+      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);
+
+    }
+
+  /* Don't emit .TOC. symbol.  */
+  symp = symbol_find (".TOC.");
+  if (symp != NULL)
+    symbol_remove (symp, &symbol_rootP, &symbol_lastP);
+}
 #endif /* OBJ_ELF */
 \f
 #ifdef TE_PE
 
 /*
- * Summary of parse_toc_entry().
+ * Summary of parse_toc_entry.
  *
  * in: Input_line_pointer points to the '[' in one of:
  *
@@ -1475,7 +1940,7 @@ ppc_elf_validate_fix (fixp, seg)
  *
  *      Anything else is an error of one kind or another.
  *
- * out:        
+ * out:
  *   return value: success or failure
  *   toc_kind:     kind of toc reference
  *   input_line_pointer:
@@ -1491,8 +1956,8 @@ ppc_elf_validate_fix (fixp, seg)
  *
  */
 
-enum toc_size_qualifier 
-{ 
+enum toc_size_qualifier
+{
   default_toc, /* The toc cell constructed should be the system default size */
   data_in_toc, /* This is a direct reference to a toc cell                   */
   must_be_32,  /* The toc cell constructed must be 32 bits wide              */
@@ -1500,7 +1965,7 @@ enum toc_size_qualifier
 };
 
 static int
-parse_toc_entry(toc_kind)
+parse_toc_entry (toc_kind)
      enum toc_size_qualifier *toc_kind;
 {
   char *start;
@@ -1508,60 +1973,94 @@ parse_toc_entry(toc_kind)
   char c;
   enum toc_size_qualifier t;
 
-  /* save the input_line_pointer */
+  /* Save the input_line_pointer.  */
   start = input_line_pointer;
 
-  /* skip over the '[' , and whitespace */
+  /* Skip over the '[' , and whitespace.  */
   ++input_line_pointer;
   SKIP_WHITESPACE ();
-  
-  /* find the spelling of the operand */
+
+  /* Find the spelling of the operand.  */
   toc_spec = input_line_pointer;
   c = get_symbol_end ();
 
-  if (strcmp(toc_spec, "toc") == 0) 
+  if (strcmp (toc_spec, "toc") == 0)
     {
       t = default_toc;
     }
-  else if (strcmp(toc_spec, "tocv") == 0) 
+  else if (strcmp (toc_spec, "tocv") == 0)
     {
       t = data_in_toc;
     }
-  else if (strcmp(toc_spec, "toc32") == 0) 
+  else if (strcmp (toc_spec, "toc32") == 0)
     {
       t = must_be_32;
     }
-  else if (strcmp(toc_spec, "toc64") == 0) 
+  else if (strcmp (toc_spec, "toc64") == 0)
     {
       t = must_be_64;
     }
   else
     {
       as_bad (_("syntax error: invalid toc specifier `%s'"), toc_spec);
-      *input_line_pointer = c;   /* put back the delimiting char */
-      input_line_pointer = start; /* reset input_line pointer */
+      *input_line_pointer = c;
+      input_line_pointer = start;
       return 0;
     }
 
-  /* now find the ']' */
-  *input_line_pointer = c;   /* put back the delimiting char */
+  /* Now find the ']'.  */
+  *input_line_pointer = c;
 
-  SKIP_WHITESPACE ();       /* leading whitespace could be there. */
-  c = *input_line_pointer++; /* input_line_pointer->past char in c. */
+  SKIP_WHITESPACE ();       /* leading whitespace could be there.  */
+  c = *input_line_pointer++; /* input_line_pointer->past char in c.  */
 
   if (c != ']')
     {
       as_bad (_("syntax error: expected `]', found  `%c'"), c);
-      input_line_pointer = start; /* reset input_line pointer */
+      input_line_pointer = start;
       return 0;
     }
 
-  *toc_kind = t;             /* set return value */
+  *toc_kind = t;
   return 1;
 }
 #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 ``.''.  */
@@ -1591,13 +2090,14 @@ md_assemble (str)
   struct ppc_fixup fixups[MAX_INSN_FIXUPS];
   int fc;
   char *f;
+  int addr_mod;
   int i;
 #ifdef OBJ_ELF
   bfd_reloc_code_real_type reloc;
 #endif
 
   /* Get the opcode.  */
-  for (s = str; *s != '\0' && ! isspace (*s); s++)
+  for (s = str; *s != '\0' && ! ISSPACE (*s); s++)
     ;
   if (*s != '\0')
     *s++ = '\0';
@@ -1620,18 +2120,19 @@ md_assemble (str)
   insn = opcode->opcode;
 
   str = s;
-  while (isspace (*str))
+  while (ISSPACE (*str))
     ++str;
 
   /* PowerPC operands are just expressions.  The only real issue is
      that a few operand types are optional.  All cases which might use
-     an optional operand separate the operands only with commas (in
-     some cases parentheses are used, as in ``lwz 1,0(1)'' but such
-     cases never have optional operands).  There is never more than
-     one optional operand for an instruction.  So, before we start
-     seriously parsing the operands, we check to see if we have an
-     optional operand, and, if we do, we count the number of commas to
-     see whether the operand should be omitted.  */
+     an optional operand separate the operands only with commas (in some
+     cases parentheses are used, as in ``lwz 1,0(1)'' but such cases never
+     have optional operands).  Most instructions with optional operands
+     have only one.  Those that have more than one optional operand can
+     take either all their operands or none.  So, before we start seriously
+     parsing the operands, we check to see if we have optional operands,
+     and if we do, we count the number of commas to see which operands
+     have been omitted.  */
   skip_optional = 0;
   for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++)
     {
@@ -1641,6 +2142,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.  */
@@ -1657,10 +2160,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))
+            operands.  */
+         if (opcount < num_operands_expected)
            skip_optional = 1;
 
          break;
@@ -1686,14 +2195,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;
@@ -1706,7 +2214,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);
            }
@@ -1720,94 +2228,96 @@ md_assemble (str)
       input_line_pointer = str;
 
 #ifdef TE_PE
-      if (*input_line_pointer == '[') 
+      if (*input_line_pointer == '[')
        {
          /* We are expecting something like the second argument here:
-
-               lwz r4,[toc].GS.0.static_int(rtoc)
-                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-            The argument following the `]' must be a symbol name, and the 
-             register must be the toc register: 'rtoc' or '2'
-
-            The effect is to 0 as the displacement field
-            in the instruction, and issue an IMAGE_REL_PPC_TOCREL16 (or
-            the appropriate variation) reloc against it based on the symbol.
-            The linker will build the toc, and insert the resolved toc offset.
-
-            Note:
-            o The size of the toc entry is currently assumed to be
-              32 bits. This should not be assumed to be a hard coded
-              number.
-            o In an effort to cope with a change from 32 to 64 bits,
-              there are also toc entries that are specified to be
-              either 32 or 64 bits:
-                 lwz r4,[toc32].GS.0.static_int(rtoc)
-                lwz r4,[toc64].GS.0.static_int(rtoc)
-              These demand toc entries of the specified size, and the
-              instruction probably requires it.
-          */
+          *
+          *    lwz r4,[toc].GS.0.static_int(rtoc)
+          *           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+          * The argument following the `]' must be a symbol name, and the
+          * register must be the toc register: 'rtoc' or '2'
+          *
+          * The effect is to 0 as the displacement field
+          * in the instruction, and issue an IMAGE_REL_PPC_TOCREL16 (or
+          * the appropriate variation) reloc against it based on the symbol.
+          * The linker will build the toc, and insert the resolved toc offset.
+          *
+          * Note:
+          * o The size of the toc entry is currently assumed to be
+          *   32 bits. This should not be assumed to be a hard coded
+          *   number.
+          * o In an effort to cope with a change from 32 to 64 bits,
+          *   there are also toc entries that are specified to be
+          *   either 32 or 64 bits:
+          *     lwz r4,[toc32].GS.0.static_int(rtoc)
+          *     lwz r4,[toc64].GS.0.static_int(rtoc)
+          *   These demand toc entries of the specified size, and the
+          *   instruction probably requires it.
+          */
 
          int valid_toc;
          enum toc_size_qualifier toc_kind;
          bfd_reloc_code_real_type toc_reloc;
 
-         /* go parse off the [tocXX] part */
-         valid_toc = parse_toc_entry(&toc_kind);
+         /* Go parse off the [tocXX] part.  */
+         valid_toc = parse_toc_entry (&toc_kind);
 
-         if (!valid_toc) 
+         if (!valid_toc)
            {
-             /* Note: message has already been issued.     */
-             /* FIXME: what sort of recovery should we do? */
-             /*        demand_rest_of_line(); return; ?    */
+             /* Note: message has already been issued.
+                FIXME: what sort of recovery should we do?
+                demand_rest_of_line (); return; ?  */
            }
 
-         /* Now get the symbol following the ']' */
-         expression(&ex);
+         /* Now get the symbol following the ']' */
+         expression (&ex);
 
          switch (toc_kind)
            {
            case default_toc:
-             /* In this case, we may not have seen the symbol yet, since  */
-             /* it is allowed to appear on a .extern or .globl or just be */
-             /* a label in the .data section.                             */
+             /* In this case, we may not have seen the symbol yet,
+                since  it is allowed to appear on a .extern or .globl
+                or just be a label in the .data section.  */
              toc_reloc = BFD_RELOC_PPC_TOC16;
              break;
            case data_in_toc:
-             /* 1. The symbol must be defined and either in the toc        */
-             /*    section, or a global.                                   */
-             /* 2. The reloc generated must have the TOCDEFN flag set in   */
-             /*    upper bit mess of the reloc type.                       */
-             /* FIXME: It's a little confusing what the tocv qualifier can */
-             /*        be used for. At the very least, I've seen three     */
-             /*        uses, only one of which I'm sure I can explain.     */
-             if (ex.X_op == O_symbol) 
-               {                 
+             /* 1. The symbol must be defined and either in the toc
+                section, or a global.
+                2. The reloc generated must have the TOCDEFN flag set
+                in upper bit mess of the reloc type.
+                FIXME: It's a little confusing what the tocv
+                qualifier can be used for.  At the very least, I've
+                seen three uses, only one of which I'm sure I can
+                explain.  */
+             if (ex.X_op == O_symbol)
+               {
                  assert (ex.X_add_symbol != NULL);
-                 if (ex.X_add_symbol->bsym->section != tocdata_section)
+                 if (symbol_get_bfdsym (ex.X_add_symbol)->section
+                     != tocdata_section)
                    {
-                     as_bad(_("[tocv] symbol is not a toc symbol"));
+                     as_bad (_("[tocv] symbol is not a toc symbol"));
                    }
                }
 
              toc_reloc = BFD_RELOC_PPC_TOC16;
              break;
            case must_be_32:
-             /* FIXME: these next two specifically specify 32/64 bit toc   */
-             /*        entries. We don't support them today. Is this the   */
-             /*        right way to say that?                              */
+             /* FIXME: these next two specifically specify 32/64 bit
+                toc entries.  We don't support them today.  Is this
+                the right way to say that?  */
              toc_reloc = BFD_RELOC_UNUSED;
              as_bad (_("Unimplemented toc32 expression modifier"));
              break;
            case must_be_64:
-             /* FIXME: see above */
+             /* FIXME: see above */
              toc_reloc = BFD_RELOC_UNUSED;
              as_bad (_("Unimplemented toc64 expression modifier"));
              break;
            default:
-             fprintf(stderr, 
-                     _("Unexpected return value [%d] from parse_toc_entry!\n"),
-                     toc_kind);
-             abort();
+             fprintf (stderr,
+                      _("Unexpected return value [%d] from parse_toc_entry!\n"),
+                      toc_kind);
+             abort ();
              break;
            }
 
@@ -1820,8 +2330,8 @@ md_assemble (str)
          fixups[fc].opindex = *opindex_ptr;
          ++fc;
 
-          /* Ok. We've set up the fixup for the instruction. Now make it
-            look like the constant 0 was found here */
+         /* Ok. We've set up the fixup for the instruction. Now make it
+            look like the constant 0 was found here */
          ex.X_unsigned = 1;
          ex.X_op = O_constant;
          ex.X_add_number = 0;
@@ -1835,9 +2345,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;
            }
        }
 
@@ -1856,7 +2366,7 @@ md_assemble (str)
       else if (ex.X_op == O_constant)
        {
 #ifdef OBJ_ELF
-         /* Allow @HA, @L, @H on constants. */
+         /* Allow @HA, @L, @H on constants.  */
          char *orig_str = str;
 
          if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
@@ -1868,35 +2378,84 @@ md_assemble (str)
 
              case BFD_RELOC_LO16:
                /* X_unsigned is the default, so if the user has done
-                   something which cleared it, we always produce a
-                   signed value.  */
-               if (ex.X_unsigned
-                   && (operand->flags & PPC_OPERAND_SIGNED) == 0)
+                  something which cleared it, we always produce a
+                  signed value.  */
+               if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
                  ex.X_add_number &= 0xffff;
                else
-                 ex.X_add_number = (((ex.X_add_number & 0xffff)
-                                     ^ 0x8000)
-                                    - 0x8000);
+                 ex.X_add_number = SEX16 (ex.X_add_number);
                break;
 
              case BFD_RELOC_HI16:
-               ex.X_add_number = (ex.X_add_number >> 16) & 0xffff;
+               if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
+                 ex.X_add_number = PPC_HI (ex.X_add_number);
+               else
+                 ex.X_add_number = SEX16 (PPC_HI (ex.X_add_number));
                break;
 
              case BFD_RELOC_HI16_S:
-               ex.X_add_number = (((ex.X_add_number >> 16) & 0xffff)
-                                  + ((ex.X_add_number >> 15) & 1));
+               if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
+                 ex.X_add_number = PPC_HA (ex.X_add_number);
+               else
+                 ex.X_add_number = SEX16 (PPC_HA (ex.X_add_number));
+               break;
+
+             case BFD_RELOC_PPC64_HIGHER:
+               if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
+                 ex.X_add_number = PPC_HIGHER (ex.X_add_number);
+               else
+                 ex.X_add_number = SEX16 (PPC_HIGHER (ex.X_add_number));
+               break;
+
+             case BFD_RELOC_PPC64_HIGHER_S:
+               if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
+                 ex.X_add_number = PPC_HIGHERA (ex.X_add_number);
+               else
+                 ex.X_add_number = SEX16 (PPC_HIGHERA (ex.X_add_number));
+               break;
+
+             case BFD_RELOC_PPC64_HIGHEST:
+               if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
+                 ex.X_add_number = PPC_HIGHEST (ex.X_add_number);
+               else
+                 ex.X_add_number = SEX16 (PPC_HIGHEST (ex.X_add_number));
+               break;
+
+             case BFD_RELOC_PPC64_HIGHEST_S:
+               if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED))
+                 ex.X_add_number = PPC_HIGHESTA (ex.X_add_number);
+               else
+                 ex.X_add_number = SEX16 (PPC_HIGHESTA (ex.X_add_number));
                break;
              }
-#endif
+#endif /* OBJ_ELF */
          insn = ppc_insert_operand (insn, operand, ex.X_add_number,
                                     (char *) NULL, 0);
        }
 #ifdef OBJ_ELF
       else if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
        {
-         /* For the absoulte forms of branchs, convert the PC relative form back into
-            the absolute.  */
+         /* 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)
            {
              switch (reloc)
@@ -1918,6 +2477,67 @@ md_assemble (str)
                }
            }
 
+         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"));
@@ -1965,22 +2585,56 @@ md_assemble (str)
        ++str;
     }
 
-  while (isspace (*str))
+  while (ISSPACE (*str))
     ++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);
+  addr_mod = frag_now_fix () & 3;
+  if (frag_now->has_code && frag_now->insn_addr != addr_mod)
+    as_bad (_("instruction address is not a multiple of 4"));
+  frag_now->insn_addr = addr_mod;
+  frag_now->has_code = 1;
   md_number_to_chars (f, insn, 4);
 
+#ifdef OBJ_ELF
+  dwarf2_emit_insn (4);
+#endif
+
   /* Create any fixups.  At this point we do not use a
      bfd_reloc_code_real_type, but instead just use the
      BFD_RELOC_UNUSED plus the operand index.  This lets us easily
      handle fixups for any operand type, although that is admittedly
      not a very exciting feature.  We pick a BFD reloc type in
-     md_apply_fix.  */
+     md_apply_fix3.  */
   for (i = 0; i < fc; i++)
     {
       const struct powerpc_operand *operand;
@@ -1988,11 +2642,12 @@ md_assemble (str)
       operand = &powerpc_operands[fixups[i].opindex];
       if (fixups[i].reloc != BFD_RELOC_UNUSED)
        {
-         reloc_howto_type *reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc);
+         reloc_howto_type *reloc_howto;
          int size;
          int offset;
          fixS *fixP;
 
+         reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc);
          if (!reloc_howto)
            abort ();
 
@@ -2000,10 +2655,13 @@ md_assemble (str)
          offset = target_big_endian ? (4 - size) : 0;
 
          if (size < 1 || size > 4)
-           abort();
+           abort ();
 
-         fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset, size,
-                             &fixups[i].exp, reloc_howto->pc_relative,
+         fixP = fix_new_exp (frag_now,
+                             f - frag_now->fr_literal + offset,
+                             size,
+                             &fixups[i].exp,
+                             reloc_howto->pc_relative,
                              fixups[i].reloc);
 
          /* Turn off complaints that the addend is too large for things like
@@ -2015,6 +2673,12 @@ md_assemble (str)
            case BFD_RELOC_LO16:
            case BFD_RELOC_HI16:
            case BFD_RELOC_HI16_S:
+#ifdef OBJ_ELF
+           case BFD_RELOC_PPC64_HIGHER:
+           case BFD_RELOC_PPC64_HIGHER_S:
+           case BFD_RELOC_PPC64_HIGHEST:
+           case BFD_RELOC_PPC64_HIGHEST_S:
+#endif
              fixP->fx_no_overflow = 1;
              break;
            default:
@@ -2022,11 +2686,13 @@ md_assemble (str)
            }
        }
       else
-       fix_new_exp (frag_now, f - frag_now->fr_literal, 4,
+       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)));
+                     (fixups[i].opindex + (int) BFD_RELOC_UNUSED)));
     }
 }
 
@@ -2061,7 +2727,7 @@ ppc_macro (str, macro)
       if (s == (char *) NULL)
        break;
       *s++ = '\0';
-    }  
+    }
 
   if (count != macro->operands)
     {
@@ -2108,10 +2774,10 @@ ppc_macro (str, macro)
 
   /* Assemble the constructed instruction.  */
   md_assemble (complete);
-}  
+}
 \f
 #ifdef OBJ_ELF
-/* For ELF, add support for SHF_EXCLUDE and SHT_ORDERED */
+/* For ELF, add support for SHF_EXCLUDE and SHT_ORDERED */
 
 int
 ppc_section_letter (letter, ptr_msg)
@@ -2121,8 +2787,8 @@ ppc_section_letter (letter, ptr_msg)
   if (letter == 'e')
     return SHF_EXCLUDE;
 
-  *ptr_msg = _("Bad .section directive: want a,w,x,e in string");
-  return 0;
+  *ptr_msg = _("Bad .section directive: want a,e,w,x,M,S,G,T in string");
+  return -1;
 }
 
 int
@@ -2171,7 +2837,7 @@ ppc_section_flags (flags, attr, type)
 
 static void
 ppc_byte (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   if (*input_line_pointer != '\"')
     {
@@ -2207,11 +2873,12 @@ 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
-   symbols, and uses a different smclas.  */
+   symbols, and uses a different smclas.  The native Aix 4.3.3 assembler
+   aligns .comm and .lcomm to 4 bytes.  */
 
 static void
 ppc_comm (lcomm)
@@ -2253,7 +2920,7 @@ ppc_comm (lcomm)
     {
       /* The third argument to .comm is the alignment.  */
       if (*input_line_pointer != ',')
-       align = 3;
+       align = 2;
       else
        {
          ++input_line_pointer;
@@ -2261,7 +2928,7 @@ ppc_comm (lcomm)
          if (align <= 0)
            {
              as_warn (_("ignoring bad alignment"));
-             align = 3;
+             align = 2;
            }
        }
     }
@@ -2270,11 +2937,7 @@ ppc_comm (lcomm)
       char *lcomm_name;
       char lcomm_endc;
 
-      if (size <= 1)
-       align = 0;
-      else if (size <= 2)
-       align = 1;
-      else if (size <= 4)
+      if (size <= 4)
        align = 2;
       else
        align = 3;
@@ -2293,7 +2956,7 @@ ppc_comm (lcomm)
 
       lcomm_name = input_line_pointer;
       lcomm_endc = get_symbol_end ();
-      
+
       lcomm_sym = symbol_find_or_make (lcomm_name);
 
       *input_line_pointer = lcomm_endc;
@@ -2310,9 +2973,9 @@ ppc_comm (lcomm)
       ignore_rest_of_line ();
       return;
     }
-    
+
   record_alignment (bss_section, align);
-         
+
   if (! lcomm
       || ! S_IS_DEFINED (lcomm_sym))
     {
@@ -2334,7 +2997,7 @@ ppc_comm (lcomm)
 
       subseg_set (bss_section, 1);
       frag_align (align, 0, 0);
-  
+
       symbol_set_frag (def_sym, frag_now);
       pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, def_sym,
                        def_size, (char *) NULL);
@@ -2374,15 +3037,16 @@ ppc_comm (lcomm)
 
 static void
 ppc_csect (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   char *name;
   char endc;
   symbolS *sym;
+  offsetT align;
 
   name = input_line_pointer;
   endc = get_symbol_end ();
-  
+
   sym = symbol_find_or_make (name);
 
   *input_line_pointer = endc;
@@ -2393,22 +3057,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);
@@ -2418,11 +3084,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:
@@ -2437,6 +3106,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:
@@ -2459,32 +3129,38 @@ ppc_change_csect (sym)
        }
 
       /* We set the obstack chunk size to a small value before
-         changing subsegments, so that we don't use a lot of memory
-         space for what may be a small section.  */
+        changing subsegments, so that we don't use a lot of memory
+        space for what may be a small section.  */
       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 = 2;
+      symbol_get_tc (sym)->align = align;
       symbol_get_tc (sym)->output = 1;
       symbol_get_tc (sym)->within = sym;
-         
+
       for (list = *list_ptr;
           symbol_get_tc (list)->next != (symbolS *) NULL;
           list = symbol_get_tc (list)->next)
        ;
       symbol_get_tc (list)->next = sym;
-         
+
       symbol_remove (sym, &symbol_rootP, &symbol_lastP);
       symbol_append (sym, symbol_get_tc (list)->within, &symbol_rootP,
                     &symbol_lastP);
@@ -2513,7 +3189,7 @@ ppc_section (type)
 
   sym = symbol_find_or_make (name);
 
-  ppc_change_csect (sym);
+  ppc_change_csect (sym, 2);
 
   demand_empty_rest_of_line ();
 }
@@ -2524,7 +3200,7 @@ ppc_section (type)
 
 static void
 ppc_named_section (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   char *user_name;
   const char *real_name;
@@ -2550,7 +3226,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 ();
 }
@@ -2559,7 +3235,7 @@ ppc_named_section (ignore)
 
 static void
 ppc_extern (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   char *name;
   char endc;
@@ -2578,7 +3254,7 @@ ppc_extern (ignore)
 
 static void
 ppc_lglobl (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   char *name;
   char endc;
@@ -2601,7 +3277,7 @@ ppc_lglobl (ignore)
 
 static void
 ppc_rename (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   char *name;
   char endc;
@@ -2637,7 +3313,7 @@ ppc_rename (ignore)
 
 static void
 ppc_stabx (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   char *name;
   int len;
@@ -2653,9 +3329,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;
 
@@ -2687,8 +3363,8 @@ ppc_stabx (ignore)
 
     default:
       /* The value is some complex expression.  This will probably
-         fail at some later point, but this is probably the right
-         thing to do here.  */
+        fail at some later point, but this is probably the right
+        thing to do here.  */
       symbol_set_value_expression (sym, &exp);
       break;
     }
@@ -2716,9 +3392,29 @@ ppc_stabx (ignore)
 
   symbol_get_tc (sym)->output = 1;
 
-  if (S_GET_STORAGE_CLASS (sym) == C_STSYM)
+  if (S_GET_STORAGE_CLASS (sym) == C_STSYM) {
+
     symbol_get_tc (sym)->within = ppc_current_block;
 
+    /* In this case :
+
+       .bs name
+       .stabx  "z",arrays_,133,0
+       .es
+
+       .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.  */
+
+    if (exp.X_op == O_symbol)
+      {
+       symbol_get_tc (exp.X_add_symbol)->within = ppc_current_block;
+      }
+  }
+
   if (exp.X_op != O_symbol
       || ! S_IS_EXTERNAL (exp.X_add_symbol)
       || S_GET_SEGMENT (exp.X_add_symbol) != bss_section)
@@ -2736,7 +3432,7 @@ ppc_stabx (ignore)
 
 /* The .function pseudo-op.  This takes several arguments.  The first
    argument seems to be the external name of the symbol.  The second
-   argment seems to be the label for the start of the function.  gcc
+   argument seems to be the label for the start of the function.  gcc
    uses the same name for both.  I have no idea what the third and
    fourth arguments are meant to be.  The optional fifth argument is
    an expression for the size of the function.  In COFF this symbol
@@ -2744,7 +3440,7 @@ ppc_stabx (ignore)
 
 static void
 ppc_function (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   char *name;
   char endc;
@@ -2831,11 +3527,14 @@ ppc_function (ignore)
 }
 
 /* The .bf pseudo-op.  This is just like a COFF C_FCN symbol named
-   ".bf".  */
+   ".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
 ppc_bf (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   symbolS *sym;
 
@@ -2850,6 +3549,14 @@ ppc_bf (ignore)
   S_SET_NUMBER_AUXILIARY (sym, 1);
   SA_SET_SYM_LNNO (sym, coff_line_base);
 
+  /* Line number for bi.  */
+  if (saved_bi_sym)
+    {
+      S_SET_VALUE (saved_bi_sym, coff_n_line_nos);
+      saved_bi_sym = 0;
+    }
+
+
   symbol_get_tc (sym)->output = 1;
 
   ppc_frob_label (sym);
@@ -2863,7 +3570,7 @@ ppc_bf (ignore)
 
 static void
 ppc_ef (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   symbolS *sym;
 
@@ -2883,7 +3590,8 @@ ppc_ef (ignore)
 
 /* The .bi and .ei pseudo-ops.  These take a string argument and
    generates a C_BINCL or C_EINCL symbol, which goes at the start of
-   the symbol list.  */
+   the symbol list.  The value of .bi will be know when the next .bf
+   is encountered.  */
 
 static void
 ppc_biei (ei)
@@ -2912,7 +3620,13 @@ ppc_biei (ei)
 
   S_SET_STORAGE_CLASS (sym, ei ? C_EINCL : C_BINCL);
   symbol_get_tc (sym)->output = 1;
-  
+
+  /* Save bi.  */
+  if (ei)
+    saved_bi_sym = 0;
+  else
+    saved_bi_sym = sym;
+
   for (look = last_biei ? last_biei : symbol_rootP;
        (look != (symbolS *) NULL
        && (S_GET_STORAGE_CLASS (look) == C_FILE
@@ -2936,7 +3650,7 @@ ppc_biei (ei)
 
 static void
 ppc_bs (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   char *name;
   char endc;
@@ -2972,7 +3686,7 @@ ppc_bs (ignore)
 
 static void
 ppc_es (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   symbolS *sym;
 
@@ -2997,7 +3711,7 @@ ppc_es (ignore)
 
 static void
 ppc_bb (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   symbolS *sym;
 
@@ -3024,7 +3738,7 @@ ppc_bb (ignore)
 
 static void
 ppc_eb (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   symbolS *sym;
 
@@ -3049,7 +3763,7 @@ ppc_eb (ignore)
 
 static void
 ppc_bc (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   char *name;
   int len;
@@ -3072,7 +3786,7 @@ ppc_bc (ignore)
 
 static void
 ppc_ec (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   symbolS *sym;
 
@@ -3092,7 +3806,7 @@ ppc_ec (ignore)
 
 static void
 ppc_toc (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   if (ppc_toc_csect != (symbolS *) NULL)
     subseg_set (data_section, symbol_get_tc (ppc_toc_csect)->subseg);
@@ -3101,7 +3815,7 @@ ppc_toc (ignore)
       subsegT subseg;
       symbolS *sym;
       symbolS *list;
-    
+
       subseg = ppc_data_subsegment;
       ++ppc_data_subsegment;
 
@@ -3117,7 +3831,7 @@ ppc_toc (ignore)
       symbol_get_tc (sym)->within = sym;
 
       ppc_toc_csect = sym;
-         
+
       for (list = ppc_data_csects;
           symbol_get_tc (list)->next != (symbolS *) NULL;
           list = symbol_get_tc (list)->next)
@@ -3148,7 +3862,7 @@ ppc_xcoff_cons (log_size)
 
 static void
 ppc_vbyte (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   expressionS exp;
   int byte_count;
@@ -3174,22 +3888,25 @@ ppc_vbyte (dummy)
 }
 
 #endif /* OBJ_XCOFF */
+#if defined (OBJ_XCOFF) || defined (OBJ_ELF)
 \f
 /* The .tc pseudo-op.  This is used when generating either XCOFF or
    ELF.  This takes two or more arguments.
 
    When generating XCOFF output, the first argument is the name to
    give to this location in the toc; this will be a symbol with class
-   TC.  The rest of the arguments are byte values to actually put at
+   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.
+   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.
 
    When not generating XCOFF output, the arguments are the same, but
    the first argument is simply ignored.  */
 
 static void
 ppc_tc (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
 #ifdef OBJ_XCOFF
 
@@ -3245,7 +3962,9 @@ ppc_tc (ignore)
     ppc_frob_label (sym);
   }
 
-#else /* ! defined (OBJ_XCOFF) */
+#endif /* OBJ_XCOFF */
+#ifdef OBJ_ELF
+  int align;
 
   /* Skip the TOC symbol name.  */
   while (is_part_of_name (*input_line_pointer)
@@ -3255,24 +3974,107 @@ ppc_tc (ignore)
         || *input_line_pointer == '}')
     ++input_line_pointer;
 
-  /* Align to a four byte boundary.  */
-  frag_align (2, 0, 0);
-  record_alignment (now_seg, 2);
-
-#endif /* ! defined (OBJ_XCOFF) */
+  /* Align to a four/eight byte boundary.  */
+  align = ppc_obj64 ? 3 : 2;
+  frag_align (align, 0, 0);
+  record_alignment (now_seg, align);
+#endif /* OBJ_ELF */
 
   if (*input_line_pointer != ',')
     demand_empty_rest_of_line ();
   else
     {
       ++input_line_pointer;
-      cons (4);
+      cons (ppc_obj64 ? 8 : 4);
+    }
+}
+
+/* Pseudo-op .machine.  */
+
+static void
+ppc_machine (ignore)
+     int ignore ATTRIBUTE_UNUSED;
+{
+  char *cpu_string;
+#define MAX_HISTORY 100
+  static unsigned long *cpu_history;
+  static int curr_hist;
+
+  SKIP_WHITESPACE ();
+
+  if (*input_line_pointer == '"')
+    {
+      int len;
+      cpu_string = demand_copy_C_string (&len);
+    }
+  else
+    {
+      char c;
+      cpu_string = input_line_pointer;
+      c = get_symbol_end ();
+      cpu_string = xstrdup (cpu_string);
+      *input_line_pointer = c;
+    }
+
+  if (cpu_string != NULL)
+    {
+      unsigned long old_cpu = ppc_cpu;
+      char *p;
+
+      for (p = cpu_string; *p != 0; p++)
+       *p = TOLOWER (*p);
+
+      if (strcmp (cpu_string, "push") == 0)
+       {
+         if (cpu_history == NULL)
+           cpu_history = xmalloc (MAX_HISTORY * sizeof (*cpu_history));
+
+         if (curr_hist >= MAX_HISTORY)
+           as_bad (_(".machine stack overflow"));
+         else
+           cpu_history[curr_hist++] = ppc_cpu;
+       }
+      else if (strcmp (cpu_string, "pop") == 0)
+       {
+         if (curr_hist <= 0)
+           as_bad (_(".machine stack underflow"));
+         else
+           ppc_cpu = cpu_history[--curr_hist];
+       }
+      else if (parse_cpu (cpu_string))
+       ;
+      else
+       as_bad (_("invalid machine `%s'"), cpu_string);
+
+      if (ppc_cpu != old_cpu)
+       ppc_setup_opcodes ();
     }
+
+  demand_empty_rest_of_line ();
+}
+
+/* See whether a symbol is in the TOC section.  */
+
+static int
+ppc_is_toc_sym (sym)
+     symbolS *sym;
+{
+#ifdef OBJ_XCOFF
+  return symbol_get_tc (sym)->class == XMC_TC;
+#endif
+#ifdef OBJ_ELF
+  const char *sname = segment_name (S_GET_SEGMENT (sym));
+  if (ppc_obj64)
+    return strcmp (sname, ".toc") == 0;
+  else
+    return strcmp (sname, ".got") == 0;
+#endif
 }
+#endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */
 \f
 #ifdef TE_PE
 
-/* Pseudo-ops specific to the Windows NT PowerPC PE (coff) format */
+/* Pseudo-ops specific to the Windows NT PowerPC PE (coff) format */
 
 /* Set the current section.  */
 static void
@@ -3286,86 +4088,85 @@ ppc_set_current_section (new)
 /* pseudo-op: .previous
    behaviour: toggles the current section with the previous section.
    errors:    None
-   warnings:  "No previous section"
-*/
+   warnings:  "No previous section"  */
+
 static void
-ppc_previous(ignore)
-     int ignore;
+ppc_previous (ignore)
+     int ignore ATTRIBUTE_UNUSED;
 {
   symbolS *tmp;
 
-  if (ppc_previous_section == NULL) 
+  if (ppc_previous_section == NULL)
     {
-      as_warn(_("No previous section to return to. Directive ignored."));
+      as_warn (_("No previous section to return to. Directive ignored."));
       return;
     }
 
-  subseg_set(ppc_previous_section, 0);
+  subseg_set (ppc_previous_section, 0);
 
-  ppc_set_current_section(ppc_previous_section);
+  ppc_set_current_section (ppc_previous_section);
 }
 
 /* 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)
 
    commentary:
    Tag index tables (also known as the function table) for exception
-   handling, debugging, etc.
+   handling, debugging, etc.  */
 
-*/
 static void
-ppc_pdata(ignore)
-     int ignore;
+ppc_pdata (ignore)
+     int ignore ATTRIBUTE_UNUSED;
 {
-  if (pdata_section == 0) 
+  if (pdata_section == 0)
     {
       pdata_section = subseg_new (".pdata", 0);
-      
+
       bfd_set_section_flags (stdoutput, pdata_section,
                             (SEC_ALLOC | SEC_LOAD | SEC_RELOC
                              | SEC_READONLY | SEC_DATA ));
-      
+
       bfd_set_section_alignment (stdoutput, pdata_section, 2);
     }
   else
     {
-      pdata_section = subseg_new(".pdata", 0);
+      pdata_section = subseg_new (".pdata", 0);
     }
-  ppc_set_current_section(pdata_section);
+  ppc_set_current_section (pdata_section);
 }
 
 /* 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)
    commentary:
    Tag tables (also known as the scope table) for exception handling,
-   debugging, etc.
-*/
+   debugging, etc.  */
+
 static void
-ppc_ydata(ignore)
-     int ignore;
+ppc_ydata (ignore)
+     int ignore ATTRIBUTE_UNUSED;
 {
-  if (ydata_section == 0) 
+  if (ydata_section == 0)
     {
       ydata_section = subseg_new (".ydata", 0);
       bfd_set_section_flags (stdoutput, ydata_section,
-                        (SEC_ALLOC | SEC_LOAD | SEC_RELOC
-                                      | SEC_READONLY | SEC_DATA ));
+                            (SEC_ALLOC | SEC_LOAD | SEC_RELOC
+                             | SEC_READONLY | SEC_DATA ));
 
       bfd_set_section_alignment (stdoutput, ydata_section, 3);
     }
@@ -3373,12 +4174,12 @@ ppc_ydata(ignore)
     {
       ydata_section = subseg_new (".ydata", 0);
     }
-  ppc_set_current_section(ydata_section);
+  ppc_set_current_section (ydata_section);
 }
 
 /* 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
@@ -3391,19 +4192,19 @@ ppc_ydata(ignore)
 
    commentary:
    Like .data, but intended to hold data subject to relocation, such as
-   function descriptors, etc.
-*/
+   function descriptors, etc.  */
+
 static void
-ppc_reldata(ignore)
-     int ignore;
+ppc_reldata (ignore)
+     int ignore ATTRIBUTE_UNUSED;
 {
   if (reldata_section == 0)
     {
       reldata_section = subseg_new (".reldata", 0);
 
       bfd_set_section_flags (stdoutput, reldata_section,
-                            ( SEC_ALLOC | SEC_LOAD | SEC_RELOC 
-                             | SEC_DATA ));
+                            (SEC_ALLOC | SEC_LOAD | SEC_RELOC
+                             | SEC_DATA));
 
       bfd_set_section_alignment (stdoutput, reldata_section, 2);
     }
@@ -3411,22 +4212,22 @@ ppc_reldata(ignore)
     {
       reldata_section = subseg_new (".reldata", 0);
     }
-  ppc_set_current_section(reldata_section);
+  ppc_set_current_section (reldata_section);
 }
 
 /* pseudo-op: .rdata
    behaviour: predefined read only data section
-              double word aligned
+             double word aligned
    errors:    None
    warnings:  None
    initial:   .section .rdata "dr3"
              d - initialized data
              r - readable
-             3 - double word aligned (that would be 4 byte boundary)
-*/
+             3 - double word aligned (that would be 4 byte boundary)  */
+
 static void
-ppc_rdata(ignore)
-     int ignore;
+ppc_rdata (ignore)
+     int ignore ATTRIBUTE_UNUSED;
 {
   if (rdata_section == 0)
     {
@@ -3441,43 +4242,40 @@ ppc_rdata(ignore)
     {
       rdata_section = subseg_new (".rdata", 0);
     }
-  ppc_set_current_section(rdata_section);
+  ppc_set_current_section (rdata_section);
 }
 
 /* pseudo-op: .ualong
-   behaviour: much like .int, with the exception that no alignment is 
-              performed.
+   behaviour: much like .int, with the exception that no alignment is
+             performed.
              FIXME: test the alignment statement
    errors:    None
-   warnings:  None
-*/
+   warnings:  None  */
+
 static void
-ppc_ualong(ignore)
-     int ignore;
+ppc_ualong (ignore)
+     int ignore ATTRIBUTE_UNUSED;
 {
-  /* try for long */
-  cons ( 4 );
+  /* Try for long.  */
+  cons (4);
 }
 
 /* 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
-*/
+   warnings:  Missing symbol name  */
+
 static void
-ppc_znop(ignore)
-     int ignore;
+ppc_znop (ignore)
+     int ignore ATTRIBUTE_UNUSED;
 {
   unsigned long insn;
   const struct powerpc_opcode *opcode;
   expressionS ex;
   char *f;
-
   symbolS *sym;
-
-  /* Strip out the symbol name */
   char *symbol_name;
   char c;
   char *name;
@@ -3485,6 +4283,7 @@ ppc_znop(ignore)
   flagword flags;
   asection *sec;
 
+  /* Strip out the symbol name.  */
   symbol_name = input_line_pointer;
   c = get_symbol_end ();
 
@@ -3500,7 +4299,7 @@ ppc_znop(ignore)
   /* Look up the opcode in the hash table.  */
   opcode = (const struct powerpc_opcode *) hash_find (ppc_hash, "nop");
 
-  /* stick in the nop */
+  /* Stick in the nop.  */
   insn = opcode->opcode;
 
   /* Write out the instruction.  */
@@ -3516,13 +4315,13 @@ ppc_znop(ignore)
 
 }
 
-/* pseudo-op: 
-   behaviour: 
-   errors:    
-   warnings:  
-*/
+/* pseudo-op:
+   behaviour:
+   errors:
+   warnings:  */
+
 static void
-ppc_pe_comm(lcomm)
+ppc_pe_comm (lcomm)
      int lcomm;
 {
   register char *name;
@@ -3535,7 +4334,7 @@ ppc_pe_comm(lcomm)
   name = input_line_pointer;
   c = get_symbol_end ();
 
-  /* just after name is now '\0' */
+  /* just after name is now '\0' */
   p = input_line_pointer;
   *p = c;
   SKIP_WHITESPACE ();
@@ -3619,7 +4418,7 @@ ppc_pe_comm(lcomm)
  * additions/changes for the moto-pas assembler support. There are three
  * categories:
  *
- * FIXME: I just noticed this. This doesn't work at all really. It it 
+ * FIXME: I just noticed this. This doesn't work at all really. It it
  *        setting bits that bfd probably neither understands or uses. The
  *        correct approach (?) will have to incorporate extra fields attached
  *        to the section to hold the system specific stuff. (krk)
@@ -3652,9 +4451,9 @@ ppc_pe_comm(lcomm)
 
 void
 ppc_pe_section (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
-  /* Strip out the section name */
+  /* Strip out the section name */
   char *section_name;
   char c;
   char *name;
@@ -3697,7 +4496,8 @@ ppc_pe_section (ignore)
       align = 1;
     }
   else
-    align = 4; /* default alignment to 16 byte boundary */
+    /* Default alignment to 16 byte boundary.  */
+    align = 4;
 
   if (*input_line_pointer == ',')
     {
@@ -3718,7 +4518,7 @@ ppc_pe_section (ignore)
                  as_bad (_("Unsupported section attribute -- 'a'"));
                  break;
                case 'c': /* code section */
-                 flags |= SEC_CODE; 
+                 flags |= SEC_CODE;
                  break;
                case 'd': /* section has initialized data */
                  flags |= SEC_DATA;
@@ -3734,7 +4534,7 @@ ppc_pe_section (ignore)
                  flags |= SEC_HAS_CONTENTS;
                  break;
                case 'n': /* section can be discarded */
-                 flags &=~ SEC_LOAD; 
+                 flags &=~ SEC_LOAD;
                  break;
                case 'R': /* Remove section at link time */
                  flags |= SEC_NEVER_LOAD;
@@ -3785,8 +4585,8 @@ ppc_pe_section (ignore)
                  break;
 
                default:
-                 as_bad(_("unknown section attribute '%c'"),
-                        *input_line_pointer);
+                 as_bad (_("unknown section attribute '%c'"),
+                         *input_line_pointer);
                  break;
                }
              ++input_line_pointer;
@@ -3798,7 +4598,7 @@ ppc_pe_section (ignore)
 
   sec = subseg_new (name, (subsegT) exp);
 
-  ppc_set_current_section(sec);
+  ppc_set_current_section (sec);
 
   if (flags != SEC_NO_FLAGS)
     {
@@ -3808,13 +4608,13 @@ ppc_pe_section (ignore)
                bfd_errmsg (bfd_get_error ()));
     }
 
-  bfd_set_section_alignment(stdoutput, sec, align);
+  bfd_set_section_alignment (stdoutput, sec, align);
 
 }
 
 static void
 ppc_pe_function (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   char *name;
   char endc;
@@ -3837,15 +4637,15 @@ ppc_pe_function (ignore)
 
 static void
 ppc_pe_tocd (ignore)
-     int ignore;
+     int ignore ATTRIBUTE_UNUSED;
 {
   if (tocdata_section == 0)
     {
       tocdata_section = subseg_new (".tocd", 0);
-      /* FIXME: section flags won't work */
+      /* FIXME: section flags won't work */
       bfd_set_section_flags (stdoutput, tocdata_section,
                             (SEC_ALLOC | SEC_LOAD | SEC_RELOC
-                             | SEC_READONLY | SEC_DATA ));
+                             | SEC_READONLY | SEC_DATA));
 
       bfd_set_section_alignment (stdoutput, tocdata_section, 2);
     }
@@ -3854,7 +4654,7 @@ ppc_pe_tocd (ignore)
       rdata_section = subseg_new (".tocd", 0);
     }
 
-  ppc_set_current_section(tocdata_section);
+  ppc_set_current_section (tocdata_section);
 
   demand_empty_rest_of_line ();
 }
@@ -3901,8 +4701,7 @@ ppc_canonicalize_symbol_name (name)
        }
 
       for (s++; *s != '\0' && *s != brac; s++)
-       if (islower (*s))
-         *s = toupper (*s);
+       *s = TOUPPER (*s);
 
       if (*s == '\0' || s[1] != '\0')
        as_bad (_("bad symbol suffix"));
@@ -4025,7 +4824,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
@@ -4043,11 +4842,15 @@ ppc_frob_symbol (sym)
      table.  */
   if (! symbol_used_in_reloc_p (sym)
       && ((symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) != 0
-         || (! S_IS_EXTERNAL (sym)
+         || (! (S_IS_EXTERNAL (sym) || S_IS_WEAK (sym))
              && ! symbol_get_tc (sym)->output
              && 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
@@ -4084,7 +4887,7 @@ ppc_frob_symbol (sym)
       ppc_last_function = sym;
       if (symbol_get_tc (sym)->size != (symbolS *) NULL)
        {
-         resolve_symbol_value (symbol_get_tc (sym)->size, 1);
+         resolve_symbol_value (symbol_get_tc (sym)->size);
          SA_SET_SYM_FSIZE (sym,
                            (long) S_GET_VALUE (symbol_get_tc (sym)->size));
        }
@@ -4105,7 +4908,7 @@ ppc_frob_symbol (sym)
        }
     }
 
-  if (! S_IS_EXTERNAL (sym)
+  if (! (S_IS_EXTERNAL (sym) || S_IS_WEAK (sym))
       && (symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) == 0
       && S_GET_STORAGE_CLASS (sym) != C_FILE
       && S_GET_STORAGE_CLASS (sym) != C_FCN
@@ -4144,7 +4947,7 @@ ppc_frob_symbol (sym)
                                     - S_GET_VALUE (sym));
          else
            {
-             resolve_symbol_value (symbol_get_tc (sym)->next, 1);
+             resolve_symbol_value (symbol_get_tc (sym)->next);
              a->x_csect.x_scnlen.l = (S_GET_VALUE (symbol_get_tc (sym)->next)
                                       - S_GET_VALUE (sym));
            }
@@ -4163,8 +4966,8 @@ ppc_frob_symbol (sym)
       else if (S_GET_SEGMENT (sym) == absolute_section)
        {
          /* This is an absolute symbol.  The csect will be created by
-             ppc_adjust_symtab.  */
-         ppc_saw_abs = true;
+            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;
@@ -4197,7 +5000,7 @@ ppc_frob_symbol (sym)
            }
          else
            {
-             resolve_symbol_value (next, 1);
+             resolve_symbol_value (next);
              a->x_csect.x_scnlen.l = (S_GET_VALUE (next)
                                       - S_GET_VALUE (sym));
            }
@@ -4228,7 +5031,7 @@ ppc_frob_symbol (sym)
            {
              while (symbol_get_tc (csect)->next != (symbolS *) NULL)
                {
-                 resolve_symbol_value (symbol_get_tc (csect)->next, 1);
+                 resolve_symbol_value (symbol_get_tc (csect)->next);
                  if (S_GET_VALUE (symbol_get_tc (csect)->next)
                      > S_GET_VALUE (sym))
                    break;
@@ -4242,7 +5045,7 @@ ppc_frob_symbol (sym)
            }
          a->x_csect.x_smtyp = XTY_LD;
        }
-       
+
       a->x_csect.x_parmhash = 0;
       a->x_csect.x_snhash = 0;
       if (symbol_get_tc (sym)->class == -1)
@@ -4260,10 +5063,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)
@@ -4274,15 +5077,15 @@ ppc_frob_symbol (sym)
       /* 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, 1);
+      resolve_symbol_value (csect);
       S_SET_VALUE (sym, S_GET_VALUE (sym) - S_GET_VALUE (csect));
     }
   else if (S_GET_STORAGE_CLASS (sym) == C_BINCL
           || S_GET_STORAGE_CLASS (sym) == C_EINCL)
     {
       /* We want the value to be a file offset into the line numbers.
-         BFD will do that for us if we set the right flags.  We have
-         already set the value correctly.  */
+        BFD will do that for us if we set the right flags.  We have
+        already set the value correctly.  */
       coffsymbol (symbol_get_bfdsym (sym))->native->fix_line = 1;
     }
 
@@ -4332,7 +5135,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
@@ -4342,8 +5145,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);
 }
@@ -4351,8 +5155,8 @@ ppc_frob_section (sec)
 #endif /* OBJ_XCOFF */
 \f
 /* Turn a string in input_line_pointer into a floating point constant
-   of type type, and store the appropriate bytes in *litp.  The number
-   of LITTLENUMS emitted is stored in *sizep .  An error message is
+   of type TYPE, and store the appropriate bytes in *LITP.  The number
+   of LITTLENUMS emitted is stored in *SIZEP.  An error message is
    returned, or NULL on OK.  */
 
 char *
@@ -4403,7 +5207,7 @@ md_atof (type, litp, sizep)
          litp += 2;
        }
     }
-     
+
   return NULL;
 }
 
@@ -4438,8 +5242,8 @@ md_section_align (seg, addr)
 
 int
 md_estimate_size_before_relax (fragp, seg)
-     fragS *fragp;
-     asection *seg;
+     fragS *fragp ATTRIBUTE_UNUSED;
+     asection *seg ATTRIBUTE_UNUSED;
 {
   abort ();
   return 0;
@@ -4449,19 +5253,18 @@ md_estimate_size_before_relax (fragp, seg)
 
 void
 md_convert_frag (abfd, sec, fragp)
-     bfd *abfd;
-     asection *sec;
-     fragS *fragp;
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *sec ATTRIBUTE_UNUSED;
+     fragS *fragp ATTRIBUTE_UNUSED;
 {
   abort ();
 }
 
 /* We have no need to default values of symbols.  */
 
-/*ARGSUSED*/
 symbolS *
 md_undefined_symbol (name)
-     char *name;
+     char *name ATTRIBUTE_UNUSED;
 {
   return 0;
 }
@@ -4474,7 +5277,7 @@ md_undefined_symbol (name)
 long
 md_pcrel_from_section (fixp, sec)
      fixS *fixp;
-     segT sec;
+     segT sec ATTRIBUTE_UNUSED;
 {
   return fixp->fx_frag->fr_address + fixp->fx_where;
 }
@@ -4490,14 +5293,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, 1);
-  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))
@@ -4508,12 +5313,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, 1);
-         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;
@@ -4526,23 +5332,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 ();
@@ -4552,17 +5359,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
-                    <= symbol_get_frag (fix->fx_addsy)->fr_address))
+         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
-                  == symbol_get_frag (fix->fx_addsy)->fr_address)
-                 && S_GET_VALUE (csect) == S_GET_VALUE (fix->fx_addsy))
+                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;
 
@@ -4577,31 +5382,29 @@ ppc_fix_adjustable (fix)
                    }
 
                  /* If we found the symbol before the next csect
-                     symbol, then this is the csect we want.  */
+                    symbol, then this is the csect we want.  */
                  if (scan == fix->fx_addsy)
                    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, 1);
-      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;
@@ -4629,24 +5432,61 @@ ppc_force_relocation (fix)
                  <= fix->fx_frag->fr_address))))
     return 1;
 
-  return 0;
+  return generic_force_reloc (fix);
 }
 
 #endif /* OBJ_XCOFF */
 
-/* See whether a symbol is in the TOC section.  */
+#ifdef OBJ_ELF
+/* If this function returns non-zero, it guarantees that a relocation
+   will be emitted for a fixup.  */
 
-static int
-ppc_is_toc_sym (sym)
-     symbolS *sym;
+int
+ppc_force_relocation (fix)
+     fixS *fix;
 {
-#ifdef OBJ_XCOFF
-  return symbol_get_tc (sym)->class == XMC_TC;
-#else
-  return strcmp (segment_name (S_GET_SEGMENT (sym)), ".got") == 0;
-#endif
+  /* 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;
+{
+  return (fix->fx_r_type != BFD_RELOC_16_GOTOFF
+         && 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_GPREL16
+         && fix->fx_r_type != BFD_RELOC_VTABLE_INHERIT
+         && fix->fx_r_type != BFD_RELOC_VTABLE_ENTRY
+         && !(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)
+                     == S_GET_SEGMENT (fix->fx_addsy)))
+             || S_IS_LOCAL (fix->fx_addsy)));
+}
+#endif
+
 /* Apply a fixup to the object code.  This is called for all the
    fixups we generated by the call to fix_new_exp, above.  In the call
    above we used a reloc code which was the largest legal reloc code
@@ -4656,197 +5496,215 @@ ppc_is_toc_sym (sym)
    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;
-     segT seg;
+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)
-    {
-      /* `*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;
-    }
-  else
+  if (fixP->fx_addsy != NULL)
     {
-      fixp->fx_done = 1;
+      /* 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;
 #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];
 
 #ifdef OBJ_XCOFF
-      /* It appears that an instruction like
-            l 9,LC..1(30)
-        when LC..1 is not a TOC symbol does not generate a reloc.  It
-        uses the offset of LC..1 within its csect.  However, .long
-        LC..1 will generate a reloc.  I can't find any documentation
-        on how these cases are to be distinguished, so this is a wild
-        guess.  These cases are generated by gcc -mminimal-toc.  */
+      /* An instruction like `lwz 9,sym(30)' when `sym' is not a TOC symbol
+        does not generate a reloc.  It uses the offset of `sym' within its
+        csect.  Other usages, such as `.long sym', generate relocs.  This
+        is the documented behaviour of non-TOC symbols.  */
       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);
 
       /* Determine a BFD reloc value based on the operand information.
         We are only prepared to turn a few of the operands into
-        relocs.
-        FIXME: We need to handle the DS field at the very least.
-        FIXME: Selecting the reloc type is a bit haphazard; perhaps
-        there should be a new field in the operand table.  */
+        relocs.  */
       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
-              && operand->insert == NULL
-              && fixp->fx_addsy != NULL
-              && ppc_is_toc_sym (fixp->fx_addsy))
+              && operand->shift == 0)
        {
-         fixp->fx_size = 2;
+         if (ppc_is_toc_sym (fixP->fx_addsy))
+           {
+             fixP->fx_r_type = BFD_RELOC_PPC_TOC16;
+#ifdef OBJ_ELF
+             if (ppc_obj64
+                 && (operand->flags & PPC_OPERAND_DS) != 0)
+               fixP->fx_r_type = BFD_RELOC_PPC64_TOC16_DS;
+#endif
+           }
+         else
+           {
+             fixP->fx_r_type = BFD_RELOC_16;
+#ifdef OBJ_ELF
+             if (ppc_obj64
+                 && (operand->flags & PPC_OPERAND_DS) != 0)
+               fixP->fx_r_type = BFD_RELOC_PPC64_ADDR16_DS;
+#endif
+           }
+         fixP->fx_size = 2;
          if (target_big_endian)
-           fixp->fx_where += 2;
-         fixp->fx_r_type = BFD_RELOC_PPC_TOC16;
+           fixP->fx_where += 2;
        }
+#endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */
       else
        {
          char *sfile;
          unsigned int sline;
 
          /* Use expr_symbol_where to see if this is an expression
-             symbol.  */
-         if (expr_symbol_where (fixp->fx_addsy, &sfile, &sline))
-           as_bad_where (fixp->fx_file, fixp->fx_line,
+            symbol.  */
+         if (expr_symbol_where (fixP->fx_addsy, &sfile, &sline))
+           as_bad_where (fixP->fx_file, fixP->fx_line,
                          _("unresolved expression that must be resolved"));
          else
-           as_bad_where (fixp->fx_file, fixp->fx_line,
-                         _("unsupported relocation type"));
-         fixp->fx_done = 1;
-         return 1;
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         _("unsupported relocation against %s"),
+                         S_GET_NAME (fixP->fx_addsy));
+         fixP->fx_done = 1;
+         return;
        }
     }
   else
     {
 #ifdef OBJ_ELF
-      ppc_elf_validate_fix (fixp, seg);
+      ppc_elf_validate_fix (fixP, seg);
 #endif
-      switch (fixp->fx_r_type)
+      switch (fixP->fx_r_type)
        {
-       case BFD_RELOC_32:
        case BFD_RELOC_CTOR:
-         if (fixp->fx_pcrel)
-           fixp->fx_r_type = BFD_RELOC_32_PCREL;
-                                       /* fall through */
+         if (ppc_obj64)
+           goto ctor64;
+         /* fall through */
+
+       case BFD_RELOC_32:
+         if (fixP->fx_pcrel)
+           fixP->fx_r_type = BFD_RELOC_32_PCREL;
+         /* fall through */
 
        case BFD_RELOC_RVA:
        case BFD_RELOC_32_PCREL:
-       case BFD_RELOC_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;
+         /* fall through */
+
+       case BFD_RELOC_64_PCREL:
+         md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+                             value, 8);
+         break;
+
        case BFD_RELOC_LO16:
        case BFD_RELOC_16:
        case BFD_RELOC_GPREL16:
@@ -4855,6 +5713,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:
@@ -4871,20 +5730,25 @@ md_apply_fix3 (fixp, valuep, seg)
        case BFD_RELOC_PPC_EMB_RELST_HA:
        case BFD_RELOC_PPC_EMB_RELSDA:
        case BFD_RELOC_PPC_TOC16:
-         if (fixp->fx_pcrel)
+#ifdef OBJ_ELF
+       case BFD_RELOC_PPC64_TOC16_LO:
+       case BFD_RELOC_PPC64_TOC16_HI:
+       case BFD_RELOC_PPC64_TOC16_HA:
+#endif
+         if (fixP->fx_pcrel)
            {
-             if (fixp->fx_addsy != NULL)
-               as_bad_where (fixp->fx_file, fixp->fx_line,
+             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;
 
@@ -4892,116 +5756,242 @@ 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,
-                             value >> 16, 2);
+         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,
-                             (value + 0x8000) >> 16, 2);
+         md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+                             PPC_HA (value), 2);
          break;
 
-         /* 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)
+#ifdef OBJ_ELF
+       case BFD_RELOC_PPC64_HIGHER:
+         if (fixP->fx_pcrel)
            abort ();
-
-         md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where
-                             + ((target_big_endian) ? 2 : 0),
-                             value, 2);
+         md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+                             PPC_HIGHER (value), 2);
          break;
 
-       case BFD_RELOC_8:
-         if (fixp->fx_pcrel)
+       case BFD_RELOC_PPC64_HIGHER_S:
+         if (fixP->fx_pcrel)
            abort ();
+         md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+                             PPC_HIGHERA (value), 2);
+         break;
 
-         md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
-                             value, 1);
+       case BFD_RELOC_PPC64_HIGHEST:
+         if (fixP->fx_pcrel)
+           abort ();
+         md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+                             PPC_HIGHEST (value), 2);
          break;
 
-       case BFD_RELOC_24_PLT_PCREL:
-       case BFD_RELOC_PPC_LOCAL24PC:
-         if (!fixp->fx_pcrel && !fixp->fx_done)
+       case BFD_RELOC_PPC64_HIGHEST_S:
+         if (fixP->fx_pcrel)
            abort ();
+         md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+                             PPC_HIGHESTA (value), 2);
+         break;
 
-         if (fixp->fx_done)
+       case BFD_RELOC_PPC64_ADDR16_DS:
+       case BFD_RELOC_PPC64_ADDR16_LO_DS:
+       case BFD_RELOC_PPC64_GOT16_DS:
+       case BFD_RELOC_PPC64_GOT16_LO_DS:
+       case BFD_RELOC_PPC64_PLT16_LO_DS:
+       case BFD_RELOC_PPC64_SECTOFF_DS:
+       case BFD_RELOC_PPC64_SECTOFF_LO_DS:
+       case BFD_RELOC_PPC64_TOC16_DS:
+       case BFD_RELOC_PPC64_TOC16_LO_DS:
+       case BFD_RELOC_PPC64_PLTGOT16_DS:
+       case BFD_RELOC_PPC64_PLTGOT16_LO_DS:
+         if (fixP->fx_pcrel)
+           abort ();
          {
-           char *where;
-           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;
+           unsigned char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
+           unsigned long val, mask;
+
            if (target_big_endian)
-             insn = bfd_getb32 ((unsigned char *) where);
+             val = bfd_getb32 (where - 2);
            else
-             insn = bfd_getl32 ((unsigned char *) where);
-           if ((value & 3) != 0)
-             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,
-                           _("@local or @plt branch destination is too far away, %ld bytes"),
-                           value);
-           insn = insn | (value & 0x03fffffc);
+             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_putb32 ((bfd_vma) insn, (unsigned char *) where);
+             bfd_putb16 ((bfd_vma) val, where);
            else
-             bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
+             bfd_putl16 ((bfd_vma) val, where);
          }
          break;
 
+       case BFD_RELOC_PPC_B16_BRTAKEN:
+       case BFD_RELOC_PPC_B16_BRNTAKEN:
+       case BFD_RELOC_PPC_BA16_BRTAKEN:
+       case BFD_RELOC_PPC_BA16_BRNTAKEN:
+         break;
+
+       case BFD_RELOC_PPC_TLS:
+       case BFD_RELOC_PPC_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)
+           abort ();
+
+         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)
+           {
+             /* This can occur if there is a bug in the input assembler, eg:
+                ".byte <undefined_symbol> - ."  */
+             if (fixP->fx_addsy)
+               as_bad (_("Unable to handle reference to symbol %s"),
+                       S_GET_NAME (fixP->fx_addsy));
+             else
+               as_bad (_("Unable to resolve expression"));
+             fixP->fx_done = 1;
+           }
+         else
+           md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+                               value, 1);
+         break;
+
+       case BFD_RELOC_24_PLT_PCREL:
+       case BFD_RELOC_PPC_LOCAL24PC:
+         if (!fixP->fx_pcrel && !fixP->fx_done)
+           abort ();
+
+         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;
+             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,
+                             _("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,
+                             _("@local or @plt branch destination is too far away, %ld bytes"),
+                             (long) value);
+             insn = insn | (value & 0x03fffffc);
+             if (target_big_endian)
+               bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
+             else
+               bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
+           }
+         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
+         /* Generated by reference to `sym@tocbase'.  The sym is
+            ignored by the linker.  */
+       case BFD_RELOC_PPC64_TOC:
+         fixP->fx_done = 0;
+         break;
+#endif
        default:
-         fprintf(stderr,
-                 _("Gas failure, reloc value %d\n"), fixp->fx_r_type);
-         fflush(stderr);
+         fprintf (stderr,
+                  _("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.  */
 
 arelent *
 tc_gen_reloc (seg, fixp)
-     asection *seg;
+     asection *seg ATTRIBUTE_UNUSED;
      fixS *fixp;
 {
   arelent *reloc;
@@ -5015,10 +6005,57 @@ tc_gen_reloc (seg, fixp)
   if (reloc->howto == (reloc_howto_type *) NULL)
     {
       as_bad_where (fixp->fx_file, fixp->fx_line,
-                   _("reloc %d not supported by object file format"), (int)fixp->fx_r_type);
+                   _("reloc %d not supported by object file format"),
+                   (int) fixp->fx_r_type);
       return NULL;
     }
   reloc->addend = fixp->fx_addnumber;
 
   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.085745 seconds and 4 git commands to generate.