gas/
[deliverable/binutils-gdb.git] / gas / config / tc-ppc.c
index d4893e7610d495787b7c00cc0569702ff601db2c..d5bdb9e643ea685d84afa0a900dc8c578c0b8d24 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-ppc.c -- Assemble for the PowerPC or POWER (RS/6000)
    Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
 /* tc-ppc.c -- Assemble for the PowerPC or POWER (RS/6000)
    Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-   2004 Free Software Foundation, Inc.
+   2004, 2005 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.
@@ -17,8 +17,8 @@
 
    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
 
    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.  */
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
 
 #include <stdio.h>
 #include "as.h"
 
 #include <stdio.h>
 #include "as.h"
@@ -184,8 +184,10 @@ const char EXP_CHARS[] = "eE";
 const char FLT_CHARS[] = "dD";
 
 /* '+' and '-' can be used as postfix predicate predictors for conditional
 const char FLT_CHARS[] = "dD";
 
 /* '+' and '-' can be used as postfix predicate predictors for conditional
-   branches.  So they need to be accepted as symbol characters.  */
-const char ppc_symbol_chars[] = "+-";
+   branches.  So they need to be accepted as symbol characters.
+   Also, anything that can start an operand needs to be mentioned here,
+   to stop the input scrubber eating whitespace.  */
+const char ppc_symbol_chars[] = "+-%[";
 
 /* The dwarf2 data alignment, adjusted for 32 or 64 bit.  */
 int ppc_cie_data_alignment;
 
 /* The dwarf2 data alignment, adjusted for 32 or 64 bit.  */
 int ppc_cie_data_alignment;
@@ -858,6 +860,9 @@ parse_cpu (const char *arg)
           || strcmp (arg, "7455") == 0)
     ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
               | PPC_OPCODE_ALTIVEC | PPC_OPCODE_32);
           || strcmp (arg, "7455") == 0)
     ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
               | PPC_OPCODE_ALTIVEC | PPC_OPCODE_32);
+  else if (strcmp (arg, "e300") == 0)
+    ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32
+              | PPC_OPCODE_E300);
   else if (strcmp (arg, "altivec") == 0)
     {
       if (ppc_cpu == 0)
   else if (strcmp (arg, "altivec") == 0)
     {
       if (ppc_cpu == 0)
@@ -906,6 +911,12 @@ parse_cpu (const char *arg)
       ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
                 | PPC_OPCODE_64 | PPC_OPCODE_POWER4);
     }
       ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
                 | PPC_OPCODE_64 | PPC_OPCODE_POWER4);
     }
+  else if (strcmp (arg, "power5") == 0)
+    {
+      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
+                | PPC_OPCODE_64 | PPC_OPCODE_POWER4
+                | PPC_OPCODE_POWER5);
+    }
   /* -mcom means assemble for the common intersection between Power
      and PowerPC.  At present, we just allow the union, rather
      than the intersection.  */
   /* -mcom means assemble for the common intersection between Power
      and PowerPC.  At present, we just allow the union, rather
      than the intersection.  */
@@ -1100,10 +1111,12 @@ PowerPC options:\n\
 -mbooke64              generate code for 64-bit PowerPC BookE\n\
 -mbooke, mbooke32      generate code for 32-bit PowerPC BookE\n\
 -mpower4               generate code for Power4 architecture\n\
 -mbooke64              generate code for 64-bit PowerPC BookE\n\
 -mbooke, mbooke32      generate code for 32-bit PowerPC BookE\n\
 -mpower4               generate code for Power4 architecture\n\
+-mpower5               generate code for Power5 architecture\n\
 -mcom                  generate code Power/PowerPC common instructions\n\
 -many                  generate code for any architecture (PWR/PWRX/PPC)\n"));
   fprintf (stream, _("\
 -maltivec              generate code for AltiVec\n\
 -mcom                  generate code Power/PowerPC common instructions\n\
 -many                  generate code for any architecture (PWR/PWRX/PPC)\n"));
   fprintf (stream, _("\
 -maltivec              generate code for AltiVec\n\
+-me300                 generate code for PowerPC e300 family\n\
 -me500, -me500x2       generate code for Motorola e500 core complex\n\
 -mspe                  generate code for Motorola SPE instructions\n\
 -mregnames             Allow symbolic names for registers\n\
 -me500, -me500x2       generate code for Motorola e500 core complex\n\
 -mspe                  generate code for Motorola SPE instructions\n\
 -mregnames             Allow symbolic names for registers\n\
@@ -1144,19 +1157,15 @@ ppc_set_cpu ()
       else if (strcmp (default_cpu, "rs6000") == 0)
        ppc_cpu |= PPC_OPCODE_POWER | PPC_OPCODE_32;
       else if (strncmp (default_cpu, "powerpc", 7) == 0)
       else if (strcmp (default_cpu, "rs6000") == 0)
        ppc_cpu |= PPC_OPCODE_POWER | PPC_OPCODE_32;
       else if (strncmp (default_cpu, "powerpc", 7) == 0)
-       {
-         if (default_cpu[7] == '6' && default_cpu[8] == '4')
-           ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64;
-         else
-           ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32;
-       }
+       ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32;
       else
        as_fatal (_("Unknown default cpu = %s, os = %s"),
                  default_cpu, default_os);
     }
 }
 
       else
        as_fatal (_("Unknown default cpu = %s, os = %s"),
                  default_cpu, default_os);
     }
 }
 
-/* Figure out the BFD architecture to use.  */
+/* Figure out the BFD architecture to use.  This function and ppc_mach
+   are called well before md_begin, when the output file is opened.  */
 
 enum bfd_architecture
 ppc_arch ()
 
 enum bfd_architecture
 ppc_arch ()
@@ -1208,9 +1217,13 @@ ppc_target_format ()
 #endif
 #endif
 #ifdef OBJ_ELF
 #endif
 #endif
 #ifdef OBJ_ELF
+# ifdef TE_VXWORKS
+  return "elf32-powerpc-vxworks";
+# else
   return (target_big_endian
          ? (ppc_obj64 ? "elf64-powerpc" : "elf32-powerpc")
          : (ppc_obj64 ? "elf64-powerpcle" : "elf32-powerpcle"));
   return (target_big_endian
          ? (ppc_obj64 ? "elf64-powerpc" : "elf32-powerpc")
          : (ppc_obj64 ? "elf64-powerpcle" : "elf32-powerpcle"));
+# endif
 #endif
 }
 
 #endif
 }
 
@@ -1254,7 +1267,10 @@ ppc_setup_opcodes (void)
              || (ppc_cpu & PPC_OPCODE_BOOKE) == 0)
          && ((op->flags & (PPC_OPCODE_POWER4 | PPC_OPCODE_NOPOWER4)) == 0
              || ((op->flags & PPC_OPCODE_POWER4)
              || (ppc_cpu & PPC_OPCODE_BOOKE) == 0)
          && ((op->flags & (PPC_OPCODE_POWER4 | PPC_OPCODE_NOPOWER4)) == 0
              || ((op->flags & PPC_OPCODE_POWER4)
-                 == (ppc_cpu & PPC_OPCODE_POWER4))))
+                 == (ppc_cpu & PPC_OPCODE_POWER4)))
+         && ((op->flags & PPC_OPCODE_POWER5) == 0
+             || ((op->flags & PPC_OPCODE_POWER5)
+                 == (ppc_cpu & PPC_OPCODE_POWER5))))
        {
          const char *retval;
 
        {
          const char *retval;
 
@@ -1891,6 +1907,7 @@ void
 ppc_frob_file_before_adjust ()
 {
   symbolS *symp;
 ppc_frob_file_before_adjust ()
 {
   symbolS *symp;
+  asection *toc;
 
   if (!ppc_obj64)
     return;
 
   if (!ppc_obj64)
     return;
@@ -1914,15 +1931,19 @@ ppc_frob_file_before_adjust ()
       dotname = xmalloc (len + 1);
       dotname[0] = '.';
       memcpy (dotname + 1, name, len);
       dotname = xmalloc (len + 1);
       dotname[0] = '.';
       memcpy (dotname + 1, name, len);
-      dotsym = symbol_find (dotname);
+      dotsym = symbol_find_noref (dotname, 1);
       free (dotname);
       if (dotsym != NULL && (symbol_used_p (dotsym)
                             || symbol_used_in_reloc_p (dotsym)))
       free (dotname);
       if (dotsym != NULL && (symbol_used_p (dotsym)
                             || symbol_used_in_reloc_p (dotsym)))
-       {
-         symbol_mark_used (symp);
-       }
+       symbol_mark_used (symp);
+
     }
 
     }
 
+  toc = bfd_get_section_by_name (stdoutput, ".toc");
+  if (toc != NULL
+      && bfd_section_size (stdoutput, toc) > 0x10000)
+    as_warn (_("TOC section size exceeds 64k"));
+
   /* Don't emit .TOC. symbol.  */
   symp = symbol_find (".TOC.");
   if (symp != NULL)
   /* Don't emit .TOC. symbol.  */
   symp = symbol_find (".TOC.");
   if (symp != NULL)
@@ -2635,7 +2656,7 @@ md_assemble (str)
      BFD_RELOC_UNUSED plus the operand index.  This lets us easily
      handle fixups for any operand type, although that is admittedly
      not a very exciting feature.  We pick a BFD reloc type in
      BFD_RELOC_UNUSED plus the operand index.  This lets us easily
      handle fixups for any operand type, although that is admittedly
      not a very exciting feature.  We pick a BFD reloc type in
-     md_apply_fix3.  */
+     md_apply_fix.  */
   for (i = 0; i < fc; i++)
     {
       const struct powerpc_operand *operand;
   for (i = 0; i < fc; i++)
     {
       const struct powerpc_operand *operand;
@@ -4395,6 +4416,7 @@ ppc_pe_comm (lcomm)
     {
       S_SET_VALUE (symbolP, (valueT) temp);
       S_SET_EXTERNAL (symbolP);
     {
       S_SET_VALUE (symbolP, (valueT) temp);
       S_SET_EXTERNAL (symbolP);
+      S_SET_SEGMENT (symbolP, bfd_com_section_ptr);
     }
 
   demand_empty_rest_of_line ();
     }
 
   demand_empty_rest_of_line ();
@@ -4819,6 +4841,10 @@ ppc_frob_label (sym)
                     &symbol_rootP, &symbol_lastP);
       symbol_get_tc (ppc_current_csect)->within = sym;
     }
                     &symbol_rootP, &symbol_lastP);
       symbol_get_tc (ppc_current_csect)->within = sym;
     }
+
+#ifdef OBJ_ELF
+  dwarf2_emit_label (sym);
+#endif
 }
 
 /* This variable is set by ppc_frob_symbol if any absolute symbols are
 }
 
 /* This variable is set by ppc_frob_symbol if any absolute symbols are
@@ -4843,7 +4869,7 @@ ppc_frob_symbol (sym)
      table.  */
   if (! symbol_used_in_reloc_p (sym)
       && ((symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) != 0
      table.  */
   if (! symbol_used_in_reloc_p (sym)
       && ((symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) != 0
-         || (! S_IS_EXTERNAL (sym)
+         || (! (S_IS_EXTERNAL (sym) || S_IS_WEAK (sym))
              && ! symbol_get_tc (sym)->output
              && S_GET_STORAGE_CLASS (sym) != C_FILE)))
     return 1;
              && ! symbol_get_tc (sym)->output
              && S_GET_STORAGE_CLASS (sym) != C_FILE)))
     return 1;
@@ -4909,7 +4935,7 @@ ppc_frob_symbol (sym)
        }
     }
 
        }
     }
 
-  if (! S_IS_EXTERNAL (sym)
+  if (! (S_IS_EXTERNAL (sym) || S_IS_WEAK (sym))
       && (symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) == 0
       && S_GET_STORAGE_CLASS (sym) != C_FILE
       && S_GET_STORAGE_CLASS (sym) != C_FCN
       && (symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) == 0
       && S_GET_STORAGE_CLASS (sym) != C_FILE
       && S_GET_STORAGE_CLASS (sym) != C_FCN
@@ -5454,6 +5480,7 @@ ppc_force_relocation (fix)
     case BFD_RELOC_PPC_B16_BRNTAKEN:
     case BFD_RELOC_PPC_BA16_BRTAKEN:
     case BFD_RELOC_PPC_BA16_BRNTAKEN:
     case BFD_RELOC_PPC_B16_BRNTAKEN:
     case BFD_RELOC_PPC_BA16_BRTAKEN:
     case BFD_RELOC_PPC_BA16_BRNTAKEN:
+    case BFD_RELOC_24_PLT_PCREL:
     case BFD_RELOC_PPC64_TOC:
       return 1;
     default:
     case BFD_RELOC_PPC64_TOC:
       return 1;
     default:
@@ -5479,12 +5506,7 @@ ppc_fix_adjustable (fix)
          && fix->fx_r_type != BFD_RELOC_VTABLE_INHERIT
          && fix->fx_r_type != BFD_RELOC_VTABLE_ENTRY
          && !(fix->fx_r_type >= BFD_RELOC_PPC_TLS
          && fix->fx_r_type != BFD_RELOC_VTABLE_INHERIT
          && fix->fx_r_type != BFD_RELOC_VTABLE_ENTRY
          && !(fix->fx_r_type >= BFD_RELOC_PPC_TLS
-              && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA)
-         && (fix->fx_pcrel
-             || (fix->fx_subsy != NULL
-                 && (S_GET_SEGMENT (fix->fx_subsy)
-                     == S_GET_SEGMENT (fix->fx_addsy)))
-             || S_IS_LOCAL (fix->fx_addsy)));
+              && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA));
 }
 #endif
 
 }
 #endif
 
@@ -5498,7 +5520,7 @@ ppc_fix_adjustable (fix)
    fixup.  */
 
 void
    fixup.  */
 
 void
-md_apply_fix3 (fixP, valP, seg)
+md_apply_fix (fixP, valP, seg)
      fixS *fixP;
      valueT * valP;
      segT seg ATTRIBUTE_UNUSED;
      fixS *fixP;
      valueT * valP;
      segT seg ATTRIBUTE_UNUSED;
@@ -5516,11 +5538,11 @@ md_apply_fix3 (fixP, valP, seg)
     fixP->fx_done = 1;
 #else
   /* FIXME FIXME FIXME: The value we are passed in *valP includes
     fixP->fx_done = 1;
 #else
   /* FIXME FIXME FIXME: The value we are passed in *valP includes
-     the symbol values.  Since we are using BFD_ASSEMBLER, if we are
-     doing this relocation the code in write.c is going to call
-     bfd_install_relocation, which is also going to use the symbol
-     value.  That means that if the reloc is fully resolved we want to
-     use *valP since bfd_install_relocation is not being used.
+     the symbol values.  If we are doing this relocation the code in
+     write.c is going to call bfd_install_relocation, which is also
+     going to use the symbol value.  That means that if the reloc is
+     fully resolved we want to use *valP since bfd_install_relocation is
+     not being used.
      However, if the reloc is not fully resolved we do not want to use
      *valP, and must use fx_offset instead.  However, if the reloc
      is PC relative, we do want to use *valP since it includes the
      However, if the reloc is not fully resolved we do not want to use
      *valP, and must use fx_offset instead.  However, if the reloc
      is PC relative, we do want to use *valP since it includes the
@@ -5706,8 +5728,6 @@ md_apply_fix3 (fixP, valP, seg)
                              value, 8);
          break;
 
                              value, 8);
          break;
 
-       case BFD_RELOC_LO16:
-       case BFD_RELOC_16:
        case BFD_RELOC_GPREL16:
        case BFD_RELOC_16_GOT_PCREL:
        case BFD_RELOC_16_GOTOFF:
        case BFD_RELOC_GPREL16:
        case BFD_RELOC_16_GOT_PCREL:
        case BFD_RELOC_16_GOTOFF:
@@ -5753,19 +5773,45 @@ md_apply_fix3 (fixP, valP, seg)
                              value, 2);
          break;
 
                              value, 2);
          break;
 
+       case BFD_RELOC_16:
+         if (fixP->fx_pcrel)
+           fixP->fx_r_type = BFD_RELOC_16_PCREL;
+         /* fall through */
+
+       case BFD_RELOC_16_PCREL:
+         md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+                             value, 2);
+         break;
+
+       case BFD_RELOC_LO16:
+         if (fixP->fx_pcrel)
+           fixP->fx_r_type = BFD_RELOC_LO16_PCREL;
+         /* fall through */
+
+       case BFD_RELOC_LO16_PCREL:
+         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)
          /* 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 ();
+           fixP->fx_r_type = BFD_RELOC_HI16_PCREL;
+         /* fall through */
+
+       case BFD_RELOC_HI16_PCREL:
          md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
                              PPC_HI (value), 2);
          break;
 
        case BFD_RELOC_HI16_S:
          if (fixP->fx_pcrel)
          md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
                              PPC_HI (value), 2);
          break;
 
        case BFD_RELOC_HI16_S:
          if (fixP->fx_pcrel)
-           abort ();
+           fixP->fx_r_type = BFD_RELOC_HI16_S_PCREL;
+         /* fall through */
+
+       case BFD_RELOC_HI16_S_PCREL:
          md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
                              PPC_HA (value), 2);
          break;
          md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
                              PPC_HA (value), 2);
          break;
@@ -5813,7 +5859,7 @@ md_apply_fix3 (fixP, valP, seg)
          if (fixP->fx_pcrel)
            abort ();
          {
          if (fixP->fx_pcrel)
            abort ();
          {
-           unsigned char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
+           char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
            unsigned long val, mask;
 
            if (target_big_endian)
            unsigned long val, mask;
 
            if (target_big_endian)
@@ -5840,6 +5886,8 @@ md_apply_fix3 (fixP, valP, seg)
          break;
 
        case BFD_RELOC_PPC_TLS:
          break;
 
        case BFD_RELOC_PPC_TLS:
+         break;
+
        case BFD_RELOC_PPC_DTPMOD:
        case BFD_RELOC_PPC_TPREL16:
        case BFD_RELOC_PPC_TPREL16_LO:
        case BFD_RELOC_PPC_DTPMOD:
        case BFD_RELOC_PPC_TPREL16:
        case BFD_RELOC_PPC_TPREL16_LO:
@@ -5879,6 +5927,7 @@ md_apply_fix3 (fixP, valP, seg)
        case BFD_RELOC_PPC64_DTPREL16_HIGHERA:
        case BFD_RELOC_PPC64_DTPREL16_HIGHEST:
        case BFD_RELOC_PPC64_DTPREL16_HIGHESTA:
        case BFD_RELOC_PPC64_DTPREL16_HIGHERA:
        case BFD_RELOC_PPC64_DTPREL16_HIGHEST:
        case BFD_RELOC_PPC64_DTPREL16_HIGHESTA:
+         S_SET_THREAD_LOCAL (fixP->fx_addsy);
          break;
 #endif
          /* Because SDA21 modifies the register field, the size is set to 4
          break;
 #endif
          /* Because SDA21 modifies the register field, the size is set to 4
@@ -5971,6 +6020,13 @@ md_apply_fix3 (fixP, valP, seg)
 
 #ifdef OBJ_ELF
   fixP->fx_addnumber = value;
 
 #ifdef OBJ_ELF
   fixP->fx_addnumber = value;
+
+  /* PowerPC uses RELA relocs, ie. the reloc addend is stored separately
+     from the section contents.  If we are going to be emitting a reloc
+     then the section contents are immaterial, so don't warn if they
+     happen to overflow.  Leave such warnings to ld.  */
+  if (!fixP->fx_done)
+    fixP->fx_no_overflow = 1;
 #else
   if (fixP->fx_r_type != BFD_RELOC_PPC_TOC16)
     fixP->fx_addnumber = 0;
 #else
   if (fixP->fx_r_type != BFD_RELOC_PPC_TOC16)
     fixP->fx_addnumber = 0;
@@ -6032,7 +6088,7 @@ tc_ppc_regname_to_dw2regnum (const char *regname)
     {
       { "sp", 1 }, { "r.sp", 1 }, { "rtoc", 2 }, { "r.toc", 2 },
       { "mq", 64 }, { "lr", 65 }, { "ctr", 66 }, { "ap", 67 },
     {
       { "sp", 1 }, { "r.sp", 1 }, { "rtoc", 2 }, { "r.toc", 2 },
       { "mq", 64 }, { "lr", 65 }, { "ctr", 66 }, { "ap", 67 },
-      { "cc", 68 }, { "xer", 76 }, { "vrsave", 109 }, { "vscr", 110 },
+      { "cr", 70 }, { "xer", 76 }, { "vrsave", 109 }, { "vscr", 110 },
       { "spe_acc", 111 }, { "spefscr", 112 }
     };
 
       { "spe_acc", 111 }, { "spefscr", 112 }
     };
 
This page took 0.043338 seconds and 4 git commands to generate.