* config/tc-ppc.c (md_assemble): Trim @ha constant to 16 bits, to
[deliverable/binutils-gdb.git] / gas / config / tc-ppc.c
index bda925c8e2b57c8c515dde3d9d830e60dbcd8e8b..c18a274793d94084e96f363a1d8ca8c9c476009b 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-ppc.c -- Assemble for the PowerPC or POWER (RS/6000)
 /* tc-ppc.c -- Assemble for the PowerPC or POWER (RS/6000)
-   Copyright (C) 1994 Free Software Foundation, Inc.
+   Copyright (C) 1994, 95, 96, 97, 98, 1999 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of GAS, the GNU Assembler.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of GAS, the GNU Assembler.
@@ -15,8 +15,9 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    GNU General Public License for more details.
 
    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. */
+   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. */
 
 #include <stdio.h>
 #include <ctype.h>
 
 #include <stdio.h>
 #include <ctype.h>
@@ -41,6 +42,18 @@ extern int target_big_endian;
 /* Whether or not, we've set target_big_endian.  */
 static int set_target_endian = 0;
 
 /* Whether or not, we've set target_big_endian.  */
 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
+#else
+#define TARGET_REG_NAMES_P false
+#endif
+#endif
+
+static boolean reg_names_p = TARGET_REG_NAMES_P;
+
+static 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,
 static void ppc_set_cpu PARAMS ((void));
 static unsigned long ppc_insert_operand
   PARAMS ((unsigned long insn, const struct powerpc_operand *operand,
@@ -53,24 +66,33 @@ static void ppc_tc PARAMS ((int));
 #ifdef OBJ_XCOFF
 static void ppc_comm PARAMS ((int));
 static void ppc_bb PARAMS ((int));
 #ifdef OBJ_XCOFF
 static void ppc_comm PARAMS ((int));
 static void ppc_bb PARAMS ((int));
+static void ppc_bc PARAMS ((int));
 static void ppc_bf PARAMS ((int));
 static void ppc_biei PARAMS ((int));
 static void ppc_bs PARAMS ((int));
 static void ppc_eb PARAMS ((int));
 static void ppc_bf PARAMS ((int));
 static void ppc_biei PARAMS ((int));
 static void ppc_bs PARAMS ((int));
 static void ppc_eb PARAMS ((int));
+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_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_function PARAMS ((int));
 static void ppc_extern PARAMS ((int));
 static void ppc_lglobl PARAMS ((int));
 static void ppc_function PARAMS ((int));
 static void ppc_extern PARAMS ((int));
 static void ppc_lglobl PARAMS ((int));
+static void ppc_section PARAMS ((int));
+static void ppc_named_section PARAMS ((int));
 static void ppc_stabx PARAMS ((int));
 static void ppc_rename PARAMS ((int));
 static void ppc_toc PARAMS ((int));
 static void ppc_stabx PARAMS ((int));
 static void ppc_rename PARAMS ((int));
 static void ppc_toc PARAMS ((int));
+static void ppc_xcoff_cons PARAMS ((int));
+static void ppc_vbyte PARAMS ((int));
 #endif
 
 #ifdef OBJ_ELF
 #endif
 
 #ifdef OBJ_ELF
-static bfd_reloc_code_real_type ppc_elf_suffix PARAMS ((char **));
+static bfd_reloc_code_real_type ppc_elf_suffix PARAMS ((char **, expressionS *));
 static void ppc_elf_cons PARAMS ((int));
 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));
 #endif
 
 static void ppc_elf_validate_fix PARAMS ((fixS *, segT));
 #endif
 
@@ -92,8 +114,22 @@ static void ppc_pe_tocd PARAMS ((int));
 /* Generic assembler global variables which must be defined by all
    targets.  */
 
 /* Generic assembler global variables which must be defined by all
    targets.  */
 
-/* Characters which always start a comment.  */
+#ifdef OBJ_ELF
+/* This string holds the chars that always start a comment.  If the
+   pre-processor is disabled, these aren't very useful.  The macro
+   tc_comment_chars points to this.  We use this, rather than the
+   usual comment_chars, so that we can switch for Solaris conventions.  */
+static const char ppc_solaris_comment_chars[] = "#!";
+static const char ppc_eabi_comment_chars[] = "#";
+
+#ifdef TARGET_SOLARIS_COMMENT
+const char *ppc_comment_chars = ppc_solaris_comment_chars;
+#else
+const char *ppc_comment_chars = ppc_eabi_comment_chars;
+#endif
+#else
 const char comment_chars[] = "#";
 const char comment_chars[] = "#";
+#endif
 
 /* Characters which start a comment at the beginning of a line.  */
 const char line_comment_chars[] = "#";
 
 /* Characters which start a comment at the beginning of a line.  */
 const char line_comment_chars[] = "#";
@@ -125,11 +161,14 @@ const pseudo_typeS md_pseudo_table[] =
   { "comm",    ppc_comm,       0 },
   { "lcomm",   ppc_comm,       1 },
   { "bb",      ppc_bb,         0 },
   { "comm",    ppc_comm,       0 },
   { "lcomm",   ppc_comm,       1 },
   { "bb",      ppc_bb,         0 },
+  { "bc",      ppc_bc,         0 },
   { "bf",      ppc_bf,         0 },
   { "bi",      ppc_biei,       0 },
   { "bs",      ppc_bs,         0 },
   { "csect",   ppc_csect,      0 },
   { "bf",      ppc_bf,         0 },
   { "bi",      ppc_biei,       0 },
   { "bs",      ppc_bs,         0 },
   { "csect",   ppc_csect,      0 },
+  { "data",    ppc_section,    'd' },
   { "eb",      ppc_eb,         0 },
   { "eb",      ppc_eb,         0 },
+  { "ec",      ppc_ec,         0 },
   { "ef",      ppc_ef,         0 },
   { "ei",      ppc_biei,       1 },
   { "es",      ppc_es,         0 },
   { "ef",      ppc_ef,         0 },
   { "ei",      ppc_biei,       1 },
   { "es",      ppc_es,         0 },
@@ -137,14 +176,23 @@ const pseudo_typeS md_pseudo_table[] =
   { "function",        ppc_function,   0 },
   { "lglobl",  ppc_lglobl,     0 },
   { "rename",  ppc_rename,     0 },
   { "function",        ppc_function,   0 },
   { "lglobl",  ppc_lglobl,     0 },
   { "rename",  ppc_rename,     0 },
+  { "section", ppc_named_section, 0 },
   { "stabx",   ppc_stabx,      0 },
   { "stabx",   ppc_stabx,      0 },
+  { "text",    ppc_section,    't' },
   { "toc",     ppc_toc,        0 },
   { "toc",     ppc_toc,        0 },
+  { "long",    ppc_xcoff_cons, 2 },
+  { "word",    ppc_xcoff_cons, 1 },
+  { "short",   ppc_xcoff_cons, 1 },
+  { "vbyte",    ppc_vbyte,     0 },
 #endif
 
 #ifdef OBJ_ELF
   { "long",    ppc_elf_cons,   4 },
   { "word",    ppc_elf_cons,   2 },
   { "short",   ppc_elf_cons,   2 },
 #endif
 
 #ifdef OBJ_ELF
   { "long",    ppc_elf_cons,   4 },
   { "word",    ppc_elf_cons,   2 },
   { "short",   ppc_elf_cons,   2 },
+  { "rdata",   ppc_elf_rdata,  0 },
+  { "rodata",  ppc_elf_rdata,  0 },
+  { "lcomm",   ppc_elf_lcomm,  0 },
 #endif
 
 #ifdef TE_PE
 #endif
 
 #ifdef TE_PE
@@ -170,9 +218,7 @@ const pseudo_typeS md_pseudo_table[] =
 };
 
 \f
 };
 
 \f
-#ifdef TE_PE
-/* The Windows NT PowerPC assembler uses predefined names.            */
-
+/* 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.                      */
 
 /* In general, there are lots of them, in an attempt to be compatible */
 /* with a number of other Windows NT assemblers.                      */
 
@@ -401,36 +447,138 @@ static const struct pd_reg pre_defined_registers[] =
 /* Given NAME, find the register number associated with that name, return
    the integer value associated with the given name or -1 on failure.  */
 
 /* Given NAME, find the register number associated with that name, return
    the integer value associated with the given name or -1 on failure.  */
 
-static int reg_name_search PARAMS ( (char * name) );
+static int reg_name_search
+  PARAMS ((const struct pd_reg *, int, const char * name));
 
 static int
 
 static int
-reg_name_search (name)
-     char *name;
+reg_name_search (regs, regcount, name)
+     const struct pd_reg *regs;
+     int regcount;
+     const char *name;
 {
   int middle, low, high;
   int cmp;
 
   low = 0;
 {
   int middle, low, high;
   int cmp;
 
   low = 0;
-  high = REG_NAME_CNT - 1;
+  high = regcount - 1;
 
   do
     {
       middle = (low + high) / 2;
 
   do
     {
       middle = (low + high) / 2;
-      cmp = strcasecmp (name, pre_defined_registers[middle].name);
+      cmp = strcasecmp (name, regs[middle].name);
       if (cmp < 0)
        high = middle - 1;
       else if (cmp > 0)
        low = middle + 1;
       else
       if (cmp < 0)
        high = middle - 1;
       else if (cmp > 0)
        low = middle + 1;
       else
-       return pre_defined_registers[middle].value;
+       return regs[middle].value;
     }
   while (low <= high);
 
   return -1;
 }
 
     }
   while (low <= high);
 
   return -1;
 }
 
-#endif
+/*
+ * Summary of register_name().
+ *
+ * in: Input_line_pointer points to 1st char of operand.
+ *
+ * out:        A expressionS.
+ *      The operand may have been a register: in this case, X_op == O_register,
+ *      X_add_number is set to the register number, and truth is returned.
+ *     Input_line_pointer->(next non-blank) char after operand, or is in its
+ *      original state.
+ */
+
+static boolean
+register_name (expressionP)
+     expressionS *expressionP;
+{
+  int reg_number;
+  char *name;
+  char *start;
+  char c;
+
+  /* Find the spelling of the operand */
+  start = name = input_line_pointer;
+  if (name[0] == '%' && isalpha (name[1]))
+    name = ++input_line_pointer;
+
+  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) 
+    {
+      expressionP->X_op = O_register;
+      expressionP->X_add_number = reg_number;
+      
+      /* 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;
+    }
+}
+\f
+/* This function is called for each symbol seen in an expression.  It
+   handles the special parsing which PowerPC assemblers are supposed
+   to use for condition codes.  */
+
+/* Whether to do the special parsing.  */
+static boolean cr_operand;
 
 
+/* Names to recognize in a condition code.  This table is sorted.  */
+static const struct pd_reg cr_names[] =
+{
+  { "cr0", 0 },
+  { "cr1", 1 },
+  { "cr2", 2 },
+  { "cr3", 3 },
+  { "cr4", 4 },
+  { "cr5", 5 },
+  { "cr6", 6 },
+  { "cr7", 7 },
+  { "eq", 2 },
+  { "gt", 1 },
+  { "lt", 0 },
+  { "so", 3 },
+  { "un", 3 }
+};
+
+/* Parsing function.  This returns non-zero if it recognized an
+   expression.  */
+
+int
+ppc_parse_name (name, expr)
+     const char *name;
+     expressionS *expr;
+{
+  int val;
+
+  if (! cr_operand)
+    return 0;
+
+  val = reg_name_search (cr_names, sizeof cr_names / sizeof cr_names[0],
+                        name);
+  if (val < 0)
+    return 0;
+
+  expr->X_op = O_constant;
+  expr->X_add_number = val;
+
+  return 1;
+}
 \f
 /* Local variables.  */
 
 \f
 /* Local variables.  */
 
@@ -449,12 +597,20 @@ static struct hash_control *ppc_hash;
 static struct hash_control *ppc_macro_hash;
 
 #ifdef OBJ_ELF
 static struct hash_control *ppc_macro_hash;
 
 #ifdef OBJ_ELF
-/* Whether to warn about non PC relative relocations that aren't
-   in the .got2 section. */
-static boolean mrelocatable = false;
+/* What type of shared library support to use */
+static enum { SHLIB_NONE, SHLIB_PIC, SHILB_MRELOCATABLE } shlib = SHLIB_NONE;
 
 /* Flags to set in the elf header */
 static flagword ppc_flags = 0;
 
 /* 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
+#else
+#define SOLARIS_P false
+#endif
+
+static boolean msolaris = SOLARIS_P;
 #endif
 
 #ifdef OBJ_XCOFF
 #endif
 
 #ifdef OBJ_XCOFF
@@ -502,9 +658,6 @@ static symbolS *ppc_current_block;
    cause BFD to set the section number of a symbol to N_DEBUG.  */
 static asection *ppc_coff_debug_section;
 
    cause BFD to set the section number of a symbol to N_DEBUG.  */
 static asection *ppc_coff_debug_section;
 
-/* The size of the .debug section.  */
-static bfd_size_type ppc_debug_name_section_size;
-
 #endif /* OBJ_XCOFF */
 
 #ifdef TE_PE
 #endif /* OBJ_XCOFF */
 
 #ifdef TE_PE
@@ -525,14 +678,9 @@ static segT ppc_current_section;
 #ifdef OBJ_ELF
 symbolS *GOT_symbol;           /* Pre-defined "_GLOBAL_OFFSET_TABLE" */
 #endif /* OBJ_ELF */
 #ifdef OBJ_ELF
 symbolS *GOT_symbol;           /* Pre-defined "_GLOBAL_OFFSET_TABLE" */
 #endif /* OBJ_ELF */
-
-#ifndef WORKING_DOT_WORD
-const int md_short_jump_size = 4;
-const int md_long_jump_size = 4;
-#endif
 \f
 #ifdef OBJ_ELF
 \f
 #ifdef OBJ_ELF
-CONST char *md_shortopts = "um:VQ:";
+CONST char *md_shortopts = "b:l:usm:K:VQ:";
 #else
 CONST char *md_shortopts = "um:";
 #endif
 #else
 CONST char *md_shortopts = "um:";
 #endif
@@ -553,6 +701,44 @@ md_parse_option (c, arg)
         external, which is the default for gas anyhow.  */
       break;
 
         external, which is the default for gas anyhow.  */
       break;
 
+#ifdef OBJ_ELF
+    case 'l':
+      /* Solaris as takes -le (presumably for little endian).  For completeness
+         sake, recognize -be also.  */
+      if (strcmp (arg, "e") == 0)
+       {
+         target_big_endian = 0;
+         set_target_endian = 1;
+       }
+      else
+       return 0;
+
+      break;
+
+    case 'b':
+      if (strcmp (arg, "e") == 0)
+       {
+         target_big_endian = 1;
+         set_target_endian = 1;
+       }
+      else
+       return 0;
+
+      break;
+
+    case 'K':
+      /* Recognize -K PIC */
+      if (strcmp (arg, "PIC") == 0 || strcmp (arg, "pic") == 0)
+       {
+         shlib = SHLIB_PIC;
+         ppc_flags |= EF_PPC_RELOCATABLE_LIB;
+       }
+      else
+       return 0;
+
+      break;
+#endif
+
     case 'm':
       /* -mpwrx and -mpwr2 mean to assemble for the IBM POWER/2
          (RIOS2).  */
     case 'm':
       /* -mpwrx and -mpwr2 mean to assemble for the IBM POWER/2
          (RIOS2).  */
@@ -561,10 +747,8 @@ md_parse_option (c, arg)
       /* -mpwr means to assemble for the IBM POWER (RIOS1).  */
       else if (strcmp (arg, "pwr") == 0)
        ppc_cpu = PPC_OPCODE_POWER;
       /* -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.  FIXME: We
-        ignore the option for now, but we should really use it to permit
-        instructions defined on the 601 that are not part of the standard
-        PowerPC architecture (mostly holdovers from the 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
       else if (strcmp (arg, "601") == 0)
        ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_601;
       /* -mppc, -mppc32, -m603, and -m604 mean to assemble for the
@@ -582,26 +766,37 @@ md_parse_option (c, arg)
          ppc_cpu = PPC_OPCODE_PPC;
          ppc_size = PPC_OPCODE_64;
        }
          ppc_cpu = PPC_OPCODE_PPC;
          ppc_size = PPC_OPCODE_64;
        }
+      else if (strcmp (arg, "ppc64bridge") == 0)
+       {
+         ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_64_BRIDGE;
+         ppc_size = PPC_OPCODE_64;
+       }
       /* -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)
       /* -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_POWER | PPC_OPCODE_PPC;
+       ppc_cpu = PPC_OPCODE_COMMON;
       /* -many means to assemble for any architecture (PWR/PWRX/PPC).  */
       else if (strcmp (arg, "any") == 0)
       /* -many means to assemble for any architecture (PWR/PWRX/PPC).  */
       else if (strcmp (arg, "any") == 0)
-       ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_POWER2 | PPC_OPCODE_PPC;
+       ppc_cpu = PPC_OPCODE_ANY;
+
+      else if (strcmp (arg, "regnames") == 0)
+       reg_names_p = true;
+
+      else if (strcmp (arg, "no-regnames") == 0)
+       reg_names_p = false;
 
 #ifdef OBJ_ELF
       /* -mrelocatable/-mrelocatable-lib -- warn about initializations that require relocation */
       else if (strcmp (arg, "relocatable") == 0)
        {
 
 #ifdef OBJ_ELF
       /* -mrelocatable/-mrelocatable-lib -- warn about initializations that require relocation */
       else if (strcmp (arg, "relocatable") == 0)
        {
-         mrelocatable = true;
+         shlib = SHILB_MRELOCATABLE;
          ppc_flags |= EF_PPC_RELOCATABLE;
        }
 
       else if (strcmp (arg, "relocatable-lib") == 0)
        {
          ppc_flags |= EF_PPC_RELOCATABLE;
        }
 
       else if (strcmp (arg, "relocatable-lib") == 0)
        {
-         mrelocatable = true;
+         shlib = SHILB_MRELOCATABLE;
          ppc_flags |= EF_PPC_RELOCATABLE_LIB;
        }
 
          ppc_flags |= EF_PPC_RELOCATABLE_LIB;
        }
 
@@ -621,10 +816,22 @@ md_parse_option (c, arg)
          target_big_endian = 1;
          set_target_endian = 1;
        }
          target_big_endian = 1;
          set_target_endian = 1;
        }
+
+      else if (strcmp (arg, "solaris") == 0)
+       {
+         msolaris = true;
+         ppc_comment_chars = ppc_solaris_comment_chars;
+       }
+
+      else if (strcmp (arg, "no-solaris") == 0)
+       {
+         msolaris = false;
+         ppc_comment_chars = ppc_eabi_comment_chars;
+       }
 #endif
       else
        {
 #endif
       else
        {
-         as_bad ("invalid switch -m%s", arg);
+         as_bad (_("invalid switch -m%s"), arg);
          return 0;
        }
       break;
          return 0;
        }
       break;
@@ -639,6 +846,15 @@ md_parse_option (c, arg)
         should be emitted or not.  FIXME: Not implemented.  */
     case 'Q':
       break;
         should be emitted or not.  FIXME: Not implemented.  */
     case 'Q':
       break;
+
+      /* Solaris takes -s to specify that .stabs go in a .stabs section,
+        rather than .stabs.excl, which is ignored by the linker.
+        FIXME: Not implemented.  */
+    case 's':
+      if (arg)
+       return 0;
+
+      break;
 #endif
 
     default:
 #endif
 
     default:
@@ -652,7 +868,7 @@ void
 md_show_usage (stream)
      FILE *stream;
 {
 md_show_usage (stream)
      FILE *stream;
 {
-  fprintf(stream, "\
+  fprintf(stream, _("\
 PowerPC options:\n\
 -u                     ignored\n\
 -mpwrx, -mpwr2         generate code for IBM POWER/2 (RIOS2)\n\
 PowerPC options:\n\
 -u                     ignored\n\
 -mpwrx, -mpwr2         generate code for IBM POWER/2 (RIOS2)\n\
@@ -661,18 +877,23 @@ PowerPC options:\n\
 -mppc, -mppc32, -m403, -m603, -m604\n\
                        generate code for Motorola PowerPC 603/604\n\
 -mppc64, -m620         generate code for Motorola PowerPC 620\n\
 -mppc, -mppc32, -m403, -m603, -m604\n\
                        generate code for Motorola PowerPC 603/604\n\
 -mppc64, -m620         generate code for Motorola PowerPC 620\n\
--mcom                  generate code Power/PowerPC common instructions\n
--many                  generate code for any architecture (PWR/PWRX/PPC)\n");
+-mppc64bridge          generate code for PowerPC 64, including bridge insns\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"));
 #ifdef OBJ_ELF
 #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\
                        generate code for a little endian machine\n\
 -mbig, -mbig-endian    generate code for a big endian machine\n\
 -mrelocatable          support for GCC's -mrelocatble option\n\
 -mrelocatable-lib      support for GCC's -mrelocatble-lib option\n\
 -memb                  set PPC_EMB bit in ELF flags\n\
 -mlittle, -mlittle-endian\n\
                        generate code for a little endian machine\n\
 -mbig, -mbig-endian    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\
 -V                     print assembler version number\n\
--Qy, -Qn               ignored\n");
+-Qy, -Qn               ignored\n"));
 #endif
 }
 \f
 #endif
 }
 \f
@@ -681,17 +902,23 @@ PowerPC options:\n\
 static void
 ppc_set_cpu ()
 {
 static void
 ppc_set_cpu ()
 {
+  const char *default_os  = TARGET_OS;
   const char *default_cpu = TARGET_CPU;
 
   if (ppc_cpu == 0)
     {
   const char *default_cpu = TARGET_CPU;
 
   if (ppc_cpu == 0)
     {
-      if (strcmp (default_cpu, "rs6000") == 0)
+      if (strncmp (default_os, "aix", 3) == 0
+         && default_os[3] >= '4' && default_os[3] <= '9')
+       ppc_cpu = PPC_OPCODE_COMMON;
+      else if (strncmp (default_os, "aix3", 4) == 0)
+       ppc_cpu = PPC_OPCODE_POWER;
+      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;
       else
        ppc_cpu = PPC_OPCODE_POWER;
       else if (strcmp (default_cpu, "powerpc") == 0
               || strcmp (default_cpu, "powerpcle") == 0)
        ppc_cpu = PPC_OPCODE_PPC;
       else
-       as_fatal ("Unknown default cpu = %s", default_cpu);
+       as_fatal (_("Unknown default cpu = %s, os = %s"), default_cpu, default_os);
     }
 }
 
     }
 }
 
@@ -700,17 +927,24 @@ ppc_set_cpu ()
 enum bfd_architecture
 ppc_arch ()
 {
 enum bfd_architecture
 ppc_arch ()
 {
+  const char *default_cpu = TARGET_CPU;
   ppc_set_cpu ();
 
   if ((ppc_cpu & PPC_OPCODE_PPC) != 0)
     return bfd_arch_powerpc;
   else if ((ppc_cpu & PPC_OPCODE_POWER) != 0)
     return bfd_arch_rs6000;
   ppc_set_cpu ();
 
   if ((ppc_cpu & PPC_OPCODE_PPC) != 0)
     return bfd_arch_powerpc;
   else if ((ppc_cpu & PPC_OPCODE_POWER) != 0)
     return bfd_arch_rs6000;
-  else
+  else if ((ppc_cpu & (PPC_OPCODE_COMMON | PPC_OPCODE_ANY)) != 0)
     {
     {
-      as_fatal ("Neither Power nor PowerPC opcodes were selected.");
-      return bfd_arch_unknown;
+      if (strcmp (default_cpu, "rs6000") == 0)
+       return bfd_arch_rs6000;
+      else if (strcmp (default_cpu, "powerpc") == 0
+              || strcmp (default_cpu, "powerpcle") == 0)
+       return bfd_arch_powerpc;
     }
     }
+
+  as_fatal (_("Neither Power nor PowerPC opcodes were selected."));
+  return bfd_arch_unknown;
 }
 
 /* This function is called when the assembler starts up.  It is called
 }
 
 /* This function is called when the assembler starts up.  It is called
@@ -724,12 +958,13 @@ md_begin ()
   const struct powerpc_opcode *op_end;
   const struct powerpc_macro *macro;
   const struct powerpc_macro *macro_end;
   const struct powerpc_opcode *op_end;
   const struct powerpc_macro *macro;
   const struct powerpc_macro *macro_end;
+  boolean dup_insn = false;
 
   ppc_set_cpu ();
 
 #ifdef OBJ_ELF
   /* Set the ELF flags if desired. */
 
   ppc_set_cpu ();
 
 #ifdef OBJ_ELF
   /* Set the ELF flags if desired. */
-  if (ppc_flags)
+  if (ppc_flags && !msolaris)
     bfd_set_private_flags (stdoutput, ppc_flags);
 #endif
 
     bfd_set_private_flags (stdoutput, ppc_flags);
 #endif
 
@@ -743,31 +978,21 @@ md_begin ()
 
       if ((op->flags & ppc_cpu) != 0
          && ((op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64)) == 0
 
       if ((op->flags & ppc_cpu) != 0
          && ((op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64)) == 0
-             || (op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64)) == ppc_size))
+             || (op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64)) == ppc_size
+             || (ppc_cpu & PPC_OPCODE_64_BRIDGE) != 0))
        {
          const char *retval;
 
          retval = hash_insert (ppc_hash, op->name, (PTR) op);
          if (retval != (const char *) NULL)
            {
        {
          const char *retval;
 
          retval = hash_insert (ppc_hash, op->name, (PTR) op);
          if (retval != (const char *) NULL)
            {
-             /* We permit a duplication of the mfdec instruction on
-                the 601, because it seems to have one value on the
-                601 and a different value on other PowerPC
-                processors.  It's easier to permit a duplication than
-                to define a new instruction type flag.  When using
-                -many, the comparison instructions are a harmless
-                special case.  */
-             if (strcmp (retval, "exists") != 0
-                 || (((ppc_cpu & PPC_OPCODE_601) == 0
-                      || strcmp (op->name, "mfdec") != 0)
-                     && (ppc_cpu != (PPC_OPCODE_POWER
-                                     | PPC_OPCODE_POWER2
-                                     | PPC_OPCODE_PPC)
-                         || (strcmp (op->name, "cmpli") != 0
-                             && strcmp (op->name, "cmpi") != 0
-                             && strcmp (op->name, "cmp") != 0
-                             && strcmp (op->name, "cmpl") != 0))))
-               abort ();
+             /* 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;
            }
        }
     }
            }
        }
     }
@@ -784,10 +1009,16 @@ md_begin ()
 
          retval = hash_insert (ppc_macro_hash, macro->name, (PTR) macro);
          if (retval != (const char *) NULL)
 
          retval = hash_insert (ppc_macro_hash, macro->name, (PTR) macro);
          if (retval != (const char *) NULL)
-           abort ();
+           {
+             as_bad (_("Internal assembler error for macro %s"), macro->name);
+             dup_insn = true;
+           }
        }
     }
 
        }
     }
 
+  if (dup_insn)
+    abort ();
+
   /* Tell the main code what the endianness is if it is not overidden by the user.  */
   if (!set_target_endian)
     {
   /* Tell the main code what the endianness is if it is not overidden by the user.  */
   if (!set_target_endian)
     {
@@ -802,9 +1033,9 @@ md_begin ()
      text csects to precede the data csects.  These symbols will not
      be output.  */
   ppc_text_csects = symbol_make ("dummy\001");
      text csects to precede the data csects.  These symbols will not
      be output.  */
   ppc_text_csects = symbol_make ("dummy\001");
-  ppc_text_csects->sy_tc.within = ppc_text_csects;
+  symbol_get_tc (ppc_text_csects)->within = ppc_text_csects;
   ppc_data_csects = symbol_make ("dummy\001");
   ppc_data_csects = symbol_make ("dummy\001");
-  ppc_data_csects->sy_tc.within = ppc_data_csects;
+  symbol_get_tc (ppc_data_csects)->within = ppc_data_csects;
 #endif
 
 #ifdef TE_PE
 #endif
 
 #ifdef TE_PE
@@ -832,12 +1063,26 @@ ppc_insert_operand (insn, operand, val, file, line)
 
       if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
        {
 
       if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
        {
-         if ((operand->flags & PPC_OPERAND_SIGNOPT) != 0
-             && ppc_size == PPC_OPCODE_32)
+         if ((operand->flags & PPC_OPERAND_SIGNOPT) != 0)
            max = (1 << operand->bits) - 1;
          else
            max = (1 << (operand->bits - 1)) - 1;
          min = - (1 << (operand->bits - 1));
            max = (1 << operand->bits) - 1;
          else
            max = (1 << (operand->bits - 1)) - 1;
          min = - (1 << (operand->bits - 1));
+
+         if (ppc_size == PPC_OPCODE_32)
+           {
+             /* 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 -= 0x80000000;
+                 val -= 0x80000000;
+               }
+           }
        }
       else
        {
        }
       else
        {
@@ -853,14 +1098,14 @@ ppc_insert_operand (insn, operand, val, file, line)
       if (test < (offsetT) min || test > (offsetT) max)
        {
          const char *err =
       if (test < (offsetT) min || test > (offsetT) max)
        {
          const char *err =
-           "operand out of range (%s not between %ld and %ld)";
+           _("operand out of range (%s not between %ld and %ld)");
          char buf[100];
 
          sprint_value (buf, test);
          if (file == (char *) NULL)
          char buf[100];
 
          sprint_value (buf, test);
          if (file == (char *) NULL)
-           as_warn (err, buf, min, max);
+           as_bad (err, buf, min, max);
          else
          else
-           as_warn_where (file, line, err, buf, min, max);
+           as_bad_where (file, line, err, buf, min, max);
        }
     }
 
        }
     }
 
@@ -871,7 +1116,7 @@ ppc_insert_operand (insn, operand, val, file, line)
       errmsg = NULL;
       insn = (*operand->insert) (insn, (long) val, &errmsg);
       if (errmsg != (const char *) NULL)
       errmsg = NULL;
       insn = (*operand->insert) (insn, (long) val, &errmsg);
       if (errmsg != (const char *) NULL)
-       as_warn (errmsg);
+       as_bad (errmsg);
     }
   else
     insn |= (((long) val & ((1 << operand->bits) - 1))
     }
   else
     insn |= (((long) val & ((1 << operand->bits) - 1))
@@ -880,11 +1125,13 @@ ppc_insert_operand (insn, operand, val, file, line)
   return insn;
 }
 
   return insn;
 }
 
+\f
 #ifdef OBJ_ELF
 /* Parse @got, etc. and return the desired relocation.  */
 static bfd_reloc_code_real_type
 #ifdef OBJ_ELF
 /* Parse @got, etc. and return the desired relocation.  */
 static bfd_reloc_code_real_type
-ppc_elf_suffix (str_p)
+ppc_elf_suffix (str_p, exp_p)
      char **str_p;
      char **str_p;
+     expressionS *exp_p;
 {
   struct map_bfd {
     char *string;
 {
   struct map_bfd {
     char *string;
@@ -902,21 +1149,22 @@ ppc_elf_suffix (str_p)
 #define MAP(str,reloc) { str, sizeof(str)-1, reloc }
 
   static struct map_bfd mapping[] = {
 #define MAP(str,reloc) { str, sizeof(str)-1, reloc }
 
   static struct map_bfd mapping[] = {
-    MAP ("got",                BFD_RELOC_PPC_TOC16),
     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 ("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 ("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 ("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 ("plt",                BFD_RELOC_32_PLTOFF),
+    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 ("pltrel",     BFD_RELOC_32_PLT_PCREL),
     MAP ("plt@l",      BFD_RELOC_LO16_PLTOFF),
     MAP ("plt@h",      BFD_RELOC_HI16_PLTOFF),
@@ -926,6 +1174,23 @@ ppc_elf_suffix (str_p)
     MAP ("sectoff@l",  BFD_RELOC_LO16_BASEREL),
     MAP ("sectoff@h",  BFD_RELOC_HI16_BASEREL),
     MAP ("sectoff@ha", BFD_RELOC_HI16_S_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 }
   };
 
     { (char *)0,       0,      BFD_RELOC_UNUSED }
   };
@@ -934,7 +1199,8 @@ ppc_elf_suffix (str_p)
     return BFD_RELOC_UNUSED;
 
   for (ch = *str, str2 = ident;
     return BFD_RELOC_UNUSED;
 
   for (ch = *str, str2 = ident;
-       str2 < ident + sizeof(ident) - 1 && isalnum (ch) || ch == '@';
+       (str2 < ident + sizeof (ident) - 1
+       && (isalnum (ch) || ch == '@'));
        ch = *++str)
     {
       *str2++ = (islower (ch)) ? ch : tolower (ch);
        ch = *++str)
     {
       *str2++ = (islower (ch)) ? ch : tolower (ch);
@@ -945,8 +1211,35 @@ ppc_elf_suffix (str_p)
 
   ch = ident[0];
   for (ptr = &mapping[0]; ptr->length > 0; ptr++)
 
   ch = ident[0];
   for (ptr = &mapping[0]; ptr->length > 0; ptr++)
-    if (ch == ptr->string[0] && len == ptr->length && memcmp (ident, ptr->string, ptr->length) == 0)
+    if (ch == ptr->string[0]
+       && len == ptr->length
+       && memcmp (ident, ptr->string, ptr->length) == 0)
       {
       {
+       if (exp_p->X_add_number != 0
+           && (ptr->reloc == BFD_RELOC_16_GOTOFF
+               || ptr->reloc == BFD_RELOC_LO16_GOTOFF
+               || ptr->reloc == BFD_RELOC_HI16_GOTOFF
+               || ptr->reloc == BFD_RELOC_HI16_S_GOTOFF))
+         as_warn (_("identifier+constant@got means identifier@got+constant"));
+
+       /* Now check for identifier@suffix+constant */
+       if (*str == '-' || *str == '+')
+         {
+           char *orig_line = input_line_pointer;
+           expressionS new_exp;
+
+           input_line_pointer = str;
+           expression (&new_exp);
+           if (new_exp.X_op == O_constant)
+             {
+               exp_p->X_add_number += new_exp.X_add_number;
+               str = input_line_pointer;
+             }
+
+           if (&input_line_pointer != str_p)
+             input_line_pointer = orig_line;
+         }
+
        *str_p = str;
        return ptr->reloc;
       }
        *str_p = str;
        return ptr->reloc;
       }
@@ -975,13 +1268,13 @@ ppc_elf_cons (nbytes)
       expression (&exp);
       if (exp.X_op == O_symbol
          && *input_line_pointer == '@'
       expression (&exp);
       if (exp.X_op == O_symbol
          && *input_line_pointer == '@'
-         && (reloc = ppc_elf_suffix (&input_line_pointer)) != 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);
 
          if (size > nbytes)
        {
          reloc_howto_type *reloc_howto = bfd_reloc_type_lookup (stdoutput, reloc);
          int 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);
+           as_bad (_("%s relocations do not fit in %d bytes\n"), reloc_howto->name, nbytes);
 
          else
            {
 
          else
            {
@@ -1000,81 +1293,178 @@ ppc_elf_cons (nbytes)
   demand_empty_rest_of_line ();
 }
 
   demand_empty_rest_of_line ();
 }
 
-/* Validate any relocations emitted for -mrelocatable, possibly adding
-   fixups for word relocations in writable segments, so we can adjust
-   them at runtime.  */
+/* Solaris pseduo op to change to the .rodata section.  */
 static void
 static void
-ppc_elf_validate_fix (fixp, seg)
-     fixS *fixp;
-     segT seg;
+ppc_elf_rdata (xxx)
+     int xxx;
 {
 {
-  if (mrelocatable
-      && !fixp->fx_done
-      && !fixp->fx_pcrel
-      && fixp->fx_r_type <= BFD_RELOC_UNUSED
-      && 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)
+  char *save_line = input_line_pointer;
+  static char section[] = ".rodata\n";
+
+  /* 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 */
+static void
+ppc_elf_lcomm(xxx)
+     int xxx;
+{
+  register char *name;
+  register char c;
+  register char *p;
+  offsetT size;
+  register symbolS *symbolP;
+  offsetT align;
+  segT old_sec;
+  int old_subsec;
+  char *pfrag;
+  int align2;
+
+  name = input_line_pointer;
+  c = get_symbol_end ();
+
+  /* just after name is now '\0' */
+  p = input_line_pointer;
+  *p = c;
+  SKIP_WHITESPACE ();
+  if (*input_line_pointer != ',')
+    {
+      as_bad (_("Expected comma after symbol-name: rest of line ignored."));
+      ignore_rest_of_line ();
+      return;
+    }
+
+  input_line_pointer++;                /* skip ',' */
+  if ((size = get_absolute_expression ()) < 0)
     {
     {
-      if ((seg->flags & (SEC_READONLY | SEC_CODE)) != 0
-         || fixp->fx_r_type != BFD_RELOC_CTOR)
+      as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) size);
+      ignore_rest_of_line ();
+      return;
+    }
+
+  /* The third argument to .lcomm is the alignment.  */
+  if (*input_line_pointer != ',')
+    align = 8;
+  else
+    {
+      ++input_line_pointer;
+      align = get_absolute_expression ();
+      if (align <= 0)
        {
        {
-         as_warn_where (fixp->fx_file, fixp->fx_line,
-                        "Relocation cannot be done when using -mrelocatable");
+         as_warn (_("ignoring bad alignment"));
+         align = 8;
        }
     }
        }
     }
-}
 
 
-#endif /* OBJ_ELF */
+  *p = 0;
+  symbolP = symbol_find_or_make (name);
+  *p = c;
 
 
-#ifdef TE_PE
-/*
- * Summary of register_name().
- *
- * in: Input_line_pointer points to 1st char of operand.
- *
- * out:        A expressionS.
- *      The operand may have been a register: in this case, X_op == O_register,
- *      X_add_number is set to the register number, and truth is returned.
- *     Input_line_pointer->(next non-blank) char after operand, or is in its
- *      original state.
- */
+  if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP))
+    {
+      as_bad (_("Ignoring attempt to re-define symbol `%s'."),
+             S_GET_NAME (symbolP));
+      ignore_rest_of_line ();
+      return;
+    }
 
 
-static int
-register_name (expressionP)
-     expressionS *expressionP;
-{
-  int reg_number;
-  char *name;
-  char c;
+  if (S_GET_VALUE (symbolP) && S_GET_VALUE (symbolP) != (valueT) size)
+    {
+      as_bad (_("Length of .lcomm \"%s\" is already %ld. Not changed to %ld."),
+             S_GET_NAME (symbolP),
+             (long) S_GET_VALUE (symbolP),
+             (long) size);
 
 
-  /* Find the spelling of the operand */
-  name = input_line_pointer;
-  c = get_symbol_end ();
-  reg_number = reg_name_search (name);
+      ignore_rest_of_line ();
+      return;
+    }
 
 
-  /* look to see if it's in the register table */
-  if (reg_number >= 0) 
+  /* allocate_bss: */
+  old_sec = now_seg;
+  old_subsec = now_subseg;
+  if (align)
     {
     {
-      expressionP->X_op = O_register;
-      expressionP->X_add_number = reg_number;
-      
-      /* make the rest nice */
-      expressionP->X_add_symbol = NULL;
-      expressionP->X_op_symbol = NULL;
-      *input_line_pointer = c;   /* put back the delimiting char */
-      return 1;
+      /* convert to a power of 2 alignment */
+      for (align2 = 0; (align & 1) == 0; align >>= 1, ++align2);
+      if (align != 1)
+       {
+         as_bad (_("Common alignment not a power of 2"));
+         ignore_rest_of_line ();
+         return;
+       }
     }
   else
     }
   else
+    align2 = 0;
+
+  record_alignment (bss_section, align2);
+  subseg_set (bss_section, 0);
+  if (align2)
+    frag_align (align2, 0, 0);
+  if (S_GET_SEGMENT (symbolP) == bss_section)
+    symbol_get_frag (symbolP)->fr_symbol = 0;
+  symbol_set_frag (symbolP, frag_now);
+  pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, size,
+                   (char *) 0);
+  *pfrag = 0;
+  S_SET_SIZE (symbolP, size);
+  S_SET_SEGMENT (symbolP, bss_section);
+  subseg_set (old_sec, old_subsec);
+  demand_empty_rest_of_line ();
+}
+
+/* Validate any relocations emitted for -mrelocatable, possibly adding
+   fixups for word relocations in writable segments, so we can adjust
+   them at runtime.  */
+static void
+ppc_elf_validate_fix (fixp, seg)
+     fixS *fixp;
+     segT seg;
+{
+  if (fixp->fx_done || fixp->fx_pcrel)
+    return;
+
+  switch (shlib)
     {
     {
-      /* reset the line as if we had not done anything */
-      *input_line_pointer = c;   /* put back the delimiting char */
-      input_line_pointer = name; /* reset input_line pointer */
-      return 0;
+    case SHLIB_NONE:
+    case SHLIB_PIC:
+      return;
+
+    case SHILB_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_LO16_BASEREL
+         && fixp->fx_r_type != BFD_RELOC_HI16_BASEREL
+         && fixp->fx_r_type != BFD_RELOC_HI16_S_BASEREL
+         && 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)
+       {
+         if ((seg->flags & (SEC_READONLY | SEC_CODE)) != 0
+             || fixp->fx_r_type != BFD_RELOC_CTOR)
+           {
+             as_bad_where (fixp->fx_file, fixp->fx_line,
+                           _("Relocation cannot be done when using -mrelocatable"));
+           }
+       }
+      return;
     }
 }
     }
 }
+#endif /* OBJ_ELF */
+\f
+#ifdef TE_PE
 
 /*
  * Summary of parse_toc_entry().
 
 /*
  * Summary of parse_toc_entry().
@@ -1147,7 +1537,7 @@ parse_toc_entry(toc_kind)
     }
   else
     {
     }
   else
     {
-      as_bad ("syntax error: invalid toc specifier `%s'", toc_spec);
+      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 */
       return 0;
       *input_line_pointer = c;   /* put back the delimiting char */
       input_line_pointer = start; /* reset input_line pointer */
       return 0;
@@ -1161,7 +1551,7 @@ parse_toc_entry(toc_kind)
 
   if (c != ']')
     {
 
   if (c != ']')
     {
-      as_bad ("syntax error: expected `]', found  `%c'", c);
+      as_bad (_("syntax error: expected `]', found  `%c'"), c);
       input_line_pointer = start; /* reset input_line pointer */
       return 0;
     }
       input_line_pointer = start; /* reset input_line pointer */
       return 0;
     }
@@ -1169,9 +1559,8 @@ parse_toc_entry(toc_kind)
   *toc_kind = t;             /* set return value */
   return 1;
 }
   *toc_kind = t;             /* set return value */
   return 1;
 }
-
 #endif
 #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
 
 /* 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
@@ -1221,7 +1610,7 @@ md_assemble (str)
 
       macro = (const struct powerpc_macro *) hash_find (ppc_macro_hash, str);
       if (macro == (const struct powerpc_macro *) NULL)
 
       macro = (const struct powerpc_macro *) hash_find (ppc_macro_hash, str);
       if (macro == (const struct powerpc_macro *) NULL)
-       as_bad ("Unrecognized opcode: `%s'", str);
+       as_bad (_("Unrecognized opcode: `%s'"), str);
       else
        ppc_macro (s, macro);
 
       else
        ppc_macro (s, macro);
 
@@ -1306,7 +1695,7 @@ md_assemble (str)
        {
          insn = (*operand->insert) (insn, 0L, &errmsg);
          if (errmsg != (const char *) NULL)
        {
          insn = (*operand->insert) (insn, 0L, &errmsg);
          if (errmsg != (const char *) NULL)
-           as_warn (errmsg);
+           as_bad (errmsg);
          continue;
        }
 
          continue;
        }
 
@@ -1319,7 +1708,7 @@ md_assemble (str)
            {
              insn = (*operand->insert) (insn, 0L, &errmsg);
              if (errmsg != (const char *) NULL)
            {
              insn = (*operand->insert) (insn, 0L, &errmsg);
              if (errmsg != (const char *) NULL)
-               as_warn (errmsg);
+               as_bad (errmsg);
            }
          if ((operand->flags & PPC_OPERAND_NEXT) != 0)
            next_opindex = *opindex_ptr + 1;
            }
          if ((operand->flags & PPC_OPERAND_NEXT) != 0)
            next_opindex = *opindex_ptr + 1;
@@ -1394,9 +1783,10 @@ md_assemble (str)
              if (ex.X_op == O_symbol) 
                {                 
                  assert (ex.X_add_symbol != NULL);
              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_warn("[tocv] symbol is not a toc symbol");
+                     as_bad(_("[tocv] symbol is not a toc symbol"));
                    }
                }
 
                    }
                }
 
@@ -1407,16 +1797,16 @@ md_assemble (str)
              /*        entries. We don't support them today. Is this the   */
              /*        right way to say that?                              */
              toc_reloc = BFD_RELOC_UNUSED;
              /*        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");
+             as_bad (_("Unimplemented toc32 expression modifier"));
              break;
            case must_be_64:
              /* FIXME: see above */
              toc_reloc = BFD_RELOC_UNUSED;
              break;
            case must_be_64:
              /* FIXME: see above */
              toc_reloc = BFD_RELOC_UNUSED;
-             as_bad ("Unimplemented toc64 expression modifier");
+             as_bad (_("Unimplemented toc64 expression modifier"));
              break;
            default:
              fprintf(stderr, 
              break;
            default:
              fprintf(stderr, 
-                     "Unexpected return value [%d] from parse_toc_entry!\n",
+                     _("Unexpected return value [%d] from parse_toc_entry!\n"),
                      toc_kind);
              abort();
              break;
                      toc_kind);
              abort();
              break;
@@ -1424,7 +1814,7 @@ md_assemble (str)
 
          /* We need to generate a fixup for this expression.  */
          if (fc >= MAX_INSN_FIXUPS)
 
          /* We need to generate a fixup for this expression.  */
          if (fc >= MAX_INSN_FIXUPS)
-           as_fatal ("too many fixups");
+           as_fatal (_("too many fixups"));
 
          fixups[fc].reloc = toc_reloc;
          fixups[fc].exp = ex;
 
          fixups[fc].reloc = toc_reloc;
          fixups[fc].exp = ex;
@@ -1439,33 +1829,38 @@ md_assemble (str)
          ex.X_add_symbol = NULL;
          ex.X_op_symbol = NULL;
        }
          ex.X_add_symbol = NULL;
          ex.X_op_symbol = NULL;
        }
+
       else
       else
+#endif         /* TE_PE */
        {
        {
-         if (!register_name(&ex))
+         if (! register_name (&ex))
            {
            {
+             if ((operand->flags & PPC_OPERAND_CR) != 0)
+               cr_operand = true;
              expression (&ex);
              expression (&ex);
+             cr_operand = false;
            }
        }
 
       str = input_line_pointer;
       input_line_pointer = hold;
            }
        }
 
       str = input_line_pointer;
       input_line_pointer = hold;
-#else
-      expression (&ex);
-      str = input_line_pointer;
-      input_line_pointer = hold;
-#endif
 
       if (ex.X_op == O_illegal)
 
       if (ex.X_op == O_illegal)
-       as_bad ("illegal operand");
+       as_bad (_("illegal operand"));
       else if (ex.X_op == O_absent)
       else if (ex.X_op == O_absent)
-       as_bad ("missing operand");
+       as_bad (_("missing operand"));
+      else if (ex.X_op == O_register)
+       {
+         insn = ppc_insert_operand (insn, operand, ex.X_add_number,
+                                    (char *) NULL, 0);
+       }
       else if (ex.X_op == O_constant)
        {
 #ifdef OBJ_ELF
          /* Allow @HA, @L, @H on constants. */
          char *orig_str = str;
 
       else if (ex.X_op == O_constant)
        {
 #ifdef OBJ_ELF
          /* Allow @HA, @L, @H on constants. */
          char *orig_str = str;
 
-         if ((reloc = ppc_elf_suffix (&str)) != BFD_RELOC_UNUSED)
+         if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
            switch (reloc)
              {
              default:
            switch (reloc)
              {
              default:
@@ -1473,7 +1868,16 @@ md_assemble (str)
                break;
 
              case BFD_RELOC_LO16:
                break;
 
              case BFD_RELOC_LO16:
-               ex.X_add_number = ((ex.X_add_number & 0xffff) ^ 0x8000) - 0x8000;
+               /* 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)
+                 ex.X_add_number &= 0xffff;
+               else
+                 ex.X_add_number = (((ex.X_add_number & 0xffff)
+                                     ^ 0x8000)
+                                    - 0x8000);
                break;
 
              case BFD_RELOC_HI16:
                break;
 
              case BFD_RELOC_HI16:
@@ -1481,38 +1885,44 @@ md_assemble (str)
                break;
 
              case BFD_RELOC_HI16_S:
                break;
 
              case BFD_RELOC_HI16_S:
-               ex.X_add_number = ((ex.X_add_number >> 16) & 0xffff)
-                 + ((ex.X_add_number >> 15) & 1);
+               ex.X_add_number = ((((ex.X_add_number >> 16) & 0xffff)
+                                   + ((ex.X_add_number >> 15) & 1))
+                                  & 0xffff);
                break;
              }
 #endif
          insn = ppc_insert_operand (insn, operand, ex.X_add_number,
                                     (char *) NULL, 0);
        }
                break;
              }
 #endif
          insn = ppc_insert_operand (insn, operand, ex.X_add_number,
                                     (char *) NULL, 0);
        }
-#ifdef TE_PE
-      else if (ex.X_op == O_register)
-       {
-         insn = ppc_insert_operand (insn, operand, ex.X_add_number,
-                                    (char *) NULL, 0);
-       }
-#endif
 #ifdef OBJ_ELF
 #ifdef OBJ_ELF
-      else if ((reloc = ppc_elf_suffix (&str)) != BFD_RELOC_UNUSED)
+      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.  */
          if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
        {
          /* For the absoulte forms of branchs, convert the PC relative form back into
             the absolute.  */
          if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
-           switch (reloc)
-             {
-             case BFD_RELOC_PPC_B26:           reloc = BFD_RELOC_PPC_BA26;             break;
-             case BFD_RELOC_PPC_B16:           reloc = BFD_RELOC_PPC_BA16;             break;
-             case BFD_RELOC_PPC_B16_BRTAKEN:   reloc = BFD_RELOC_PPC_BA16_BRTAKEN;     break;
-             case BFD_RELOC_PPC_B16_BRNTAKEN:  reloc = BFD_RELOC_PPC_BA16_BRNTAKEN;    break;
-             }
+           {
+             switch (reloc)
+               {
+               case BFD_RELOC_PPC_B26:
+                 reloc = BFD_RELOC_PPC_BA26;
+                 break;
+               case BFD_RELOC_PPC_B16:
+                 reloc = BFD_RELOC_PPC_BA16;
+                 break;
+               case BFD_RELOC_PPC_B16_BRTAKEN:
+                 reloc = BFD_RELOC_PPC_BA16_BRTAKEN;
+                 break;
+               case BFD_RELOC_PPC_B16_BRNTAKEN:
+                 reloc = BFD_RELOC_PPC_BA16_BRNTAKEN;
+                 break;
+               default:
+                 break;
+               }
+           }
 
          /* We need to generate a fixup for this expression.  */
          if (fc >= MAX_INSN_FIXUPS)
 
          /* We need to generate a fixup for this expression.  */
          if (fc >= MAX_INSN_FIXUPS)
-           as_fatal ("too many fixups");
+           as_fatal (_("too many fixups"));
          fixups[fc].exp = ex;
          fixups[fc].opindex = 0;
          fixups[fc].reloc = reloc;
          fixups[fc].exp = ex;
          fixups[fc].opindex = 0;
          fixups[fc].reloc = reloc;
@@ -1524,7 +1934,7 @@ md_assemble (str)
        {
          /* We need to generate a fixup for this expression.  */
          if (fc >= MAX_INSN_FIXUPS)
        {
          /* We need to generate a fixup for this expression.  */
          if (fc >= MAX_INSN_FIXUPS)
-           as_fatal ("too many fixups");
+           as_fatal (_("too many fixups"));
          fixups[fc].exp = ex;
          fixups[fc].opindex = *opindex_ptr;
          fixups[fc].reloc = BFD_RELOC_UNUSED;
          fixups[fc].exp = ex;
          fixups[fc].opindex = *opindex_ptr;
          fixups[fc].reloc = BFD_RELOC_UNUSED;
@@ -1549,7 +1959,7 @@ md_assemble (str)
       if (*str != endc
          && (endc != ',' || *str != '\0'))
        {
       if (*str != endc
          && (endc != ',' || *str != '\0'))
        {
-         as_bad ("syntax error; found `%c' but expected `%c'", *str, endc);
+         as_bad (_("syntax error; found `%c' but expected `%c'"), *str, endc);
          break;
        }
 
          break;
        }
 
@@ -1561,7 +1971,7 @@ md_assemble (str)
     ++str;
 
   if (*str != '\0')
     ++str;
 
   if (*str != '\0')
-    as_bad ("junk at end of line: `%s'", str);
+    as_bad (_("junk at end of line: `%s'"), str);
 
   /* Write out the instruction.  */
   f = frag_more (4);
 
   /* Write out the instruction.  */
   f = frag_more (4);
@@ -1602,6 +2012,8 @@ md_assemble (str)
             foo+100000@ha.  */
          switch (fixups[i].reloc)
            {
             foo+100000@ha.  */
          switch (fixups[i].reloc)
            {
+           case BFD_RELOC_16_GOTOFF:
+           case BFD_RELOC_PPC_TOC16:
            case BFD_RELOC_LO16:
            case BFD_RELOC_HI16:
            case BFD_RELOC_HI16_S:
            case BFD_RELOC_LO16:
            case BFD_RELOC_HI16:
            case BFD_RELOC_HI16_S:
@@ -1620,29 +2032,6 @@ md_assemble (str)
     }
 }
 
     }
 }
 
-#ifndef WORKING_DOT_WORD
-/* Handle long and short jumps */
-void
-md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
-     char *ptr;
-     addressT from_addr, to_addr;
-     fragS *frag;
-     symbolS *to_symbol;
-{
-  abort ();
-}
-
-void
-md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
-     char *ptr;
-     addressT from_addr, to_addr;
-     fragS *frag;
-     symbolS *to_symbol;
-{
-  abort ();
-}
-#endif
-
 /* Handle a macro.  Gather all the operands, transform them as
    described by the macro, and call md_assemble recursively.  All the
    operands are separated by commas; we don't accept parentheses
 /* Handle a macro.  Gather all the operands, transform them as
    described by the macro, and call md_assemble recursively.  All the
    operands are separated by commas; we don't accept parentheses
@@ -1678,7 +2067,7 @@ ppc_macro (str, macro)
 
   if (count != macro->operands)
     {
 
   if (count != macro->operands)
     {
-      as_bad ("wrong number of operands");
+      as_bad (_("wrong number of operands"));
       return;
     }
 
       return;
     }
 
@@ -1722,6 +2111,60 @@ ppc_macro (str, macro)
   /* Assemble the constructed instruction.  */
   md_assemble (complete);
 }  
   /* Assemble the constructed instruction.  */
   md_assemble (complete);
 }  
+\f
+#ifdef OBJ_ELF
+/* For ELF, add support for SHF_EXCLUDE and SHT_ORDERED */
+
+int
+ppc_section_letter (letter, ptr_msg)
+     int letter;
+     char **ptr_msg;
+{
+  if (letter == 'e')
+    return SHF_EXCLUDE;
+
+  *ptr_msg = _("Bad .section directive: want a,w,x,e in string");
+  return 0;
+}
+
+int
+ppc_section_word (str, len)
+     char *str;
+     size_t len;
+{
+  if (len == 7 && strncmp (str, "exclude", 7) == 0)
+    return SHF_EXCLUDE;
+
+  return -1;
+}
+
+int
+ppc_section_type (str, len)
+     char *str;
+     size_t len;
+{
+  if (len == 7 && strncmp (str, "ordered", 7) == 0)
+    return SHT_ORDERED;
+
+  return -1;
+}
+
+int
+ppc_section_flags (flags, attr, type)
+     int flags;
+     int attr;
+     int type;
+{
+  if (type == SHT_ORDERED)
+    flags |= SEC_ALLOC | SEC_LOAD | SEC_SORT_ENTRIES;
+
+  if (attr & SHF_EXCLUDE)
+    flags |= SEC_EXCLUDE;
+
+  return flags;
+}
+#endif /* OBJ_ELF */
+
 \f
 /* Pseudo-op handling.  */
 
 \f
 /* Pseudo-op handling.  */
 
@@ -1764,6 +2207,10 @@ ppc_byte (ignore)
 
 /* XCOFF specific pseudo-op handling.  */
 
 
 /* XCOFF specific pseudo-op handling.  */
 
+/* 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;
+
 /* 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 .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.  */
@@ -1790,7 +2237,7 @@ ppc_comm (lcomm)
 
   if (*input_line_pointer != ',')
     {
 
   if (*input_line_pointer != ',')
     {
-      as_bad ("missing size");
+      as_bad (_("missing size"));
       ignore_rest_of_line ();
       return;
     }
       ignore_rest_of_line ();
       return;
     }
@@ -1799,7 +2246,7 @@ ppc_comm (lcomm)
   size = get_absolute_expression ();
   if (size < 0)
     {
   size = get_absolute_expression ();
   if (size < 0)
     {
-      as_bad ("negative size");
+      as_bad (_("negative size"));
       ignore_rest_of_line ();
       return;
     }
       ignore_rest_of_line ();
       return;
     }
@@ -1815,7 +2262,7 @@ ppc_comm (lcomm)
          align = get_absolute_expression ();
          if (align <= 0)
            {
          align = get_absolute_expression ();
          if (align <= 0)
            {
-             as_warn ("ignoring bad alignment");
+             as_warn (_("ignoring bad alignment"));
              align = 3;
            }
        }
              align = 3;
            }
        }
@@ -1840,7 +2287,7 @@ ppc_comm (lcomm)
         argument.  */
       if (*input_line_pointer != ',')
        {
         argument.  */
       if (*input_line_pointer != ',')
        {
-         as_bad ("missing real symbol name");
+         as_bad (_("missing real symbol name"));
          ignore_rest_of_line ();
          return;
        }
          ignore_rest_of_line ();
          return;
        }
@@ -1861,7 +2308,7 @@ ppc_comm (lcomm)
   if (S_IS_DEFINED (sym)
       || S_GET_VALUE (sym) != 0)
     {
   if (S_IS_DEFINED (sym)
       || S_GET_VALUE (sym) != 0)
     {
-      as_bad ("attempt to redefine symbol");
+      as_bad (_("attempt to redefine symbol"));
       ignore_rest_of_line ();
       return;
     }
       ignore_rest_of_line ();
       return;
     }
@@ -1882,38 +2329,38 @@ ppc_comm (lcomm)
        }
       else
        {
        }
       else
        {
-         lcomm_sym->sy_tc.output = 1;
+         symbol_get_tc (lcomm_sym)->output = 1;
          def_sym = lcomm_sym;
          def_size = 0;
        }
 
       subseg_set (bss_section, 1);
          def_sym = lcomm_sym;
          def_size = 0;
        }
 
       subseg_set (bss_section, 1);
-      frag_align (align, 0);
+      frag_align (align, 0, 0);
   
   
-      def_sym->sy_frag = frag_now;
+      symbol_set_frag (def_sym, frag_now);
       pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, def_sym,
                        def_size, (char *) NULL);
       *pfrag = 0;
       S_SET_SEGMENT (def_sym, bss_section);
       pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, def_sym,
                        def_size, (char *) NULL);
       *pfrag = 0;
       S_SET_SEGMENT (def_sym, bss_section);
-      def_sym->sy_tc.align = align;
+      symbol_get_tc (def_sym)->align = align;
     }
   else if (lcomm)
     {
       /* Align the size of lcomm_sym.  */
     }
   else if (lcomm)
     {
       /* Align the size of lcomm_sym.  */
-      lcomm_sym->sy_frag->fr_offset =
-       ((lcomm_sym->sy_frag->fr_offset + (1 << align) - 1)
+      symbol_get_frag (lcomm_sym)->fr_offset =
+       ((symbol_get_frag (lcomm_sym)->fr_offset + (1 << align) - 1)
         &~ ((1 << align) - 1));
         &~ ((1 << align) - 1));
-      if (align > lcomm_sym->sy_tc.align)
-       lcomm_sym->sy_tc.align = align;
+      if (align > symbol_get_tc (lcomm_sym)->align)
+       symbol_get_tc (lcomm_sym)->align = align;
     }
 
   if (lcomm)
     {
       /* Make sym an offset from lcomm_sym.  */
       S_SET_SEGMENT (sym, bss_section);
     }
 
   if (lcomm)
     {
       /* Make sym an offset from lcomm_sym.  */
       S_SET_SEGMENT (sym, bss_section);
-      sym->sy_frag = lcomm_sym->sy_frag;
-      S_SET_VALUE (sym, lcomm_sym->sy_frag->fr_offset);
-      lcomm_sym->sy_frag->fr_offset += size;
+      symbol_set_frag (sym, symbol_get_frag (lcomm_sym));
+      S_SET_VALUE (sym, symbol_get_frag (lcomm_sym)->fr_offset);
+      symbol_get_frag (lcomm_sym)->fr_offset += size;
     }
 
   subseg_set (current_seg, current_subseg);
     }
 
   subseg_set (current_seg, current_subseg);
@@ -1940,21 +2387,45 @@ ppc_csect (ignore)
   
   sym = symbol_find_or_make (name);
 
   
   sym = symbol_find_or_make (name);
 
-  *input_line_pointer = endc;
+  *input_line_pointer = endc;
+
+  if (S_GET_NAME (sym)[0] == '\0')
+    {
+      /* An unnamed csect is assumed to be [PR].  */
+      symbol_get_tc (sym)->class = XMC_PR;
+    }
+
+  ppc_change_csect (sym);
+
+  if (*input_line_pointer == ',')
+    {
+      ++input_line_pointer;
+      symbol_get_tc (sym)->align = get_absolute_expression ();
+    }
+
+  demand_empty_rest_of_line ();
+}
+
+/* Change to a different csect.  */
 
 
+static void
+ppc_change_csect (sym)
+     symbolS *sym;
+{
   if (S_IS_DEFINED (sym))
   if (S_IS_DEFINED (sym))
-    subseg_set (S_GET_SEGMENT (sym), sym->sy_tc.subseg);
+    subseg_set (S_GET_SEGMENT (sym), symbol_get_tc (sym)->subseg);
   else
     {
       symbolS **list_ptr;
       int after_toc;
   else
     {
       symbolS **list_ptr;
       int after_toc;
+      int hold_chunksize;
       symbolS *list;
 
       /* 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;
       symbolS *list;
 
       /* 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;
-      switch (sym->sy_tc.class)
+      switch (symbol_get_tc (sym)->class)
        {
        case XMC_PR:
        case XMC_RO:
        {
        case XMC_PR:
        case XMC_RO:
@@ -1965,7 +2436,7 @@ ppc_csect (ignore)
        case XMC_TI:
        case XMC_TB:
          S_SET_SEGMENT (sym, text_section);
        case XMC_TI:
        case XMC_TB:
          S_SET_SEGMENT (sym, text_section);
-         sym->sy_tc.subseg = ppc_text_subsegment;
+         symbol_get_tc (sym)->subseg = ppc_text_subsegment;
          ++ppc_text_subsegment;
          list_ptr = &ppc_text_csects;
          break;
          ++ppc_text_subsegment;
          list_ptr = &ppc_text_csects;
          break;
@@ -1976,10 +2447,12 @@ ppc_csect (ignore)
        case XMC_UA:
        case XMC_BS:
        case XMC_UC:
        case XMC_UA:
        case XMC_BS:
        case XMC_UC:
-         if (ppc_toc_csect->sy_tc.subseg + 1 == ppc_data_subsegment)
+         if (ppc_toc_csect != NULL
+             && (symbol_get_tc (ppc_toc_csect)->subseg + 1
+                 == ppc_data_subsegment))
            after_toc = 1;
          S_SET_SEGMENT (sym, data_section);
            after_toc = 1;
          S_SET_SEGMENT (sym, data_section);
-         sym->sy_tc.subseg = ppc_data_subsegment;
+         symbol_get_tc (sym)->subseg = ppc_data_subsegment;
          ++ppc_data_subsegment;
          list_ptr = &ppc_data_csects;
          break;
          ++ppc_data_subsegment;
          list_ptr = &ppc_data_csects;
          break;
@@ -1987,34 +2460,99 @@ ppc_csect (ignore)
          abort ();
        }
 
          abort ();
        }
 
-      subseg_new (segment_name (S_GET_SEGMENT (sym)), sym->sy_tc.subseg);
+      /* 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.  */
+      hold_chunksize = chunksize;
+      chunksize = 64;
+
+      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;
 
       if (after_toc)
        ppc_after_toc_frag = frag_now;
 
-      sym->sy_frag = frag_now;
+      symbol_set_frag (sym, frag_now);
       S_SET_VALUE (sym, (valueT) frag_now_fix ());
 
       S_SET_VALUE (sym, (valueT) frag_now_fix ());
 
-      sym->sy_tc.align = 2;
-      sym->sy_tc.output = 1;
-      sym->sy_tc.within = sym;
+      symbol_get_tc (sym)->align = 2;
+      symbol_get_tc (sym)->output = 1;
+      symbol_get_tc (sym)->within = sym;
          
       for (list = *list_ptr;
          
       for (list = *list_ptr;
-          list->sy_tc.next != (symbolS *) NULL;
-          list = list->sy_tc.next)
+          symbol_get_tc (list)->next != (symbolS *) NULL;
+          list = symbol_get_tc (list)->next)
        ;
        ;
-      list->sy_tc.next = sym;
+      symbol_get_tc (list)->next = sym;
          
       symbol_remove (sym, &symbol_rootP, &symbol_lastP);
          
       symbol_remove (sym, &symbol_rootP, &symbol_lastP);
-      symbol_append (sym, list->sy_tc.within, &symbol_rootP, &symbol_lastP);
+      symbol_append (sym, symbol_get_tc (list)->within, &symbol_rootP,
+                    &symbol_lastP);
     }
 
     }
 
-  if (*input_line_pointer == ',')
+  ppc_current_csect = sym;
+}
+
+/* This function handles the .text and .data pseudo-ops.  These
+   pseudo-ops aren't really used by XCOFF; we implement them for the
+   convenience of people who aren't used to XCOFF.  */
+
+static void
+ppc_section (type)
+     int type;
+{
+  const char *name;
+  symbolS *sym;
+
+  if (type == 't')
+    name = ".text[PR]";
+  else if (type == 'd')
+    name = ".data[RW]";
+  else
+    abort ();
+
+  sym = symbol_find_or_make (name);
+
+  ppc_change_csect (sym);
+
+  demand_empty_rest_of_line ();
+}
+
+/* This function handles the .section pseudo-op.  This is mostly to
+   give an error, since XCOFF only supports .text, .data and .bss, but
+   we do permit the user to name the text or data section.  */
+
+static void
+ppc_named_section (ignore)
+     int ignore;
+{
+  char *user_name;
+  const char *real_name;
+  char c;
+  symbolS *sym;
+
+  user_name = input_line_pointer;
+  c = get_symbol_end ();
+
+  if (strcmp (user_name, ".text") == 0)
+    real_name = ".text[PR]";
+  else if (strcmp (user_name, ".data") == 0)
+    real_name = ".data[RW]";
+  else
     {
     {
-      ++input_line_pointer;
-      sym->sy_tc.align = get_absolute_expression ();
+      as_bad (_("The XCOFF file format does not support arbitrary sections"));
+      *input_line_pointer = c;
+      ignore_rest_of_line ();
+      return;
     }
 
     }
 
-  ppc_current_csect = sym;
+  *input_line_pointer = c;
+
+  sym = symbol_find_or_make (real_name);
+
+  ppc_change_csect (sym);
 
   demand_empty_rest_of_line ();
 }
 
   demand_empty_rest_of_line ();
 }
@@ -2038,15 +2576,26 @@ ppc_extern (ignore)
   demand_empty_rest_of_line ();
 }
 
   demand_empty_rest_of_line ();
 }
 
-/* The .lglobl pseudo-op.  I think the RS/6000 assembler only needs
-   this because it can't handle undefined symbols.  I think we can
-   just ignore it.  */
+/* The .lglobl pseudo-op.  Keep the symbol in the symbol table.  */
 
 static void
 ppc_lglobl (ignore)
      int ignore;
 {
 
 static void
 ppc_lglobl (ignore)
      int ignore;
 {
-  s_ignore (0);
+  char *name;
+  char endc;
+  symbolS *sym;
+
+  name = input_line_pointer;
+  endc = get_symbol_end ();
+
+  sym = symbol_find_or_make (name);
+
+  *input_line_pointer = endc;
+
+  symbol_get_tc (sym)->output = 1;
+
+  demand_empty_rest_of_line ();
 }
 
 /* The .rename pseudo-op.  The RS/6000 assembler can rename symbols,
 }
 
 /* The .rename pseudo-op.  The RS/6000 assembler can rename symbols,
@@ -2070,13 +2619,13 @@ ppc_rename (ignore)
 
   if (*input_line_pointer != ',')
     {
 
   if (*input_line_pointer != ',')
     {
-      as_bad ("missing rename string");
+      as_bad (_("missing rename string"));
       ignore_rest_of_line ();
       return;
     }
   ++input_line_pointer;
 
       ignore_rest_of_line ();
       return;
     }
   ++input_line_pointer;
 
-  sym->sy_tc.real_name = demand_copy_C_string (&len);
+  symbol_get_tc (sym)->real_name = demand_copy_C_string (&len);
 
   demand_empty_rest_of_line ();
 }
 
   demand_empty_rest_of_line ();
 }
@@ -2101,12 +2650,16 @@ ppc_stabx (ignore)
 
   if (*input_line_pointer != ',')
     {
 
   if (*input_line_pointer != ',')
     {
-      as_bad ("missing value");
+      as_bad (_("missing value"));
       return;
     }
   ++input_line_pointer;
 
       return;
     }
   ++input_line_pointer;
 
+  ppc_stab_symbol = true;
   sym = symbol_make (name);
   sym = symbol_make (name);
+  ppc_stab_symbol = false;
+
+  symbol_get_tc (sym)->real_name = name;
 
   (void) expression (&exp);
 
 
   (void) expression (&exp);
 
@@ -2115,22 +2668,22 @@ ppc_stabx (ignore)
     case O_illegal:
     case O_absent:
     case O_big:
     case O_illegal:
     case O_absent:
     case O_big:
-      as_bad ("illegal .stabx expression; zero assumed");
+      as_bad (_("illegal .stabx expression; zero assumed"));
       exp.X_add_number = 0;
       /* Fall through.  */
     case O_constant:
       S_SET_VALUE (sym, (valueT) exp.X_add_number);
       exp.X_add_number = 0;
       /* Fall through.  */
     case O_constant:
       S_SET_VALUE (sym, (valueT) exp.X_add_number);
-      sym->sy_frag = &zero_address_frag;
+      symbol_set_frag (sym, &zero_address_frag);
       break;
 
     case O_symbol:
       if (S_GET_SEGMENT (exp.X_add_symbol) == undefined_section)
       break;
 
     case O_symbol:
       if (S_GET_SEGMENT (exp.X_add_symbol) == undefined_section)
-       sym->sy_value = exp;
+       symbol_set_value_expression (sym, &exp);
       else
        {
          S_SET_VALUE (sym,
                       exp.X_add_number + S_GET_VALUE (exp.X_add_symbol));
       else
        {
          S_SET_VALUE (sym,
                       exp.X_add_number + S_GET_VALUE (exp.X_add_symbol));
-         sym->sy_frag = exp.X_add_symbol->sy_frag;
+         symbol_set_frag (sym, symbol_get_frag (exp.X_add_symbol));
        }
       break;
 
        }
       break;
 
@@ -2138,16 +2691,16 @@ ppc_stabx (ignore)
       /* The value is some complex expression.  This will probably
          fail at some later point, but this is probably the right
          thing to do here.  */
       /* The value is some complex expression.  This will probably
          fail at some later point, but this is probably the right
          thing to do here.  */
-      sym->sy_value = exp;
+      symbol_set_value_expression (sym, &exp);
       break;
     }
 
   S_SET_SEGMENT (sym, ppc_coff_debug_section);
       break;
     }
 
   S_SET_SEGMENT (sym, ppc_coff_debug_section);
-  sym->bsym->flags |= BSF_DEBUGGING;
+  symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
 
   if (*input_line_pointer != ',')
     {
 
   if (*input_line_pointer != ',')
     {
-      as_bad ("missing class");
+      as_bad (_("missing class"));
       return;
     }
   ++input_line_pointer;
       return;
     }
   ++input_line_pointer;
@@ -2156,17 +2709,17 @@ ppc_stabx (ignore)
 
   if (*input_line_pointer != ',')
     {
 
   if (*input_line_pointer != ',')
     {
-      as_bad ("missing type");
+      as_bad (_("missing type"));
       return;
     }
   ++input_line_pointer;
 
   S_SET_DATA_TYPE (sym, get_absolute_expression ());
 
       return;
     }
   ++input_line_pointer;
 
   S_SET_DATA_TYPE (sym, get_absolute_expression ());
 
-  sym->sy_tc.output = 1;
+  symbol_get_tc (sym)->output = 1;
 
   if (S_GET_STORAGE_CLASS (sym) == C_STSYM)
 
   if (S_GET_STORAGE_CLASS (sym) == C_STSYM)
-    sym->sy_tc.within = ppc_current_block;
+    symbol_get_tc (sym)->within = ppc_current_block;
 
   if (exp.X_op != O_symbol
       || ! S_IS_EXTERNAL (exp.X_add_symbol)
 
   if (exp.X_op != O_symbol
       || ! S_IS_EXTERNAL (exp.X_add_symbol)
@@ -2176,15 +2729,8 @@ ppc_stabx (ignore)
     {
       symbol_remove (sym, &symbol_rootP, &symbol_lastP);
       symbol_append (sym, exp.X_add_symbol, &symbol_rootP, &symbol_lastP);
     {
       symbol_remove (sym, &symbol_rootP, &symbol_lastP);
       symbol_append (sym, exp.X_add_symbol, &symbol_rootP, &symbol_lastP);
-      if (ppc_current_csect->sy_tc.within == exp.X_add_symbol)
-       ppc_current_csect->sy_tc.within = sym;
-    }
-
-  if (strlen (name) > SYMNMLEN)
-    {
-      /* For some reason, each name is preceded by a two byte length
-        and followed by a null byte.  */
-      ppc_debug_name_section_size += strlen (name) + 3;
+      if (symbol_get_tc (ppc_current_csect)->within == exp.X_add_symbol)
+       symbol_get_tc (ppc_current_csect)->within = sym;
     }
 
   demand_empty_rest_of_line ();
     }
 
   demand_empty_rest_of_line ();
@@ -2224,7 +2770,7 @@ ppc_function (ignore)
 
   if (*input_line_pointer != ',')
     {
 
   if (*input_line_pointer != ',')
     {
-      as_bad ("missing symbol name");
+      as_bad (_("missing symbol name"));
       ignore_rest_of_line ();
       return;
     }
       ignore_rest_of_line ();
       return;
     }
@@ -2239,15 +2785,19 @@ ppc_function (ignore)
 
   if (ext_sym != lab_sym)
     {
 
   if (ext_sym != lab_sym)
     {
-      ext_sym->sy_value.X_op = O_symbol;
-      ext_sym->sy_value.X_add_symbol = lab_sym;
-      ext_sym->sy_value.X_op_symbol = NULL;
-      ext_sym->sy_value.X_add_number = 0;
+      expressionS exp;
+
+      exp.X_op = O_symbol;
+      exp.X_add_symbol = lab_sym;
+      exp.X_op_symbol = NULL;
+      exp.X_add_number = 0;
+      exp.X_unsigned = 0;
+      symbol_set_value_expression (ext_sym, &exp);
     }
 
     }
 
-  if (ext_sym->sy_tc.class == -1)
-    ext_sym->sy_tc.class = XMC_PR;
-  ext_sym->sy_tc.output = 1;
+  if (symbol_get_tc (ext_sym)->class == -1)
+    symbol_get_tc (ext_sym)->class = XMC_PR;
+  symbol_get_tc (ext_sym)->output = 1;
 
   if (*input_line_pointer == ',')
     {
 
   if (*input_line_pointer == ',')
     {
@@ -2265,11 +2815,11 @@ ppc_function (ignore)
            {
              /* The fifth argument is the function size.  */
              ++input_line_pointer;
            {
              /* The fifth argument is the function size.  */
              ++input_line_pointer;
-             ext_sym->sy_tc.size = symbol_new ("L0\001",
-                                               absolute_section,
-                                               (valueT) 0,
-                                               &zero_address_frag);
-             pseudo_set (ext_sym->sy_tc.size);
+             symbol_get_tc (ext_sym)->size = symbol_new ("L0\001",
+                                                         absolute_section,
+                                                         (valueT) 0,
+                                                         &zero_address_frag);
+             pseudo_set (symbol_get_tc (ext_sym)->size);
            }
        }
     }
            }
        }
     }
@@ -2293,7 +2843,7 @@ ppc_bf (ignore)
 
   sym = symbol_make (".bf");
   S_SET_SEGMENT (sym, text_section);
 
   sym = symbol_make (".bf");
   S_SET_SEGMENT (sym, text_section);
-  sym->sy_frag = frag_now;
+  symbol_set_frag (sym, frag_now);
   S_SET_VALUE (sym, frag_now_fix ());
   S_SET_STORAGE_CLASS (sym, C_FCN);
 
   S_SET_VALUE (sym, frag_now_fix ());
   S_SET_STORAGE_CLASS (sym, C_FCN);
 
@@ -2302,7 +2852,7 @@ ppc_bf (ignore)
   S_SET_NUMBER_AUXILIARY (sym, 1);
   SA_SET_SYM_LNNO (sym, coff_line_base);
 
   S_SET_NUMBER_AUXILIARY (sym, 1);
   SA_SET_SYM_LNNO (sym, coff_line_base);
 
-  sym->sy_tc.output = 1;
+  symbol_get_tc (sym)->output = 1;
 
   ppc_frob_label (sym);
 
 
   ppc_frob_label (sym);
 
@@ -2321,12 +2871,12 @@ ppc_ef (ignore)
 
   sym = symbol_make (".ef");
   S_SET_SEGMENT (sym, text_section);
 
   sym = symbol_make (".ef");
   S_SET_SEGMENT (sym, text_section);
-  sym->sy_frag = frag_now;
+  symbol_set_frag (sym, frag_now);
   S_SET_VALUE (sym, frag_now_fix ());
   S_SET_STORAGE_CLASS (sym, C_FCN);
   S_SET_NUMBER_AUXILIARY (sym, 1);
   SA_SET_SYM_LNNO (sym, get_absolute_expression ());
   S_SET_VALUE (sym, frag_now_fix ());
   S_SET_STORAGE_CLASS (sym, C_FCN);
   S_SET_NUMBER_AUXILIARY (sym, 1);
   SA_SET_SYM_LNNO (sym, get_absolute_expression ());
-  sym->sy_tc.output = 1;
+  symbol_get_tc (sym)->output = 1;
 
   ppc_frob_label (sym);
 
 
   ppc_frob_label (sym);
 
@@ -2341,6 +2891,8 @@ static void
 ppc_biei (ei)
      int ei;
 {
 ppc_biei (ei)
      int ei;
 {
+  static symbolS *last_biei;
+
   char *name;
   int len;
   symbolS *sym;
   char *name;
   int len;
   symbolS *sym;
@@ -2354,18 +2906,16 @@ ppc_biei (ei)
      to do the right thing.  */
 
   sym = symbol_make (name);
      to do the right thing.  */
 
   sym = symbol_make (name);
-  S_SET_SEGMENT (sym, now_seg);
-  S_SET_VALUE (sym, coff_n_line_nos);
-  sym->bsym->flags |= BSF_DEBUGGING;
-
   /* obj-coff.c currently only handles line numbers correctly in the
      .text section.  */
   /* obj-coff.c currently only handles line numbers correctly in the
      .text section.  */
-  assert (now_seg == text_section);
+  S_SET_SEGMENT (sym, text_section);
+  S_SET_VALUE (sym, coff_n_line_nos);
+  symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
 
   S_SET_STORAGE_CLASS (sym, ei ? C_EINCL : C_BINCL);
 
   S_SET_STORAGE_CLASS (sym, ei ? C_EINCL : C_BINCL);
-  sym->sy_tc.output = 1;
+  symbol_get_tc (sym)->output = 1;
   
   
-  for (look = symbol_rootP;
+  for (look = last_biei ? last_biei : symbol_rootP;
        (look != (symbolS *) NULL
        && (S_GET_STORAGE_CLASS (look) == C_FILE
            || S_GET_STORAGE_CLASS (look) == C_BINCL
        (look != (symbolS *) NULL
        && (S_GET_STORAGE_CLASS (look) == C_FILE
            || S_GET_STORAGE_CLASS (look) == C_BINCL
@@ -2376,6 +2926,7 @@ ppc_biei (ei)
     {
       symbol_remove (sym, &symbol_rootP, &symbol_lastP);
       symbol_insert (sym, look, &symbol_rootP, &symbol_lastP);
     {
       symbol_remove (sym, &symbol_rootP, &symbol_lastP);
       symbol_insert (sym, look, &symbol_rootP, &symbol_lastP);
+      last_biei = sym;
     }
 
   demand_empty_rest_of_line ();
     }
 
   demand_empty_rest_of_line ();
@@ -2395,7 +2946,7 @@ ppc_bs (ignore)
   symbolS *sym;
 
   if (ppc_current_block != NULL)
   symbolS *sym;
 
   if (ppc_current_block != NULL)
-    as_bad ("nested .bs blocks");
+    as_bad (_("nested .bs blocks"));
 
   name = input_line_pointer;
   endc = get_symbol_end ();
 
   name = input_line_pointer;
   endc = get_symbol_end ();
@@ -2407,10 +2958,10 @@ ppc_bs (ignore)
   sym = symbol_make (".bs");
   S_SET_SEGMENT (sym, now_seg);
   S_SET_STORAGE_CLASS (sym, C_BSTAT);
   sym = symbol_make (".bs");
   S_SET_SEGMENT (sym, now_seg);
   S_SET_STORAGE_CLASS (sym, C_BSTAT);
-  sym->bsym->flags |= BSF_DEBUGGING;
-  sym->sy_tc.output = 1;
+  symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
+  symbol_get_tc (sym)->output = 1;
 
 
-  sym->sy_tc.within = csect;
+  symbol_get_tc (sym)->within = csect;
 
   ppc_frob_label (sym);
 
 
   ppc_frob_label (sym);
 
@@ -2428,13 +2979,13 @@ ppc_es (ignore)
   symbolS *sym;
 
   if (ppc_current_block == NULL)
   symbolS *sym;
 
   if (ppc_current_block == NULL)
-    as_bad (".es without preceding .bs");
+    as_bad (_(".es without preceding .bs"));
 
   sym = symbol_make (".es");
   S_SET_SEGMENT (sym, now_seg);
   S_SET_STORAGE_CLASS (sym, C_ESTAT);
 
   sym = symbol_make (".es");
   S_SET_SEGMENT (sym, now_seg);
   S_SET_STORAGE_CLASS (sym, C_ESTAT);
-  sym->bsym->flags |= BSF_DEBUGGING;
-  sym->sy_tc.output = 1;
+  symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
+  symbol_get_tc (sym)->output = 1;
 
   ppc_frob_label (sym);
 
 
   ppc_frob_label (sym);
 
@@ -2454,14 +3005,16 @@ ppc_bb (ignore)
 
   sym = symbol_make (".bb");
   S_SET_SEGMENT (sym, text_section);
 
   sym = symbol_make (".bb");
   S_SET_SEGMENT (sym, text_section);
-  sym->sy_frag = frag_now;
+  symbol_set_frag (sym, frag_now);
   S_SET_VALUE (sym, frag_now_fix ());
   S_SET_STORAGE_CLASS (sym, C_BLOCK);
 
   S_SET_NUMBER_AUXILIARY (sym, 1);
   SA_SET_SYM_LNNO (sym, get_absolute_expression ());
 
   S_SET_VALUE (sym, frag_now_fix ());
   S_SET_STORAGE_CLASS (sym, C_BLOCK);
 
   S_SET_NUMBER_AUXILIARY (sym, 1);
   SA_SET_SYM_LNNO (sym, get_absolute_expression ());
 
-  sym->sy_tc.output = 1;
+  symbol_get_tc (sym)->output = 1;
+
+  SF_SET_PROCESS (sym);
 
   ppc_frob_label (sym);
 
 
   ppc_frob_label (sym);
 
@@ -2479,12 +3032,58 @@ ppc_eb (ignore)
 
   sym = symbol_make (".eb");
   S_SET_SEGMENT (sym, text_section);
 
   sym = symbol_make (".eb");
   S_SET_SEGMENT (sym, text_section);
-  sym->sy_frag = frag_now;
+  symbol_set_frag (sym, frag_now);
   S_SET_VALUE (sym, frag_now_fix ());
   S_SET_VALUE (sym, frag_now_fix ());
-  S_SET_STORAGE_CLASS (sym, C_FCN);
+  S_SET_STORAGE_CLASS (sym, C_BLOCK);
   S_SET_NUMBER_AUXILIARY (sym, 1);
   SA_SET_SYM_LNNO (sym, get_absolute_expression ());
   S_SET_NUMBER_AUXILIARY (sym, 1);
   SA_SET_SYM_LNNO (sym, get_absolute_expression ());
-  sym->sy_tc.output = 1;
+  symbol_get_tc (sym)->output = 1;
+
+  SF_SET_PROCESS (sym);
+
+  ppc_frob_label (sym);
+
+  demand_empty_rest_of_line ();
+}
+
+/* The .bc pseudo-op.  This just creates a C_BCOMM symbol with a
+   specified name.  */
+
+static void
+ppc_bc (ignore)
+     int ignore;
+{
+  char *name;
+  int len;
+  symbolS *sym;
+
+  name = demand_copy_C_string (&len);
+  sym = symbol_make (name);
+  S_SET_SEGMENT (sym, ppc_coff_debug_section);
+  symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
+  S_SET_STORAGE_CLASS (sym, C_BCOMM);
+  S_SET_VALUE (sym, 0);
+  symbol_get_tc (sym)->output = 1;
+
+  ppc_frob_label (sym);
+
+  demand_empty_rest_of_line ();
+}
+
+/* The .ec pseudo-op.  This just creates a C_ECOMM symbol.  */
+
+static void
+ppc_ec (ignore)
+     int ignore;
+{
+  symbolS *sym;
+
+  sym = symbol_make (".ec");
+  S_SET_SEGMENT (sym, ppc_coff_debug_section);
+  symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING;
+  S_SET_STORAGE_CLASS (sym, C_ECOMM);
+  S_SET_VALUE (sym, 0);
+  symbol_get_tc (sym)->output = 1;
 
   ppc_frob_label (sym);
 
 
   ppc_frob_label (sym);
 
@@ -2498,7 +3097,7 @@ ppc_toc (ignore)
      int ignore;
 {
   if (ppc_toc_csect != (symbolS *) NULL)
      int ignore;
 {
   if (ppc_toc_csect != (symbolS *) NULL)
-    subseg_set (data_section, ppc_toc_csect->sy_tc.subseg);
+    subseg_set (data_section, symbol_get_tc (ppc_toc_csect)->subseg);
   else
     {
       subsegT subseg;
   else
     {
       subsegT subseg;
@@ -2512,23 +3111,24 @@ ppc_toc (ignore)
       ppc_toc_frag = frag_now;
 
       sym = symbol_find_or_make ("TOC[TC0]");
       ppc_toc_frag = frag_now;
 
       sym = symbol_find_or_make ("TOC[TC0]");
-      sym->sy_frag = frag_now;
+      symbol_set_frag (sym, frag_now);
       S_SET_SEGMENT (sym, data_section);
       S_SET_VALUE (sym, (valueT) frag_now_fix ());
       S_SET_SEGMENT (sym, data_section);
       S_SET_VALUE (sym, (valueT) frag_now_fix ());
-      sym->sy_tc.subseg = subseg;
-      sym->sy_tc.output = 1;
-      sym->sy_tc.within = sym;
+      symbol_get_tc (sym)->subseg = subseg;
+      symbol_get_tc (sym)->output = 1;
+      symbol_get_tc (sym)->within = sym;
 
       ppc_toc_csect = sym;
          
       for (list = ppc_data_csects;
 
       ppc_toc_csect = sym;
          
       for (list = ppc_data_csects;
-          list->sy_tc.next != (symbolS *) NULL;
-          list = list->sy_tc.next)
+          symbol_get_tc (list)->next != (symbolS *) NULL;
+          list = symbol_get_tc (list)->next)
        ;
        ;
-      list->sy_tc.next = sym;
+      symbol_get_tc (list)->next = sym;
 
       symbol_remove (sym, &symbol_rootP, &symbol_lastP);
 
       symbol_remove (sym, &symbol_rootP, &symbol_lastP);
-      symbol_append (sym, list->sy_tc.within, &symbol_rootP, &symbol_lastP);
+      symbol_append (sym, symbol_get_tc (list)->within, &symbol_rootP,
+                    &symbol_lastP);
     }
 
   ppc_current_csect = ppc_toc_csect;
     }
 
   ppc_current_csect = ppc_toc_csect;
@@ -2536,6 +3136,45 @@ ppc_toc (ignore)
   demand_empty_rest_of_line ();
 }
 
   demand_empty_rest_of_line ();
 }
 
+/* The AIX assembler automatically aligns the operands of a .long or
+   .short pseudo-op, and we want to be compatible.  */
+
+static void
+ppc_xcoff_cons (log_size)
+     int log_size;
+{
+  frag_align (log_size, 0, 0);
+  record_alignment (now_seg, log_size);
+  cons (1 << log_size);
+}
+
+static void
+ppc_vbyte (dummy)
+     int dummy;
+{
+  expressionS exp;
+  int byte_count;
+
+  (void) expression (&exp);
+
+  if (exp.X_op != O_constant)
+    {
+      as_bad (_("non-constant byte count"));
+      return;
+    }
+
+  byte_count = exp.X_add_number;
+
+  if (*input_line_pointer != ',')
+    {
+      as_bad (_("missing value"));
+      return;
+    }
+
+  ++input_line_pointer;
+  cons (byte_count);
+}
+
 #endif /* OBJ_XCOFF */
 \f
 /* The .tc pseudo-op.  This is used when generating either XCOFF or
 #endif /* OBJ_XCOFF */
 \f
 /* The .tc pseudo-op.  This is used when generating either XCOFF or
@@ -2565,7 +3204,7 @@ ppc_tc (ignore)
     if (ppc_toc_csect == (symbolS *) NULL
        || ppc_toc_csect != ppc_current_csect)
       {
     if (ppc_toc_csect == (symbolS *) NULL
        || ppc_toc_csect != ppc_current_csect)
       {
-       as_bad (".tc not in .toc section");
+       as_bad (_(".tc not in .toc section"));
        ignore_rest_of_line ();
        return;
       }
        ignore_rest_of_line ();
        return;
       }
@@ -2581,16 +3220,16 @@ ppc_tc (ignore)
       {
        symbolS *label;
 
       {
        symbolS *label;
 
-       label = ppc_current_csect->sy_tc.within;
-       if (label->sy_tc.class != XMC_TC0)
+       label = symbol_get_tc (ppc_current_csect)->within;
+       if (symbol_get_tc (label)->class != XMC_TC0)
          {
          {
-           as_warn (".tc with no label");
+           as_bad (_(".tc with no label"));
            ignore_rest_of_line ();
            return;
          }
 
        S_SET_SEGMENT (label, S_GET_SEGMENT (sym));
            ignore_rest_of_line ();
            return;
          }
 
        S_SET_SEGMENT (label, S_GET_SEGMENT (sym));
-       label->sy_frag = sym->sy_frag;
+       symbol_set_frag (label, symbol_get_frag (sym));
        S_SET_VALUE (label, S_GET_VALUE (sym));
 
        while (! is_end_of_line[(unsigned char) *input_line_pointer])
        S_SET_VALUE (label, S_GET_VALUE (sym));
 
        while (! is_end_of_line[(unsigned char) *input_line_pointer])
@@ -2600,10 +3239,10 @@ ppc_tc (ignore)
       }
 
     S_SET_SEGMENT (sym, now_seg);
       }
 
     S_SET_SEGMENT (sym, now_seg);
-    sym->sy_frag = frag_now;
+    symbol_set_frag (sym, frag_now);
     S_SET_VALUE (sym, (valueT) frag_now_fix ());
     S_SET_VALUE (sym, (valueT) frag_now_fix ());
-    sym->sy_tc.class = XMC_TC;
-    sym->sy_tc.output = 1;
+    symbol_get_tc (sym)->class = XMC_TC;
+    symbol_get_tc (sym)->output = 1;
 
     ppc_frob_label (sym);
   }
 
     ppc_frob_label (sym);
   }
@@ -2619,7 +3258,7 @@ ppc_tc (ignore)
     ++input_line_pointer;
 
   /* Align to a four byte boundary.  */
     ++input_line_pointer;
 
   /* Align to a four byte boundary.  */
-  frag_align (2, 0);
+  frag_align (2, 0, 0);
   record_alignment (now_seg, 2);
 
 #endif /* ! defined (OBJ_XCOFF) */
   record_alignment (now_seg, 2);
 
 #endif /* ! defined (OBJ_XCOFF) */
@@ -2659,7 +3298,7 @@ ppc_previous(ignore)
 
   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;
     }
 
       return;
     }
 
@@ -2696,7 +3335,7 @@ ppc_pdata(ignore)
                             (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, pdata_section, 3);
+      bfd_set_section_alignment (stdoutput, pdata_section, 2);
     }
   else
     {
     }
   else
     {
@@ -2768,7 +3407,7 @@ ppc_reldata(ignore)
                             ( SEC_ALLOC | SEC_LOAD | SEC_RELOC 
                              | SEC_DATA ));
 
                             ( SEC_ALLOC | SEC_LOAD | SEC_RELOC 
                              | SEC_DATA ));
 
-      bfd_set_section_alignment (stdoutput, reldata_section, 3);
+      bfd_set_section_alignment (stdoutput, reldata_section, 2);
     }
   else
     {
     }
   else
     {
@@ -2904,7 +3543,7 @@ ppc_pe_comm(lcomm)
   SKIP_WHITESPACE ();
   if (*input_line_pointer != ',')
     {
   SKIP_WHITESPACE ();
   if (*input_line_pointer != ',')
     {
-      as_bad ("Expected comma after symbol-name: rest of line ignored.");
+      as_bad (_("Expected comma after symbol-name: rest of line ignored."));
       ignore_rest_of_line ();
       return;
     }
       ignore_rest_of_line ();
       return;
     }
@@ -2912,7 +3551,7 @@ ppc_pe_comm(lcomm)
   input_line_pointer++;                /* skip ',' */
   if ((temp = get_absolute_expression ()) < 0)
     {
   input_line_pointer++;                /* skip ',' */
   if ((temp = get_absolute_expression ()) < 0)
     {
-      as_warn (".COMMon length (%ld.) <0! Ignored.", (long) temp);
+      as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) temp);
       ignore_rest_of_line ();
       return;
     }
       ignore_rest_of_line ();
       return;
     }
@@ -2928,7 +3567,7 @@ ppc_pe_comm(lcomm)
          align = get_absolute_expression ();
          if (align <= 0)
            {
          align = get_absolute_expression ();
          if (align <= 0)
            {
-             as_warn ("ignoring bad alignment");
+             as_warn (_("ignoring bad alignment"));
              align = 3;
            }
        }
              align = 3;
            }
        }
@@ -2938,9 +3577,9 @@ ppc_pe_comm(lcomm)
   symbolP = symbol_find_or_make (name);
 
   *p = c;
   symbolP = symbol_find_or_make (name);
 
   *p = c;
-  if (S_IS_DEFINED (symbolP))
+  if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP))
     {
     {
-      as_bad ("Ignoring attempt to re-define symbol `%s'.",
+      as_bad (_("Ignoring attempt to re-define symbol `%s'."),
              S_GET_NAME (symbolP));
       ignore_rest_of_line ();
       return;
              S_GET_NAME (symbolP));
       ignore_rest_of_line ();
       return;
@@ -2949,7 +3588,7 @@ ppc_pe_comm(lcomm)
   if (S_GET_VALUE (symbolP))
     {
       if (S_GET_VALUE (symbolP) != (valueT) temp)
   if (S_GET_VALUE (symbolP))
     {
       if (S_GET_VALUE (symbolP) != (valueT) temp)
-       as_bad ("Length of .comm \"%s\" is already %ld. Not changed to %ld.",
+       as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."),
                S_GET_NAME (symbolP),
                (long) S_GET_VALUE (symbolP),
                (long) temp);
                S_GET_NAME (symbolP),
                (long) S_GET_VALUE (symbolP),
                (long) temp);
@@ -3026,8 +3665,6 @@ ppc_pe_section (ignore)
   segT sec;
   int align;
 
   segT sec;
   int align;
 
-  align = 4; /* default alignment to 16 byte boundary */
-
   section_name = input_line_pointer;
   c = get_symbol_end ();
 
   section_name = input_line_pointer;
   c = get_symbol_end ();
 
@@ -3041,6 +3678,29 @@ ppc_pe_section (ignore)
   exp = 0;
   flags = SEC_NO_FLAGS;
 
   exp = 0;
   flags = SEC_NO_FLAGS;
 
+  if (strcmp (name, ".idata$2") == 0)
+    {
+      align = 0;
+    }
+  else if (strcmp (name, ".idata$3") == 0)
+    {
+      align = 0;
+    }
+  else if (strcmp (name, ".idata$4") == 0)
+    {
+      align = 2;
+    }
+  else if (strcmp (name, ".idata$5") == 0)
+    {
+      align = 2;
+    }
+  else if (strcmp (name, ".idata$6") == 0)
+    {
+      align = 1;
+    }
+  else
+    align = 4; /* default alignment to 16 byte boundary */
+
   if (*input_line_pointer == ',')
     {
       ++input_line_pointer;
   if (*input_line_pointer == ',')
     {
       ++input_line_pointer;
@@ -3057,7 +3717,7 @@ ppc_pe_section (ignore)
                {
                  /* Section Contents */
                case 'a': /* unknown */
                {
                  /* Section Contents */
                case 'a': /* unknown */
-                 as_warn ("Unsupported section attribute -- 'a'");
+                 as_bad (_("Unsupported section attribute -- 'a'"));
                  break;
                case 'c': /* code section */
                  flags |= SEC_CODE; 
                  break;
                case 'c': /* code section */
                  flags |= SEC_CODE; 
@@ -3127,8 +3787,8 @@ ppc_pe_section (ignore)
                  break;
 
                default:
                  break;
 
                default:
-                 as_warn("unknown section attribute '%c'",
-                         *input_line_pointer);
+                 as_bad(_("unknown section attribute '%c'"),
+                        *input_line_pointer);
                  break;
                }
              ++input_line_pointer;
                  break;
                }
              ++input_line_pointer;
@@ -3145,9 +3805,9 @@ ppc_pe_section (ignore)
   if (flags != SEC_NO_FLAGS)
     {
       if (! bfd_set_section_flags (stdoutput, sec, flags))
   if (flags != SEC_NO_FLAGS)
     {
       if (! bfd_set_section_flags (stdoutput, sec, flags))
-       as_warn ("error setting flags for \"%s\": %s",
-                bfd_section_name (stdoutput, sec),
-                bfd_errmsg (bfd_get_error ()));
+       as_bad (_("error setting flags for \"%s\": %s"),
+               bfd_section_name (stdoutput, sec),
+               bfd_errmsg (bfd_get_error ()));
     }
 
   bfd_set_section_alignment(stdoutput, sec, align);
     }
 
   bfd_set_section_alignment(stdoutput, sec, align);
@@ -3225,6 +3885,9 @@ ppc_canonicalize_symbol_name (name)
 {
   char *s;
 
 {
   char *s;
 
+  if (ppc_stab_symbol)
+    return name;
+
   for (s = name; *s != '\0' && *s != '{' && *s != '['; s++)
     ;
   if (*s != '\0')
   for (s = name; *s != '\0' && *s != '{' && *s != '['; s++)
     ;
   if (*s != '\0')
@@ -3244,7 +3907,7 @@ ppc_canonicalize_symbol_name (name)
          *s = toupper (*s);
 
       if (*s == '\0' || s[1] != '\0')
          *s = toupper (*s);
 
       if (*s == '\0' || s[1] != '\0')
-       as_bad ("bad symbol suffix");
+       as_bad (_("bad symbol suffix"));
 
       *s = ']';
     }
 
       *s = ']';
     }
@@ -3259,16 +3922,21 @@ void
 ppc_symbol_new_hook (sym)
      symbolS *sym;
 {
 ppc_symbol_new_hook (sym)
      symbolS *sym;
 {
+  struct ppc_tc_sy *tc;
   const char *s;
 
   const char *s;
 
-  sym->sy_tc.next = NULL;
-  sym->sy_tc.output = 0;
-  sym->sy_tc.class = -1;
-  sym->sy_tc.real_name = NULL;
-  sym->sy_tc.subseg = 0;
-  sym->sy_tc.align = 0;
-  sym->sy_tc.size = NULL;
-  sym->sy_tc.within = NULL;
+  tc = symbol_get_tc (sym);
+  tc->next = NULL;
+  tc->output = 0;
+  tc->class = -1;
+  tc->real_name = NULL;
+  tc->subseg = 0;
+  tc->align = 0;
+  tc->size = NULL;
+  tc->within = NULL;
+
+  if (ppc_stab_symbol)
+    return;
 
   s = strchr (S_GET_NAME (sym), '[');
   if (s == (const char *) NULL)
 
   s = strchr (S_GET_NAME (sym), '[');
   if (s == (const char *) NULL)
@@ -3283,56 +3951,56 @@ ppc_symbol_new_hook (sym)
     {
     case 'B':
       if (strcmp (s, "BS]") == 0)
     {
     case 'B':
       if (strcmp (s, "BS]") == 0)
-       sym->sy_tc.class = XMC_BS;
+       tc->class = XMC_BS;
       break;
     case 'D':
       if (strcmp (s, "DB]") == 0)
       break;
     case 'D':
       if (strcmp (s, "DB]") == 0)
-       sym->sy_tc.class = XMC_DB;
+       tc->class = XMC_DB;
       else if (strcmp (s, "DS]") == 0)
       else if (strcmp (s, "DS]") == 0)
-       sym->sy_tc.class = XMC_DS;
+       tc->class = XMC_DS;
       break;
     case 'G':
       if (strcmp (s, "GL]") == 0)
       break;
     case 'G':
       if (strcmp (s, "GL]") == 0)
-       sym->sy_tc.class = XMC_GL;
+       tc->class = XMC_GL;
       break;
     case 'P':
       if (strcmp (s, "PR]") == 0)
       break;
     case 'P':
       if (strcmp (s, "PR]") == 0)
-       sym->sy_tc.class = XMC_PR;
+       tc->class = XMC_PR;
       break;
     case 'R':
       if (strcmp (s, "RO]") == 0)
       break;
     case 'R':
       if (strcmp (s, "RO]") == 0)
-       sym->sy_tc.class = XMC_RO;
+       tc->class = XMC_RO;
       else if (strcmp (s, "RW]") == 0)
       else if (strcmp (s, "RW]") == 0)
-       sym->sy_tc.class = XMC_RW;
+       tc->class = XMC_RW;
       break;
     case 'S':
       if (strcmp (s, "SV]") == 0)
       break;
     case 'S':
       if (strcmp (s, "SV]") == 0)
-       sym->sy_tc.class = XMC_SV;
+       tc->class = XMC_SV;
       break;
     case 'T':
       if (strcmp (s, "TC]") == 0)
       break;
     case 'T':
       if (strcmp (s, "TC]") == 0)
-       sym->sy_tc.class = XMC_TC;
+       tc->class = XMC_TC;
       else if (strcmp (s, "TI]") == 0)
       else if (strcmp (s, "TI]") == 0)
-       sym->sy_tc.class = XMC_TI;
+       tc->class = XMC_TI;
       else if (strcmp (s, "TB]") == 0)
       else if (strcmp (s, "TB]") == 0)
-       sym->sy_tc.class = XMC_TB;
+       tc->class = XMC_TB;
       else if (strcmp (s, "TC0]") == 0 || strcmp (s, "T0]") == 0)
       else if (strcmp (s, "TC0]") == 0 || strcmp (s, "T0]") == 0)
-       sym->sy_tc.class = XMC_TC0;
+       tc->class = XMC_TC0;
       break;
     case 'U':
       if (strcmp (s, "UA]") == 0)
       break;
     case 'U':
       if (strcmp (s, "UA]") == 0)
-       sym->sy_tc.class = XMC_UA;
+       tc->class = XMC_UA;
       else if (strcmp (s, "UC]") == 0)
       else if (strcmp (s, "UC]") == 0)
-       sym->sy_tc.class = XMC_UC;
+       tc->class = XMC_UC;
       break;
     case 'X':
       if (strcmp (s, "XO]") == 0)
       break;
     case 'X':
       if (strcmp (s, "XO]") == 0)
-       sym->sy_tc.class = XMC_XO;
+       tc->class = XMC_XO;
       break;
     }
 
       break;
     }
 
-  if (sym->sy_tc.class == -1)
-    as_bad ("Unrecognized symbol suffix");
+  if (tc->class == -1)
+    as_bad (_("Unrecognized symbol suffix"));
 }
 
 /* Set the class of a label based on where it is defined.  This
 }
 
 /* Set the class of a label based on where it is defined.  This
@@ -3345,16 +4013,22 @@ ppc_frob_label (sym)
 {
   if (ppc_current_csect != (symbolS *) NULL)
     {
 {
   if (ppc_current_csect != (symbolS *) NULL)
     {
-      if (sym->sy_tc.class == -1)
-       sym->sy_tc.class = ppc_current_csect->sy_tc.class;
+      if (symbol_get_tc (sym)->class == -1)
+       symbol_get_tc (sym)->class = symbol_get_tc (ppc_current_csect)->class;
 
       symbol_remove (sym, &symbol_rootP, &symbol_lastP);
 
       symbol_remove (sym, &symbol_rootP, &symbol_lastP);
-      symbol_append (sym, ppc_current_csect->sy_tc.within, &symbol_rootP,
-                    &symbol_lastP);
-      ppc_current_csect->sy_tc.within = sym;
+      symbol_append (sym, symbol_get_tc (ppc_current_csect)->within,
+                    &symbol_rootP, &symbol_lastP);
+      symbol_get_tc (ppc_current_csect)->within = sym;
     }
 }
 
     }
 }
 
+/* This variable is set by ppc_frob_symbol if any absolute symbols are
+   seen.  It tells ppc_adjust_symtab whether it needs to look through
+   the symbols.  */
+
+static 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
    class suffix.  Return 1 if the symbol should not be included in the
 /* 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
    class suffix.  Return 1 if the symbol should not be included in the
@@ -3369,15 +4043,15 @@ ppc_frob_symbol (sym)
 
   /* Discard symbols that should not be included in the output symbol
      table.  */
 
   /* Discard symbols that should not be included in the output symbol
      table.  */
-  if (! sym->sy_used_in_reloc
-      && ((sym->bsym->flags & BSF_SECTION_SYM) != 0
+  if (! symbol_used_in_reloc_p (sym)
+      && ((symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) != 0
          || (! S_IS_EXTERNAL (sym)
          || (! S_IS_EXTERNAL (sym)
-             && ! sym->sy_tc.output
+             && ! symbol_get_tc (sym)->output
              && S_GET_STORAGE_CLASS (sym) != C_FILE)))
     return 1;
 
              && S_GET_STORAGE_CLASS (sym) != C_FILE)))
     return 1;
 
-  if (sym->sy_tc.real_name != (char *) NULL)
-    S_SET_NAME (sym, sym->sy_tc.real_name);
+  if (symbol_get_tc (sym)->real_name != (char *) NULL)
+    S_SET_NAME (sym, symbol_get_tc (sym)->real_name);
   else
     {
       const char *name;
   else
     {
       const char *name;
@@ -3408,19 +4082,20 @@ ppc_frob_symbol (sym)
   if (SF_GET_FUNCTION (sym))
     {
       if (ppc_last_function != (symbolS *) NULL)
   if (SF_GET_FUNCTION (sym))
     {
       if (ppc_last_function != (symbolS *) NULL)
-       as_warn ("two .function pseudo-ops with no intervening .ef");
+       as_bad (_("two .function pseudo-ops with no intervening .ef"));
       ppc_last_function = sym;
       ppc_last_function = sym;
-      if (sym->sy_tc.size != (symbolS *) NULL)
+      if (symbol_get_tc (sym)->size != (symbolS *) NULL)
        {
        {
-         resolve_symbol_value (sym->sy_tc.size);
-         SA_SET_SYM_FSIZE (sym, (long) S_GET_VALUE (sym->sy_tc.size));
+         resolve_symbol_value (symbol_get_tc (sym)->size, 1);
+         SA_SET_SYM_FSIZE (sym,
+                           (long) S_GET_VALUE (symbol_get_tc (sym)->size));
        }
     }
   else if (S_GET_STORAGE_CLASS (sym) == C_FCN
           && strcmp (S_GET_NAME (sym), ".ef") == 0)
     {
       if (ppc_last_function == (symbolS *) NULL)
        }
     }
   else if (S_GET_STORAGE_CLASS (sym) == C_FCN
           && strcmp (S_GET_NAME (sym), ".ef") == 0)
     {
       if (ppc_last_function == (symbolS *) NULL)
-       as_warn (".ef with no preceding .function");
+       as_bad (_(".ef with no preceding .function"));
       else
        {
          set_end = ppc_last_function;
       else
        {
          set_end = ppc_last_function;
@@ -3433,9 +4108,10 @@ ppc_frob_symbol (sym)
     }
 
   if (! S_IS_EXTERNAL (sym)
     }
 
   if (! S_IS_EXTERNAL (sym)
-      && (sym->bsym->flags & BSF_SECTION_SYM) == 0
+      && (symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) == 0
       && S_GET_STORAGE_CLASS (sym) != C_FILE
       && S_GET_STORAGE_CLASS (sym) != C_FCN
       && S_GET_STORAGE_CLASS (sym) != C_FILE
       && S_GET_STORAGE_CLASS (sym) != C_FCN
+      && S_GET_STORAGE_CLASS (sym) != C_BLOCK
       && S_GET_STORAGE_CLASS (sym) != C_BSTAT
       && S_GET_STORAGE_CLASS (sym) != C_ESTAT
       && S_GET_STORAGE_CLASS (sym) != C_BINCL
       && S_GET_STORAGE_CLASS (sym) != C_BSTAT
       && S_GET_STORAGE_CLASS (sym) != C_ESTAT
       && S_GET_STORAGE_CLASS (sym) != C_BINCL
@@ -3443,9 +4119,8 @@ ppc_frob_symbol (sym)
       && S_GET_SEGMENT (sym) != ppc_coff_debug_section)
     S_SET_STORAGE_CLASS (sym, C_HIDEXT);
 
       && S_GET_SEGMENT (sym) != ppc_coff_debug_section)
     S_SET_STORAGE_CLASS (sym, C_HIDEXT);
 
-  if ((S_GET_STORAGE_CLASS (sym) == C_EXT
-       || S_GET_STORAGE_CLASS (sym) == C_HIDEXT)
-      && S_GET_SEGMENT (sym) != absolute_section)
+  if (S_GET_STORAGE_CLASS (sym) == C_EXT
+      || S_GET_STORAGE_CLASS (sym) == C_HIDEXT)
     {
       int i;
       union internal_auxent *a;
     {
       int i;
       union internal_auxent *a;
@@ -3453,39 +4128,48 @@ ppc_frob_symbol (sym)
       /* Create a csect aux.  */
       i = S_GET_NUMBER_AUXILIARY (sym);
       S_SET_NUMBER_AUXILIARY (sym, i + 1);
       /* Create a csect aux.  */
       i = S_GET_NUMBER_AUXILIARY (sym);
       S_SET_NUMBER_AUXILIARY (sym, i + 1);
-      a = &coffsymbol (sym->bsym)->native[i + 1].u.auxent;
-      if (sym->sy_tc.class == XMC_TC0)
+      a = &coffsymbol (symbol_get_bfdsym (sym))->native[i + 1].u.auxent;
+      if (symbol_get_tc (sym)->class == XMC_TC0)
        {
          /* This is the TOC table.  */
          know (strcmp (S_GET_NAME (sym), "TOC") == 0);
          a->x_csect.x_scnlen.l = 0;
          a->x_csect.x_smtyp = (2 << 3) | XTY_SD;
        }
        {
          /* This is the TOC table.  */
          know (strcmp (S_GET_NAME (sym), "TOC") == 0);
          a->x_csect.x_scnlen.l = 0;
          a->x_csect.x_smtyp = (2 << 3) | XTY_SD;
        }
-      else if (sym->sy_tc.subseg != 0)
+      else if (symbol_get_tc (sym)->subseg != 0)
        {
          /* This is a csect symbol.  x_scnlen is the size of the
             csect.  */
        {
          /* This is a csect symbol.  x_scnlen is the size of the
             csect.  */
-         if (sym->sy_tc.next == (symbolS *) NULL)
+         if (symbol_get_tc (sym)->next == (symbolS *) NULL)
            a->x_csect.x_scnlen.l = (bfd_section_size (stdoutput,
                                                       S_GET_SEGMENT (sym))
                                     - S_GET_VALUE (sym));
          else
            {
            a->x_csect.x_scnlen.l = (bfd_section_size (stdoutput,
                                                       S_GET_SEGMENT (sym))
                                     - S_GET_VALUE (sym));
          else
            {
-             resolve_symbol_value (sym->sy_tc.next);
-             a->x_csect.x_scnlen.l = (S_GET_VALUE (sym->sy_tc.next)
+             resolve_symbol_value (symbol_get_tc (sym)->next, 1);
+             a->x_csect.x_scnlen.l = (S_GET_VALUE (symbol_get_tc (sym)->next)
                                       - S_GET_VALUE (sym));
            }
                                       - S_GET_VALUE (sym));
            }
-         a->x_csect.x_smtyp = (sym->sy_tc.align << 3) | XTY_SD;
+         a->x_csect.x_smtyp = (symbol_get_tc (sym)->align << 3) | XTY_SD;
        }
       else if (S_GET_SEGMENT (sym) == bss_section)
        {
          /* This is a common symbol.  */
        }
       else if (S_GET_SEGMENT (sym) == bss_section)
        {
          /* This is a common symbol.  */
-         a->x_csect.x_scnlen.l = sym->sy_frag->fr_offset;
-         a->x_csect.x_smtyp = (sym->sy_tc.align << 3) | XTY_CM;
+         a->x_csect.x_scnlen.l = symbol_get_frag (sym)->fr_offset;
+         a->x_csect.x_smtyp = (symbol_get_tc (sym)->align << 3) | XTY_CM;
          if (S_IS_EXTERNAL (sym))
          if (S_IS_EXTERNAL (sym))
-           sym->sy_tc.class = XMC_RW;
+           symbol_get_tc (sym)->class = XMC_RW;
          else
          else
-           sym->sy_tc.class = XMC_BS;
+           symbol_get_tc (sym)->class = XMC_BS;
+       }
+      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;
+         a->x_csect.x_smtyp = XTY_LD;
+         if (symbol_get_tc (sym)->class == -1)
+           symbol_get_tc (sym)->class = XMC_XO;
        }
       else if (! S_IS_DEFINED (sym))
        {
        }
       else if (! S_IS_DEFINED (sym))
        {
@@ -3493,17 +4177,17 @@ ppc_frob_symbol (sym)
          a->x_csect.x_scnlen.l = 0;
          a->x_csect.x_smtyp = XTY_ER;
        }
          a->x_csect.x_scnlen.l = 0;
          a->x_csect.x_smtyp = XTY_ER;
        }
-      else if (sym->sy_tc.class == XMC_TC)
+      else if (symbol_get_tc (sym)->class == XMC_TC)
        {
          symbolS *next;
 
          /* This is a TOC definition.  x_scnlen is the size of the
             TOC entry.  */
          next = symbol_next (sym);
        {
          symbolS *next;
 
          /* This is a TOC definition.  x_scnlen is the size of the
             TOC entry.  */
          next = symbol_next (sym);
-         while (next->sy_tc.class == XMC_TC0)
+         while (symbol_get_tc (next)->class == XMC_TC0)
            next = symbol_next (next);
          if (next == (symbolS *) NULL
            next = symbol_next (next);
          if (next == (symbolS *) NULL
-             || next->sy_tc.class != XMC_TC)
+             || symbol_get_tc (next)->class != XMC_TC)
            {
              if (ppc_after_toc_frag == (fragS *) NULL)
                a->x_csect.x_scnlen.l = (bfd_section_size (stdoutput,
            {
              if (ppc_after_toc_frag == (fragS *) NULL)
                a->x_csect.x_scnlen.l = (bfd_section_size (stdoutput,
@@ -3515,7 +4199,7 @@ ppc_frob_symbol (sym)
            }
          else
            {
            }
          else
            {
-             resolve_symbol_value (next);
+             resolve_symbol_value (next, 1);
              a->x_csect.x_scnlen.l = (S_GET_VALUE (next)
                                       - S_GET_VALUE (sym));
            }
              a->x_csect.x_scnlen.l = (S_GET_VALUE (next)
                                       - S_GET_VALUE (sym));
            }
@@ -3535,34 +4219,43 @@ ppc_frob_symbol (sym)
            abort ();
 
          /* Skip the initial dummy symbol.  */
            abort ();
 
          /* Skip the initial dummy symbol.  */
-         csect = csect->sy_tc.next;
+         csect = symbol_get_tc (csect)->next;
 
          if (csect == (symbolS *) NULL)
 
          if (csect == (symbolS *) NULL)
-           a->x_csect.x_scnlen.l = 0;
+           {
+             as_warn (_("warning: symbol %s has no csect"), S_GET_NAME (sym));
+             a->x_csect.x_scnlen.l = 0;
+           }
          else
            {
          else
            {
-             while (csect->sy_tc.next != (symbolS *) NULL)
+             while (symbol_get_tc (csect)->next != (symbolS *) NULL)
                {
                {
-                 resolve_symbol_value (csect->sy_tc.next);
-                 if (S_GET_VALUE (csect->sy_tc.next) > S_GET_VALUE (sym))
+                 resolve_symbol_value (symbol_get_tc (csect)->next, 1);
+                 if (S_GET_VALUE (symbol_get_tc (csect)->next)
+                     > S_GET_VALUE (sym))
                    break;
                    break;
-                 csect = csect->sy_tc.next;
+                 csect = symbol_get_tc (csect)->next;
                }
 
                }
 
-             a->x_csect.x_scnlen.p = coffsymbol (csect->bsym)->native;
-             coffsymbol (sym->bsym)->native[i + 1].fix_scnlen = 1;
+             a->x_csect.x_scnlen.p =
+               coffsymbol (symbol_get_bfdsym (csect))->native;
+             coffsymbol (symbol_get_bfdsym (sym))->native[i + 1].fix_scnlen =
+               1;
            }
          a->x_csect.x_smtyp = XTY_LD;
        }
        
       a->x_csect.x_parmhash = 0;
       a->x_csect.x_snhash = 0;
            }
          a->x_csect.x_smtyp = XTY_LD;
        }
        
       a->x_csect.x_parmhash = 0;
       a->x_csect.x_snhash = 0;
-      if (sym->sy_tc.class == -1)
+      if (symbol_get_tc (sym)->class == -1)
        a->x_csect.x_smclas = XMC_PR;
       else
        a->x_csect.x_smclas = XMC_PR;
       else
-       a->x_csect.x_smclas = sym->sy_tc.class;
+       a->x_csect.x_smclas = symbol_get_tc (sym)->class;
       a->x_csect.x_stab = 0;
       a->x_csect.x_snstab = 0;
       a->x_csect.x_stab = 0;
       a->x_csect.x_snstab = 0;
+
+      /* Don't let the COFF backend resort these symbols.  */
+      symbol_get_bfdsym (sym)->flags |= BSF_NOT_AT_END;
     }
   else if (S_GET_STORAGE_CLASS (sym) == C_BSTAT)
     {
     }
   else if (S_GET_STORAGE_CLASS (sym) == C_BSTAT)
     {
@@ -3570,8 +4263,10 @@ ppc_frob_symbol (sym)
         csect symbol.  BFD will do that for us if we set the right
         flags.  */
       S_SET_VALUE (sym,
         csect symbol.  BFD will do that for us if we set the right
         flags.  */
       S_SET_VALUE (sym,
-                  (valueT) coffsymbol (sym->sy_tc.within->bsym)->native);
-      coffsymbol (sym->bsym)->native->fix_value = 1;
+                  ((valueT)
+                   coffsymbol (symbol_get_bfdsym
+                               (symbol_get_tc (sym)->within))->native));
+      coffsymbol (symbol_get_bfdsym (sym))->native->fix_value = 1;
     }
   else if (S_GET_STORAGE_CLASS (sym) == C_STSYM)
     {
     }
   else if (S_GET_STORAGE_CLASS (sym) == C_STSYM)
     {
@@ -3579,9 +4274,9 @@ ppc_frob_symbol (sym)
       symbolS *csect;
 
       /* The value is the offset from the enclosing csect.  */
       symbolS *csect;
 
       /* The value is the offset from the enclosing csect.  */
-      block = sym->sy_tc.within;
-      csect = block->sy_tc.within;
-      resolve_symbol_value (csect);
+      block = symbol_get_tc (sym)->within;
+      csect = symbol_get_tc (block)->within;
+      resolve_symbol_value (csect, 1);
       S_SET_VALUE (sym, S_GET_VALUE (sym) - S_GET_VALUE (csect));
     }
   else if (S_GET_STORAGE_CLASS (sym) == C_BINCL
       S_SET_VALUE (sym, S_GET_VALUE (sym) - S_GET_VALUE (csect));
     }
   else if (S_GET_STORAGE_CLASS (sym) == C_BINCL
@@ -3590,12 +4285,58 @@ ppc_frob_symbol (sym)
       /* 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.  */
       /* 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.  */
-      coffsymbol (sym->bsym)->native->fix_line = 1;
+      coffsymbol (symbol_get_bfdsym (sym))->native->fix_line = 1;
     }
 
   return 0;
 }
 
     }
 
   return 0;
 }
 
+/* Adjust the symbol table.  This creates csect symbols for all
+   absolute symbols.  */
+
+void
+ppc_adjust_symtab ()
+{
+  symbolS *sym;
+
+  if (! ppc_saw_abs)
+    return;
+
+  for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
+    {
+      symbolS *csect;
+      int i;
+      union internal_auxent *a;
+
+      if (S_GET_SEGMENT (sym) != absolute_section)
+       continue;
+
+      csect = symbol_create (".abs[XO]", absolute_section,
+                            S_GET_VALUE (sym), &zero_address_frag);
+      symbol_get_bfdsym (csect)->value = S_GET_VALUE (sym);
+      S_SET_STORAGE_CLASS (csect, C_HIDEXT);
+      i = S_GET_NUMBER_AUXILIARY (csect);
+      S_SET_NUMBER_AUXILIARY (csect, i + 1);
+      a = &coffsymbol (symbol_get_bfdsym (csect))->native[i + 1].u.auxent;
+      a->x_csect.x_scnlen.l = 0;
+      a->x_csect.x_smtyp = XTY_SD;
+      a->x_csect.x_parmhash = 0;
+      a->x_csect.x_snhash = 0;
+      a->x_csect.x_smclas = XMC_XO;
+      a->x_csect.x_stab = 0;
+      a->x_csect.x_snstab = 0;
+
+      symbol_insert (csect, sym, &symbol_rootP, &symbol_lastP);
+
+      i = S_GET_NUMBER_AUXILIARY (sym);
+      a = &coffsymbol (symbol_get_bfdsym (sym))->native[i].u.auxent;
+      a->x_csect.x_scnlen.p = coffsymbol (symbol_get_bfdsym (csect))->native;
+      coffsymbol (symbol_get_bfdsym (sym))->native[i].fix_scnlen = 1;
+    }
+
+  ppc_saw_abs = false;
+}
+
 /* Set the VMA for a section.  This is called on all the sections in
    turn.  */
 
 /* Set the VMA for a section.  This is called on all the sections in
    turn.  */
 
@@ -3609,25 +4350,6 @@ ppc_frob_section (sec)
   vma += bfd_section_size (stdoutput, sec);
 }
 
   vma += bfd_section_size (stdoutput, sec);
 }
 
-/* Adjust the file by adding a .debug section if needed.  */
-
-void
-ppc_frob_file ()
-{
-  if (ppc_debug_name_section_size > 0)
-    {
-      asection *sec;
-
-      sec = bfd_make_section (stdoutput, ".debug");
-      if (sec == (asection *) NULL
-         || ! bfd_set_section_size (stdoutput, sec,
-                                    ppc_debug_name_section_size)
-         || ! bfd_set_section_flags (stdoutput, sec,
-                                     SEC_HAS_CONTENTS | SEC_LOAD))
-       as_fatal ("can't make .debug section");
-    }
-}
-
 #endif /* OBJ_XCOFF */
 \f
 /* Turn a string in input_line_pointer into a floating point constant
 #endif /* OBJ_XCOFF */
 \f
 /* Turn a string in input_line_pointer into a floating point constant
@@ -3658,7 +4380,7 @@ md_atof (type, litp, sizep)
 
     default:
       *sizep = 0;
 
     default:
       *sizep = 0;
-      return "bad call to md_atof";
+      return _("bad call to md_atof");
     }
 
   t = atof_ieee (input_line_pointer, type, words);
     }
 
   t = atof_ieee (input_line_pointer, type, words);
@@ -3752,16 +4474,10 @@ md_undefined_symbol (name)
    given a PC relative reloc.  */
 
 long
    given a PC relative reloc.  */
 
 long
-md_pcrel_from (fixp)
+md_pcrel_from_section (fixp, sec)
      fixS *fixp;
      fixS *fixp;
+     segT sec;
 {
 {
-#ifdef OBJ_ELF
-  if (fixp->fx_addsy != (symbolS *) NULL
-      && (! S_IS_DEFINED (fixp->fx_addsy)
-         || TC_FORCE_RELOCATION (fixp)))
-    return 0;
-#endif
-
   return fixp->fx_frag->fr_address + fixp->fx_where;
 }
 
   return fixp->fx_frag->fr_address + fixp->fx_where;
 }
 
@@ -3778,7 +4494,7 @@ ppc_fix_adjustable (fix)
 {
   valueT val;
 
 {
   valueT val;
 
-  resolve_symbol_value (fix->fx_addsy);
+  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
   val = S_GET_VALUE (fix->fx_addsy);
   if (ppc_toc_csect != (symbolS *) NULL
       && fix->fx_addsy != (symbolS *) NULL
@@ -3794,11 +4510,11 @@ ppc_fix_adjustable (fix)
           sy != (symbolS *) NULL;
           sy = symbol_next (sy))
        {
           sy != (symbolS *) NULL;
           sy = symbol_next (sy))
        {
-         if (sy->sy_tc.class == XMC_TC0)
+         if (symbol_get_tc (sy)->class == XMC_TC0)
            continue;
            continue;
-         if (sy->sy_tc.class != XMC_TC)
+         if (symbol_get_tc (sy)->class != XMC_TC)
            break;
            break;
-         resolve_symbol_value (sy);
+         resolve_symbol_value (sy, 1);
          if (val == S_GET_VALUE (sy))
            {
              fix->fx_addsy = sy;
          if (val == S_GET_VALUE (sy))
            {
              fix->fx_addsy = sy;
@@ -3808,15 +4524,21 @@ ppc_fix_adjustable (fix)
        }
 
       as_bad_where (fix->fx_file, fix->fx_line,
        }
 
       as_bad_where (fix->fx_file, fix->fx_line,
-                   "symbol in .toc does not match any .tc");
+                   _("symbol in .toc does not match any .tc"));
     }
 
   /* Possibly adjust the reloc to be against the csect.  */
   if (fix->fx_addsy != (symbolS *) NULL
     }
 
   /* Possibly adjust the reloc to be against the csect.  */
   if (fix->fx_addsy != (symbolS *) NULL
-      && fix->fx_addsy->sy_tc.subseg == 0
-      && fix->fx_addsy->sy_tc.class != XMC_TC0
-      && fix->fx_addsy->sy_tc.class != XMC_TC
-      && S_GET_SEGMENT (fix->fx_addsy) != bss_section)
+      && 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
+      /* Don't adjust if this is a reloc in the toc section.  */
+      && (S_GET_SEGMENT (fix->fx_addsy) != 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 *csect;
 
@@ -3828,17 +4550,45 @@ ppc_fix_adjustable (fix)
        abort ();
 
       /* Skip the initial dummy symbol.  */
        abort ();
 
       /* Skip the initial dummy symbol.  */
-      csect = csect->sy_tc.next;
+      csect = symbol_get_tc (csect)->next;
 
       if (csect != (symbolS *) NULL)
        {
 
       if (csect != (symbolS *) NULL)
        {
-         while (csect->sy_tc.next != (symbolS *) NULL
-                && (csect->sy_tc.next->sy_frag->fr_address
-                    <= fix->fx_addsy->sy_frag->fr_address))
-           csect = csect->sy_tc.next;
+         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))
+           {
+             /* 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))
+               {
+                 symbolS *scan;
+
+                 for (scan = symbol_next (csect);
+                      scan != NULL;
+                      scan = symbol_next (scan))
+                   {
+                     if (symbol_get_tc (scan)->subseg != 0)
+                       break;
+                     if (scan == fix->fx_addsy)
+                       break;
+                   }
+
+                 /* If we found the symbol before the next csect
+                     symbol, then this is the csect we want.  */
+                 if (scan == fix->fx_addsy)
+                   break;
+               }
+
+             csect = symbol_get_tc (csect)->next;
+           }
 
          fix->fx_offset += (S_GET_VALUE (fix->fx_addsy)
 
          fix->fx_offset += (S_GET_VALUE (fix->fx_addsy)
-                            - csect->sy_frag->fr_address);
+                            - symbol_get_frag (csect)->fr_address);
          fix->fx_addsy = csect;
        }
     }
          fix->fx_addsy = csect;
        }
     }
@@ -3849,16 +4599,42 @@ ppc_fix_adjustable (fix)
       && S_GET_SEGMENT (fix->fx_addsy) == bss_section
       && ! S_IS_EXTERNAL (fix->fx_addsy))
     {
       && S_GET_SEGMENT (fix->fx_addsy) == bss_section
       && ! S_IS_EXTERNAL (fix->fx_addsy))
     {
-      resolve_symbol_value (fix->fx_addsy->sy_frag->fr_symbol);
-      fix->fx_offset += (S_GET_VALUE (fix->fx_addsy)
-                        - S_GET_VALUE (fix->fx_addsy->sy_frag->fr_symbol));
-      fix->fx_addsy = fix->fx_addsy->sy_frag->fr_symbol;
+      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;
     }
 
   return 0;
 }
 
     }
 
   return 0;
 }
 
-#endif
+/* A reloc from one csect to another must be kept.  The assembler
+   will, of course, keep relocs between sections, and it will keep
+   absolute relocs, but we need to force it to keep PC relative relocs
+   between two csects in the same section.  */
+
+int
+ppc_force_relocation (fix)
+     fixS *fix;
+{
+  /* At this point fix->fx_addsy should already have been converted to
+     a csect symbol.  If the csect does not include the fragment, then
+     we need to force the relocation.  */
+  if (fix->fx_pcrel
+      && fix->fx_addsy != NULL
+      && symbol_get_tc (fix->fx_addsy)->subseg != 0
+      && ((symbol_get_frag (fix->fx_addsy)->fr_address
+          > fix->fx_frag->fr_address)
+         || (symbol_get_tc (fix->fx_addsy)->next != NULL
+             && (symbol_get_frag (symbol_get_tc (fix->fx_addsy)->next)->fr_address
+                 <= fix->fx_frag->fr_address))))
+    return 1;
+
+  return 0;
+}
+
+#endif /* OBJ_XCOFF */
 
 /* See whether a symbol is in the TOC section.  */
 
 
 /* See whether a symbol is in the TOC section.  */
 
@@ -3867,7 +4643,7 @@ ppc_is_toc_sym (sym)
      symbolS *sym;
 {
 #ifdef OBJ_XCOFF
      symbolS *sym;
 {
 #ifdef OBJ_XCOFF
-  return sym->sy_tc.class == XMC_TC;
+  return symbol_get_tc (sym)->class == XMC_TC;
 #else
   return strcmp (segment_name (S_GET_SEGMENT (sym)), ".got") == 0;
 #endif
 #else
   return strcmp (segment_name (S_GET_SEGMENT (sym)), ".got") == 0;
 #endif
@@ -3890,17 +4666,39 @@ md_apply_fix3 (fixp, valuep, seg)
 {
   valueT value;
 
 {
   valueT value;
 
+#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
+    {
+      fixp->fx_done = 1;
+    }
+#else
   /* FIXME FIXME FIXME: The value we are passed in *valuep 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
   /* FIXME FIXME FIXME: The value we are passed in *valuep 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_perform_relocation, which is also going to use the symbol
+     bfd_install_relocation, which is also going to use the symbol
      value.  That means that if the reloc is fully resolved we want to
      value.  That means that if the reloc is fully resolved we want to
-     use *valuep since bfd_perform_relocation is not being used.
+     use *valuep 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
      result of md_pcrel_from.  This is confusing.  */
      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
      result of md_pcrel_from.  This is confusing.  */
-
   if (fixp->fx_addsy == (symbolS *) NULL)
     {
       value = *valuep;
   if (fixp->fx_addsy == (symbolS *) NULL)
     {
       value = *valuep;
@@ -3919,10 +4717,11 @@ md_apply_fix3 (fixp, valuep, seg)
            {
              /* We can't actually support subtracting a symbol.  */
              as_bad_where (fixp->fx_file, fixp->fx_line,
            {
              /* We can't actually support subtracting a symbol.  */
              as_bad_where (fixp->fx_file, fixp->fx_line,
-                           "expression too complex");
+                           _("expression too complex"));
            }
        }
     }
            }
        }
     }
+#endif
 
   if ((int) fixp->fx_r_type >= (int) BFD_RELOC_UNUSED)
     {
 
   if ((int) fixp->fx_r_type >= (int) BFD_RELOC_UNUSED)
     {
@@ -3948,9 +4747,9 @@ md_apply_fix3 (fixp, valuep, seg)
          && operand->shift == 0
          && operand->insert == NULL
          && fixp->fx_addsy != NULL
          && operand->shift == 0
          && operand->insert == NULL
          && fixp->fx_addsy != NULL
-         && fixp->fx_addsy->sy_tc.subseg != 0
-         && fixp->fx_addsy->sy_tc.class != XMC_TC
-         && fixp->fx_addsy->sy_tc.class != XMC_TC0
+         && 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;
          && S_GET_SEGMENT (fixp->fx_addsy) != bss_section)
        {
          value = fixp->fx_offset;
@@ -4014,8 +4813,17 @@ md_apply_fix3 (fixp, valuep, seg)
        }
       else
        {
        }
       else
        {
-         as_bad_where (fixp->fx_file, fixp->fx_line,
-                       "unresolved expression that must be resolved");
+         char *sfile;
+         unsigned int sline;
+
+         /* Use expr_symbol_where to see if this is an expression
+             symbol.  */
+         if (expr_symbol_where (fixp->fx_addsy, &sfile, &sline))
+           as_bad_where (fixp->fx_file, fixp->fx_line,
+                         _("unresolved expression that must be resolved"));
+         else
+           as_bad_where (fixp->fx_file, fixp->fx_line,
+                         _("unsupported relocation type"));
          fixp->fx_done = 1;
          return 1;
        }
          fixp->fx_done = 1;
          return 1;
        }
@@ -4030,27 +4838,82 @@ md_apply_fix3 (fixp, valuep, seg)
        case BFD_RELOC_32:
        case BFD_RELOC_CTOR:
          if (fixp->fx_pcrel)
        case BFD_RELOC_32:
        case BFD_RELOC_CTOR:
          if (fixp->fx_pcrel)
-           {
-             fixp->fx_r_type = BFD_RELOC_32_PCREL;
-             value += fixp->fx_frag->fr_address + fixp->fx_where;
-           }                   /* fall through */
+           fixp->fx_r_type = BFD_RELOC_32_PCREL;
+                                       /* fall through */
 
 
+       case BFD_RELOC_RVA:
        case BFD_RELOC_32_PCREL:
        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,
                              value, 4);
          break;
 
        case BFD_RELOC_LO16:
          md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
                              value, 4);
          break;
 
        case BFD_RELOC_LO16:
-       case BFD_RELOC_HI16:
-       case BFD_RELOC_HI16_S:
-       case BFD_RELOC_PPC_TOC16:
        case BFD_RELOC_16:
        case BFD_RELOC_GPREL16:
        case BFD_RELOC_16_GOT_PCREL:
        case BFD_RELOC_16:
        case BFD_RELOC_GPREL16:
        case BFD_RELOC_16_GOT_PCREL:
+       case BFD_RELOC_16_GOTOFF:
+       case BFD_RELOC_LO16_GOTOFF:
+       case BFD_RELOC_HI16_GOTOFF:
+       case BFD_RELOC_HI16_S_GOTOFF:
+       case BFD_RELOC_LO16_BASEREL:
+       case BFD_RELOC_HI16_BASEREL:
+       case BFD_RELOC_HI16_S_BASEREL:
+       case BFD_RELOC_PPC_EMB_NADDR16:
+       case BFD_RELOC_PPC_EMB_NADDR16_LO:
+       case BFD_RELOC_PPC_EMB_NADDR16_HI:
+       case BFD_RELOC_PPC_EMB_NADDR16_HA:
+       case BFD_RELOC_PPC_EMB_SDAI16:
+       case BFD_RELOC_PPC_EMB_SDA2REL:
+       case BFD_RELOC_PPC_EMB_SDA2I16:
+       case BFD_RELOC_PPC_EMB_RELSEC16:
+       case BFD_RELOC_PPC_EMB_RELST_LO:
+       case BFD_RELOC_PPC_EMB_RELST_HI:
+       case BFD_RELOC_PPC_EMB_RELST_HA:
+       case BFD_RELOC_PPC_EMB_RELSDA:
+       case BFD_RELOC_PPC_TOC16:
          if (fixp->fx_pcrel)
          if (fixp->fx_pcrel)
-           abort ();
+           {
+             if (fixp->fx_addsy != NULL)
+               as_bad_where (fixp->fx_file, fixp->fx_line,
+                             _("cannot emit PC relative %s relocation against %s"),
+                             bfd_get_reloc_code_name (fixp->fx_r_type),
+                             S_GET_NAME (fixp->fx_addsy));
+             else
+               as_bad_where (fixp->fx_file, fixp->fx_line,
+                             _("cannot emit PC relative %s relocation"),
+                             bfd_get_reloc_code_name (fixp->fx_r_type));
+           }
+
+         md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
+                             value, 2);
+         break;
 
 
+         /* This case happens when you write, for example,
+            lis %r3,(L1-L2)@ha
+            where L1 and L2 are defined later.  */
+       case BFD_RELOC_HI16:
+         if (fixp->fx_pcrel)
+           abort ();
+         md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
+                             value >> 16, 2);
+         break;
+       case BFD_RELOC_HI16_S:
+         if (fixp->fx_pcrel)
+           abort ();
          md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
          md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
+                             (value + 0x8000) >> 16, 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)
+           abort ();
+
+         md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where
+                             + ((target_big_endian) ? 2 : 0),
                              value, 2);
          break;
 
                              value, 2);
          break;
 
@@ -4062,7 +4925,55 @@ md_apply_fix3 (fixp, valuep, seg)
                              value, 1);
          break;
 
                              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"),
+                           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);
+         break;
+
+       case BFD_RELOC_VTABLE_ENTRY:
+         fixp->fx_done = 0;
+         break;
+
        default:
        default:
+         fprintf(stderr,
+                 _("Gas failure, reloc value %d\n"), fixp->fx_r_type);
+         fflush(stderr);
          abort ();
        }
     }
          abort ();
        }
     }
@@ -4097,15 +5008,16 @@ tc_gen_reloc (seg, fixp)
 {
   arelent *reloc;
 
 {
   arelent *reloc;
 
-  reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
+  reloc = (arelent *) xmalloc (sizeof (arelent));
 
 
-  reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
+  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
   if (reloc->howto == (reloc_howto_type *) NULL)
     {
       as_bad_where (fixp->fx_file, fixp->fx_line,
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
   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 NULL;
     }
   reloc->addend = fixp->fx_addnumber;
This page took 0.067215 seconds and 4 git commands to generate.