Add CRX insns: pushx, popx
[deliverable/binutils-gdb.git] / gas / config / tc-ppc.c
index 8f89c77ff0c7fd935eae01e357562c5e352d9a52..7bc70113ff940913f09eaf995d3ee7e84d4bc250 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-ppc.c -- Assemble for the PowerPC or POWER (RS/6000)
-   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
-   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.
@@ -24,7 +24,7 @@
 #include "as.h"
 #include "safe-ctype.h"
 #include "subsegs.h"
-
+#include "dw2gencfi.h"
 #include "opcode/ppc.h"
 
 #ifdef OBJ_ELF
@@ -47,9 +47,9 @@ static int set_target_endian = 0;
 /* Whether to use user friendly register names.  */
 #ifndef TARGET_REG_NAMES_P
 #ifdef TE_PE
-#define TARGET_REG_NAMES_P true
+#define TARGET_REG_NAMES_P TRUE
 #else
-#define TARGET_REG_NAMES_P false
+#define TARGET_REG_NAMES_P FALSE
 #endif
 #endif
 
@@ -83,9 +83,9 @@ static int set_target_endian = 0;
 
 #define SEX16(val) ((((val) & 0xffff) ^ 0x8000) - 0x8000)
 
-static boolean reg_names_p = TARGET_REG_NAMES_P;
+static bfd_boolean reg_names_p = TARGET_REG_NAMES_P;
 
-static boolean register_name PARAMS ((expressionS *));
+static bfd_boolean register_name PARAMS ((expressionS *));
 static void ppc_set_cpu PARAMS ((void));
 static unsigned long ppc_insert_operand
   PARAMS ((unsigned long insn, const struct powerpc_operand *operand,
@@ -111,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));
@@ -182,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.  */
 
@@ -233,8 +240,6 @@ const pseudo_typeS md_pseudo_table[] =
   { "rdata",   ppc_elf_rdata,  0 },
   { "rodata",  ppc_elf_rdata,  0 },
   { "lcomm",   ppc_elf_lcomm,  0 },
-  { "file",    (void (*) PARAMS ((int))) dwarf2_directive_file, 0 },
-  { "loc",     dwarf2_directive_loc, 0 },
 #endif
 
 #ifdef TE_PE
@@ -603,7 +608,7 @@ reg_name_search (regs, regcount, name)
  *      original state.
  */
 
-static boolean
+static bfd_boolean
 register_name (expressionP)
      expressionS *expressionP;
 {
@@ -618,7 +623,7 @@ register_name (expressionP)
     name = ++input_line_pointer;
 
   else if (!reg_names_p || !ISALPHA (name[0]))
-    return false;
+    return FALSE;
 
   c = get_symbol_end ();
   reg_number = reg_name_search (pre_defined_registers, REG_NAME_CNT, name);
@@ -635,12 +640,12 @@ register_name (expressionP)
       /* Make the rest nice.  */
       expressionP->X_add_symbol = NULL;
       expressionP->X_op_symbol = NULL;
-      return true;
+      return TRUE;
     }
 
   /* Reset the line as if we had not done anything.  */
   input_line_pointer = start;
-  return false;
+  return FALSE;
 }
 \f
 /* This function is called for each symbol seen in an expression.  It
@@ -648,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[] =
@@ -716,12 +721,12 @@ static flagword ppc_flags = 0;
 
 /* Whether this is Solaris or not.  */
 #ifdef TARGET_SOLARIS_COMMENT
-#define SOLARIS_P true
+#define SOLARIS_P TRUE
 #else
-#define SOLARIS_P false
+#define SOLARIS_P FALSE
 #endif
 
-static boolean msolaris = SOLARIS_P;
+static bfd_boolean msolaris = SOLARIS_P;
 #endif
 
 #ifdef OBJ_XCOFF
@@ -796,8 +801,8 @@ symbolS *GOT_symbol;                /* Pre-defined "_GLOBAL_OFFSET_TABLE" */
 #define PPC_APUINFO_EFS                0x101
 #define PPC_APUINFO_BRLOCK     0x102
 
-/* 
- * We keep a list of APUinfo 
+/*
+ * We keep a list of APUinfo
  */
 unsigned long *ppc_apuinfo_list;
 unsigned int ppc_apuinfo_num;
@@ -814,6 +819,107 @@ const struct option 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)
      int c;
@@ -881,97 +987,14 @@ md_parse_option (c, arg)
       break;
 
     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 | 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, "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 | PPC_OPCODE_32;
+      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
@@ -1008,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
@@ -1059,36 +1082,41 @@ md_show_usage (stream)
 {
   fprintf (stream, _("\
 PowerPC options:\n\
+-a32                   generate ELF32/XCOFF32\n\
+-a64                   generate ELF64/XCOFF64\n\
 -u                     ignored\n\
 -mpwrx, -mpwr2         generate code for 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\
+-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\
+                       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\
--maltivec              generate code for AltiVec\n\
 -mcom                  generate code Power/PowerPC common instructions\n\
--many                  generate code for any architecture (PWR/PWRX/PPC)\n\
--mregnames             Allow symbolic names for registers\n\
--mno-regnames          Do not allow symbolic names for registers\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"));
+-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, _("\
 -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\
@@ -1104,24 +1132,24 @@ ppc_set_cpu ()
   const char *default_os  = TARGET_OS;
   const char *default_cpu = TARGET_CPU;
 
-  if (ppc_cpu == 0)
+  if ((ppc_cpu & ~PPC_OPCODE_ANY) == 0)
     {
       if (ppc_obj64)
-       ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64;
+       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;
+       ppc_cpu |= PPC_OPCODE_COMMON | PPC_OPCODE_32;
       else if (strncmp (default_os, "aix3", 4) == 0)
-       ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_32;
+       ppc_cpu |= PPC_OPCODE_POWER | PPC_OPCODE_32;
       else if (strcmp (default_cpu, "rs6000") == 0)
-       ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_32;
+       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;
-        }
+       {
+         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);
@@ -1186,26 +1214,22 @@ ppc_target_format ()
 #endif
 }
 
-/* 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.  */
+/* Insert opcodes and macros into hash tables.  Called at startup and
+   for .cpu pseudo.  */
 
-void
-md_begin ()
+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;
-
-  ppc_set_cpu ();
+  bfd_boolean dup_insn = FALSE;
 
-#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 ();
@@ -1235,7 +1259,7 @@ md_begin ()
          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.  */
              if ((ppc_cpu & PPC_OPCODE_601) != 0
@@ -1244,11 +1268,15 @@ md_begin ()
 
              as_bad (_("Internal assembler error for instruction %s"),
                      op->name);
-             dup_insn = true;
+             dup_insn = TRUE;
            }
        }
     }
 
+  if ((ppc_cpu & PPC_OPCODE_ANY) != 0)
+    for (op = powerpc_opcodes; op < op_end; op++)
+      hash_insert (ppc_hash, op->name, (PTR) op);
+
   /* Insert the macros into a hash table.  */
   ppc_macro_hash = hash_new ();
 
@@ -1263,15 +1291,35 @@ 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 ();
+}
+
+/* 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 ();
 
-  /* Tell the main code what the endianness is if it is not overidden
+  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)
     {
@@ -1323,19 +1371,19 @@ ppc_cleanup ()
     asection *seg = now_seg;
     subsegT subseg = now_subseg;
     asection *apuinfo_secp = (asection *) NULL;
-    int i;
+    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 | SEC_MERGE);
+                          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);
+    md_number_to_chars (p, (valueT) ppc_apuinfo_num * 4, 4);
 
     p = frag_more (4);
     md_number_to_chars (p, (valueT) 2, 4);
@@ -1345,8 +1393,8 @@ ppc_cleanup ()
 
     for (i = 0; i < ppc_apuinfo_num; i++)
       {
-        p = frag_more (4);
-        md_number_to_chars (p, (valueT) ppc_apuinfo_list[i], 4);
+       p = frag_more (4);
+       md_number_to_chars (p, (valueT) ppc_apuinfo_list[i], 4);
       }
 
     frag_align (2, 0, 0);
@@ -1409,14 +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);
-         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)
@@ -1445,8 +1486,10 @@ ppc_elf_suffix (str_p, exp_p)
 {
   struct map_bfd {
     char *string;
-    int length;
-    int reloc;
+    unsigned int length : 8;
+    unsigned int valid32 : 1;
+    unsigned int valid64 : 1;
+    unsigned int reloc;
   };
 
   char ident[20];
@@ -1456,63 +1499,97 @@ ppc_elf_suffix (str_p, exp_p)
   int len;
   const struct map_bfd *ptr;
 
-#define MAP(str,reloc) { str, sizeof (str)-1, reloc }
+#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",          (int) BFD_RELOC_LO16),
-    MAP ("h",          (int) BFD_RELOC_HI16),
-    MAP ("ha",         (int) BFD_RELOC_HI16_S),
-    MAP ("brtaken",    (int) BFD_RELOC_PPC_B16_BRTAKEN),
-    MAP ("brntaken",   (int) BFD_RELOC_PPC_B16_BRNTAKEN),
-    MAP ("got",                (int) BFD_RELOC_16_GOTOFF),
-    MAP ("got@l",      (int) BFD_RELOC_LO16_GOTOFF),
-    MAP ("got@h",      (int) BFD_RELOC_HI16_GOTOFF),
-    MAP ("got@ha",     (int) BFD_RELOC_HI16_S_GOTOFF),
-    MAP ("fixup",      (int) BFD_RELOC_CTOR), /* warning with -mrelocatable */
-    MAP ("plt",                (int) BFD_RELOC_24_PLT_PCREL),
-    MAP ("pltrel24",   (int) BFD_RELOC_24_PLT_PCREL),
-    MAP ("copy",       (int) BFD_RELOC_PPC_COPY),
-    MAP ("globdat",    (int) BFD_RELOC_PPC_GLOB_DAT),
-    MAP ("local24pc",  (int) BFD_RELOC_PPC_LOCAL24PC),
-    MAP ("local",      (int) BFD_RELOC_PPC_LOCAL24PC),
-    MAP ("pltrel",     (int) BFD_RELOC_32_PLT_PCREL),
-    MAP ("plt@l",      (int) BFD_RELOC_LO16_PLTOFF),
-    MAP ("plt@h",      (int) BFD_RELOC_HI16_PLTOFF),
-    MAP ("plt@ha",     (int) BFD_RELOC_HI16_S_PLTOFF),
-    MAP ("sdarel",     (int) BFD_RELOC_GPREL16),
-    MAP ("sectoff",    (int) BFD_RELOC_16_BASEREL),
-    MAP ("sectoff@l",  (int) BFD_RELOC_LO16_BASEREL),
-    MAP ("sectoff@h",  (int) BFD_RELOC_HI16_BASEREL),
-    MAP ("sectoff@ha", (int) BFD_RELOC_HI16_S_BASEREL),
-    MAP ("naddr",      (int) BFD_RELOC_PPC_EMB_NADDR32),
-    MAP ("naddr16",    (int) BFD_RELOC_PPC_EMB_NADDR16),
-    MAP ("naddr@l",    (int) BFD_RELOC_PPC_EMB_NADDR16_LO),
-    MAP ("naddr@h",    (int) BFD_RELOC_PPC_EMB_NADDR16_HI),
-    MAP ("naddr@ha",   (int) BFD_RELOC_PPC_EMB_NADDR16_HA),
-    MAP ("sdai16",     (int) BFD_RELOC_PPC_EMB_SDAI16),
-    MAP ("sda2rel",    (int) BFD_RELOC_PPC_EMB_SDA2REL),
-    MAP ("sda2i16",    (int) BFD_RELOC_PPC_EMB_SDA2I16),
-    MAP ("sda21",      (int) BFD_RELOC_PPC_EMB_SDA21),
-    MAP ("mrkref",     (int) BFD_RELOC_PPC_EMB_MRKREF),
-    MAP ("relsect",    (int) BFD_RELOC_PPC_EMB_RELSEC16),
-    MAP ("relsect@l",  (int) BFD_RELOC_PPC_EMB_RELST_LO),
-    MAP ("relsect@h",  (int) BFD_RELOC_PPC_EMB_RELST_HI),
-    MAP ("relsect@ha", (int) BFD_RELOC_PPC_EMB_RELST_HA),
-    MAP ("bitfld",     (int) BFD_RELOC_PPC_EMB_BIT_FLD),
-    MAP ("relsda",     (int) BFD_RELOC_PPC_EMB_RELSDA),
-    MAP ("xgot",       (int) BFD_RELOC_PPC_TOC16),
-    /* The following are only valid for ppc64.  Negative values are
-       used instead of a flag.  */
-    MAP ("higher",     - (int) BFD_RELOC_PPC64_HIGHER),
-    MAP ("highera",    - (int) BFD_RELOC_PPC64_HIGHER_S),
-    MAP ("highest",    - (int) BFD_RELOC_PPC64_HIGHEST),
-    MAP ("highesta",   - (int) BFD_RELOC_PPC64_HIGHEST_S),
-    MAP ("tocbase",    - (int) BFD_RELOC_PPC64_TOC),
-    MAP ("toc",                - (int) BFD_RELOC_PPC_TOC16),
-    MAP ("toc@l",      - (int) BFD_RELOC_PPC64_TOC16_LO),
-    MAP ("toc@h",      - (int) BFD_RELOC_PPC64_TOC16_HI),
-    MAP ("toc@ha",     - (int) BFD_RELOC_PPC64_TOC16_HA),
-    { (char *) 0, 0,   (int) BFD_RELOC_UNUSED }
+    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++ != '@')
@@ -1533,23 +1610,18 @@ 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))
       {
        int reloc = ptr->reloc;
 
-       if (reloc < 0)
-         {
-           if (!ppc_obj64)
-             return BFD_RELOC_UNUSED;
-           reloc = -reloc;
-         }
-
-       if (exp_p->X_add_number != 0
-           && (reloc == (int) BFD_RELOC_16_GOTOFF
-               || reloc == (int) BFD_RELOC_LO16_GOTOFF
-               || reloc == (int) BFD_RELOC_HI16_GOTOFF
-               || reloc == (int) BFD_RELOC_HI16_S_GOTOFF))
-         as_warn (_("identifier+constant@got means identifier@got+constant"));
+       if (!ppc_obj64)
+         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 == '+')
@@ -1571,11 +1643,11 @@ ppc_elf_suffix (str_p, exp_p)
        *str_p = str;
 
        if (reloc == (int) BFD_RELOC_PPC64_TOC
-           && exp_p->X_op == O_symbol)
+           && exp_p->X_op == O_symbol
+           && strcmp (S_GET_NAME (exp_p->X_add_symbol), ".TOC.") == 0)
          {
-           /* This reloc type ignores the symbol.  Change the symbol
-              so that the dummy .TOC. symbol can be omitted from the
-              object file.  */
+           /* Change the symbol so that the dummy .TOC. symbol can be
+              omitted from the object file.  */
            exp_p->X_add_symbol = &abs_symbol;
          }
 
@@ -1846,9 +1918,8 @@ ppc_frob_file_before_adjust ()
       free (dotname);
       if (dotsym != NULL && (symbol_used_p (dotsym)
                             || symbol_used_in_reloc_p (dotsym)))
-       {
-         symbol_mark_used (symp);
-       }
+       symbol_mark_used (symp);
+
     }
 
   /* Don't emit .TOC. symbol.  */
@@ -1968,7 +2039,7 @@ ppc_apuinfo_section_add (apu, version)
   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)
@@ -2019,6 +2090,7 @@ 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;
@@ -2053,13 +2125,14 @@ md_assemble (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++)
     {
@@ -2095,7 +2168,7 @@ md_assemble (str)
 
          /* If there are fewer operands in the line then are called
             for by the instruction, we want to skip the optional
-            operand.  */
+            operands.  */
          if (opcount < num_operands_expected)
            skip_optional = 1;
 
@@ -2272,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;
            }
        }
 
@@ -2362,6 +2435,25 @@ md_assemble (str)
 #ifdef OBJ_ELF
       else if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
        {
+         /* Some TLS tweaks.  */
+         switch (reloc)
+           {
+           default:
+             break;
+           case BFD_RELOC_PPC_TLS:
+             insn = ppc_insert_operand (insn, operand, ppc_obj64 ? 13 : 2,
+                                        (char *) NULL, 0);
+             break;
+         /* We'll only use the 32 (or 64) bit form of these relocations
+            in constants.  Instructions get the 16 bit form.  */
+           case BFD_RELOC_PPC_DTPREL:
+             reloc = BFD_RELOC_PPC_DTPREL16;
+             break;
+           case BFD_RELOC_PPC_TPREL:
+             reloc = BFD_RELOC_PPC_TPREL16;
+             break;
+           }
+
          /* For the absolute forms of branches, convert the PC
             relative form back into the absolute.  */
          if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
@@ -2386,7 +2478,7 @@ md_assemble (str)
            }
 
          if (ppc_obj64
-             && (operand->flags & PPC_OPERAND_DS) != 0)
+             && (operand->flags & (PPC_OPERAND_DS | PPC_OPERAND_DQ)) != 0)
            {
              switch (reloc)
                {
@@ -2423,6 +2515,23 @@ md_assemble (str)
                case BFD_RELOC_PPC64_PLTGOT16_LO:
                  reloc = BFD_RELOC_PPC64_PLTGOT16_LO_DS;
                  break;
+               case BFD_RELOC_PPC_DTPREL16:
+                 reloc = BFD_RELOC_PPC64_DTPREL16_DS;
+                 break;
+               case BFD_RELOC_PPC_DTPREL16_LO:
+                 reloc = BFD_RELOC_PPC64_DTPREL16_LO_DS;
+                 break;
+               case BFD_RELOC_PPC_TPREL16:
+                 reloc = BFD_RELOC_PPC64_TPREL16_DS;
+                 break;
+               case BFD_RELOC_PPC_TPREL16_LO:
+                 reloc = BFD_RELOC_PPC64_TPREL16_LO_DS;
+                 break;
+               case BFD_RELOC_PPC_GOT_DTPREL16:
+               case BFD_RELOC_PPC_GOT_DTPREL16_LO:
+               case BFD_RELOC_PPC_GOT_TPREL16:
+               case BFD_RELOC_PPC_GOT_TPREL16_LO:
+                 break;
                default:
                  as_bad (_("unsupported relocation for DS offset field"));
                  break;
@@ -2491,24 +2600,29 @@ md_assemble (str)
     {
       /* These are all version "1".  */
       if (opcode->flags & PPC_OPCODE_SPE)
-        ppc_apuinfo_section_add (PPC_APUINFO_SPE, 1);
+       ppc_apuinfo_section_add (PPC_APUINFO_SPE, 1);
       if (opcode->flags & PPC_OPCODE_ISEL)
-        ppc_apuinfo_section_add (PPC_APUINFO_ISEL, 1);
+       ppc_apuinfo_section_add (PPC_APUINFO_ISEL, 1);
       if (opcode->flags & PPC_OPCODE_EFS)
-        ppc_apuinfo_section_add (PPC_APUINFO_EFS, 1);
+       ppc_apuinfo_section_add (PPC_APUINFO_EFS, 1);
       if (opcode->flags & PPC_OPCODE_BRLOCK)
-        ppc_apuinfo_section_add (PPC_APUINFO_BRLOCK, 1);
+       ppc_apuinfo_section_add (PPC_APUINFO_BRLOCK, 1);
       if (opcode->flags & PPC_OPCODE_PMR)
-        ppc_apuinfo_section_add (PPC_APUINFO_PMR, 1);
+       ppc_apuinfo_section_add (PPC_APUINFO_PMR, 1);
       if (opcode->flags & PPC_OPCODE_CACHELCK)
-        ppc_apuinfo_section_add (PPC_APUINFO_CACHELCK, 1);
+       ppc_apuinfo_section_add (PPC_APUINFO_CACHELCK, 1);
       if (opcode->flags & PPC_OPCODE_RFMCI)
-        ppc_apuinfo_section_add (PPC_APUINFO_RFMCI, 1);
+       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
@@ -2674,7 +2788,7 @@ ppc_section_letter (letter, ptr_msg)
     return SHF_EXCLUDE;
 
   *ptr_msg = _("Bad .section directive: want a,e,w,x,M,S,G,T in string");
-  return 0;
+  return -1;
 }
 
 int
@@ -2759,11 +2873,11 @@ 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.  The native Aix 4.3.3 assember
+   symbols, and uses a different smclas.  The native Aix 4.3.3 assembler
    aligns .comm and .lcomm to 4 bytes.  */
 
 static void
@@ -2928,6 +3042,7 @@ ppc_csect (ignore)
   char *name;
   char endc;
   symbolS *sym;
+  offsetT align;
 
   name = input_line_pointer;
   endc = get_symbol_end ();
@@ -2942,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);
@@ -2967,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:
@@ -2986,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:
@@ -3013,18 +3134,24 @@ ppc_change_csect (sym)
       hold_chunksize = chunksize;
       chunksize = 64;
 
-      subseg_new (segment_name (S_GET_SEGMENT (sym)),
-                 symbol_get_tc (sym)->subseg);
+      sec = subseg_new (segment_name (S_GET_SEGMENT (sym)),
+                       symbol_get_tc (sym)->subseg);
 
       chunksize = hold_chunksize;
 
       if (after_toc)
        ppc_after_toc_frag = frag_now;
 
+      record_alignment (sec, align);
+      if (is_code)
+       frag_align_code (align, 0);
+      else
+       frag_align (align, 0, 0);
+
       symbol_set_frag (sym, frag_now);
       S_SET_VALUE (sym, (valueT) frag_now_fix ());
 
-      symbol_get_tc (sym)->align = 2;
+      symbol_get_tc (sym)->align = align;
       symbol_get_tc (sym)->output = 1;
       symbol_get_tc (sym)->within = sym;
 
@@ -3062,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 ();
 }
@@ -3099,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 ();
 }
@@ -3202,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;
 
@@ -3305,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
@@ -3770,7 +3897,7 @@ ppc_vbyte (dummy)
    give to this location in the toc; this will be a symbol with class
    TC.  The rest of the arguments are N-byte values to actually put at
    this location in the TOC; often there is just one more argument, a
-   relocateable symbol reference.  The size of the value to store
+   relocatable symbol reference.  The size of the value to store
    depends on target word size.  A 32-bit target uses 4-byte values, a
    64-bit target uses 8-byte values.
 
@@ -3863,18 +3990,67 @@ ppc_tc (ignore)
 }
 
 /* Pseudo-op .machine.  */
-/* FIXME: `.machine' is a nop for the moment.  It would be nice to
-   accept this directive on the first line of input and set ppc_obj64
-   and the target format accordingly.  Unfortunately, the target
-   format is selected in output-file.c:output_file_create before we
-   even get to md_begin, so it's not possible without changing
-   as.c:main.  */
 
 static void
 ppc_machine (ignore)
      int ignore ATTRIBUTE_UNUSED;
 {
-  discard_rest_of_line ();
+  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.  */
@@ -3933,11 +4109,11 @@ ppc_previous (ignore)
 
 /* pseudo-op: .pdata
    behaviour: predefined read only data section
-              double word aligned
+             double word aligned
    errors:    None
    warnings:  None
    initial:   .section .pdata "adr3"
-              a - don't know -- maybe a misprint
+             a - don't know -- maybe a misprint
              d - initialized data
              r - readable
              3 - double word aligned (that would be 4 byte boundary)
@@ -3969,11 +4145,11 @@ ppc_pdata (ignore)
 
 /* pseudo-op: .ydata
    behaviour: predefined read only data section
-              double word aligned
+             double word aligned
    errors:    None
    warnings:  None
    initial:   .section .ydata "drw3"
-              a - don't know -- maybe a misprint
+             a - don't know -- maybe a misprint
              d - initialized data
              r - readable
              3 - double word aligned (that would be 4 byte boundary)
@@ -4003,7 +4179,7 @@ ppc_ydata (ignore)
 
 /* pseudo-op: .reldata
    behaviour: predefined read write data section
-              double word aligned (4-byte)
+             double word aligned (4-byte)
              FIXME: relocation is applied to it
              FIXME: what's the difference between this and .data?
    errors:    None
@@ -4041,7 +4217,7 @@ ppc_reldata (ignore)
 
 /* pseudo-op: .rdata
    behaviour: predefined read only data section
-              double word aligned
+             double word aligned
    errors:    None
    warnings:  None
    initial:   .section .rdata "dr3"
@@ -4071,7 +4247,7 @@ ppc_rdata (ignore)
 
 /* pseudo-op: .ualong
    behaviour: much like .int, with the exception that no alignment is
-              performed.
+             performed.
              FIXME: test the alignment statement
    errors:    None
    warnings:  None  */
@@ -4086,7 +4262,7 @@ ppc_ualong (ignore)
 
 /* pseudo-op: .znop  <symbol name>
    behaviour: Issue a nop instruction
-              Issue a IMAGE_REL_PPC_IFGLUE relocation against it, using
+             Issue a IMAGE_REL_PPC_IFGLUE relocation against it, using
              the supplied symbol name.
    errors:    None
    warnings:  Missing symbol name  */
@@ -4648,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
@@ -4666,7 +4842,7 @@ 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;
@@ -4732,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
@@ -4791,7 +4967,7 @@ ppc_frob_symbol (sym)
        {
          /* This is an absolute symbol.  The csect will be created by
             ppc_adjust_symtab.  */
-         ppc_saw_abs = true;
+         ppc_saw_abs = TRUE;
          a->x_csect.x_smtyp = XTY_LD;
          if (symbol_get_tc (sym)->class == -1)
            symbol_get_tc (sym)->class = XMC_XO;
@@ -4959,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
@@ -4969,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);
 }
@@ -5255,7 +5432,7 @@ ppc_force_relocation (fix)
                  <= fix->fx_frag->fr_address))))
     return 1;
 
-  return S_FORCE_RELOC (fix->fx_addsy);
+  return generic_force_reloc (fix);
 }
 
 #endif /* OBJ_XCOFF */
@@ -5277,14 +5454,16 @@ ppc_force_relocation (fix)
     case BFD_RELOC_PPC_BA16_BRTAKEN:
     case BFD_RELOC_PPC_BA16_BRNTAKEN:
     case BFD_RELOC_PPC64_TOC:
-    case BFD_RELOC_VTABLE_INHERIT:
-    case BFD_RELOC_VTABLE_ENTRY:
       return 1;
     default:
       break;
     }
 
-  return S_FORCE_RELOC (fix->fx_addsy);
+  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
@@ -5298,6 +5477,8 @@ ppc_fix_adjustable (fix)
          && fix->fx_r_type != BFD_RELOC_GPREL16
          && fix->fx_r_type != BFD_RELOC_VTABLE_INHERIT
          && fix->fx_r_type != BFD_RELOC_VTABLE_ENTRY
+         && !(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)
@@ -5446,15 +5627,26 @@ md_apply_fix3 (fixP, valP, seg)
 #if defined (OBJ_XCOFF) || defined (OBJ_ELF)
       else if ((operand->flags & PPC_OPERAND_PARENS) != 0
               && operand->bits == 16
-              && operand->shift == 0
-              && ppc_is_toc_sym (fixP->fx_addsy))
+              && operand->shift == 0)
        {
-         fixP->fx_r_type = BFD_RELOC_PPC_TOC16;
+         if (ppc_is_toc_sym (fixP->fx_addsy))
+           {
+             fixP->fx_r_type = BFD_RELOC_PPC_TOC16;
 #ifdef OBJ_ELF
-         if (ppc_obj64
-             && (operand->flags & PPC_OPERAND_DS) != 0)
-           fixP->fx_r_type = BFD_RELOC_PPC64_TOC16_DS;
+             if (ppc_obj64
+                 && (operand->flags & PPC_OPERAND_DS) != 0)
+               fixP->fx_r_type = BFD_RELOC_PPC64_TOC16_DS;
+#endif
+           }
+         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;
@@ -5621,19 +5813,72 @@ md_apply_fix3 (fixP, valP, seg)
            abort ();
          {
            unsigned char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
-           unsigned long val;
+           unsigned long val, mask;
 
            if (target_big_endian)
-             val = bfd_getb16 (where);
+             val = bfd_getb32 (where - 2);
            else
-             val = bfd_getl16 (where);
-           val |= (value & 0xfffc);
+             val = bfd_getl32 (where);
+           mask = 0xfffc;
+           /* lq insns reserve the four lsbs.  */
+           if ((ppc_cpu & PPC_OPCODE_POWER4) != 0
+               && (val & (0x3f << 26)) == (56u << 26))
+             mask = 0xfff0;
+           val |= value & mask;
            if (target_big_endian)
              bfd_putb16 ((bfd_vma) val, where);
            else
              bfd_putl16 ((bfd_vma) val, where);
          }
          break;
+
+       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.  */
@@ -5648,10 +5893,19 @@ md_apply_fix3 (fixP, valP, seg)
 
        case BFD_RELOC_8:
          if (fixP->fx_pcrel)
-           abort ();
-
-         md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
-                             value, 1);
+           {
+             /* 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:
@@ -5759,3 +6013,49 @@ tc_gen_reloc (seg, fixp)
 
   return reloc;
 }
+
+void
+ppc_cfi_frame_initial_instructions ()
+{
+  cfi_add_CFA_def_cfa (1, 0);
+}
+
+int
+tc_ppc_regname_to_dw2regnum (const char *regname)
+{
+  unsigned int regnum = -1;
+  unsigned int i;
+  const char *p;
+  char *q;
+  static struct { char *name; int dw2regnum; } regnames[] =
+    {
+      { "sp", 1 }, { "r.sp", 1 }, { "rtoc", 2 }, { "r.toc", 2 },
+      { "mq", 64 }, { "lr", 65 }, { "ctr", 66 }, { "ap", 67 },
+      { "cc", 68 }, { "xer", 76 }, { "vrsave", 109 }, { "vscr", 110 },
+      { "spe_acc", 111 }, { "spefscr", 112 }
+    };
+
+  for (i = 0; i < ARRAY_SIZE (regnames); ++i)
+    if (strcmp (regnames[i].name, regname) == 0)
+      return regnames[i].dw2regnum;
+
+  if (regname[0] == 'r' || regname[0] == 'f' || regname[0] == 'v')
+    {
+      p = regname + 1 + (regname[1] == '.');
+      regnum = strtoul (p, &q, 10);
+      if (p == q || *q || regnum >= 32)
+       return -1;
+      if (regname[0] == 'f')
+       regnum += 32;
+      else if (regname[0] == 'v')
+       regnum += 77;
+    }
+  else if (regname[0] == 'c' && regname[1] == 'r')
+    {
+      p = regname + 2 + (regname[2] == '.');
+      if (p[0] < '0' || p[0] > '7' || p[1])
+       return -1;
+      regnum = p[0] - '0' + 68;
+    }
+  return regnum;
+}
This page took 0.04526 seconds and 4 git commands to generate.