gas/
[deliverable/binutils-gdb.git] / gas / config / tc-sh.c
index 2b8f918fdb9867019de8864d508e98e7673af532..acf62aef21d643947ecf64ef2cf22934a130a23f 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-sh.c -- Assemble code for the Renesas / SuperH SH
-   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
-   Free Software Foundation, Inc.
+   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+   2003, 2004, 2005  Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -16,8 +16,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 Software Foundation, 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   the Free Software Foundation, 51 Franklin Street - Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
 
 /* Written By Steve Chamberlain <sac@cygnus.com>  */
 
@@ -35,6 +35,7 @@
 #endif
 
 #include "dwarf2dbg.h"
+#include "dw2gencfi.h"
 
 typedef struct
   {
@@ -123,21 +124,27 @@ const pseudo_typeS md_pseudo_table[] =
   {0, 0, 0}
 };
 
-/*int md_reloc_size; */
-
 int sh_relax;          /* set if -relax seen */
 
 /* Whether -small was seen.  */
 
 int sh_small;
 
-/* preset architecture set, if given; zero otherwise.  */
+/* Flag to generate relocations against symbol values for local symbols.  */
+
+static int dont_adjust_reloc_32;
+
+/* Flag to indicate that '$' is allowed as a register prefix.  */
+
+static int allow_dollar_register_prefix;
+
+/* Preset architecture set, if given; zero otherwise.  */
 
-static int preset_target_arch;
+static unsigned int preset_target_arch;
 
 /* The bit mask of architectures that could
    accommodate the insns seen so far.  */
-static int valid_arch;
+static unsigned int valid_arch;
 
 const char EXP_CHARS[] = "eE";
 
@@ -831,10 +838,10 @@ md_begin (void)
 {
   const sh_opcode_info *opcode;
   char *prev_name = "";
-  int target_arch;
+  unsigned int target_arch;
 
   target_arch
-    = preset_target_arch ? preset_target_arch : arch_sh1_up & ~arch_sh_dsp_up;
+    = preset_target_arch ? preset_target_arch : arch_sh_up & ~arch_sh_has_dsp;
   valid_arch = target_arch;
 
 #ifdef HAVE_SH64
@@ -848,7 +855,7 @@ md_begin (void)
     {
       if (strcmp (prev_name, opcode->name) != 0)
        {
-         if (! (opcode->arch & target_arch))
+         if (!SH_MERGE_ARCH_SET_VALID (opcode->arch, target_arch))
            continue;
          prev_name = opcode->name;
          hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
@@ -866,8 +873,8 @@ static int reg_b;
 
 /* Try to parse a reg name.  Return the number of chars consumed.  */
 
-static int
-parse_reg (char *src, int *mode, int *reg)
+static unsigned int
+parse_reg_without_prefix (char *src, int *mode, int *reg)
 {
   char l0 = TOLOWER (src[0]);
   char l1 = l0 ? TOLOWER (src[1]) : 0;
@@ -1093,6 +1100,12 @@ parse_reg (char *src, int *mode, int *reg)
       return 3;
     }
 
+  if (l0 == 't' && l1 == 'b' && TOLOWER (src[2]) == 'r'
+      && ! IDENT_CHAR ((unsigned char) src[3]))
+    {
+      *mode = A_TBR;
+      return 3;
+    }
   if (l0 == 'm' && l1 == 'a' && TOLOWER (src[2]) == 'c'
       && ! IDENT_CHAR ((unsigned char) src[4]))
     {
@@ -1216,6 +1229,36 @@ parse_reg (char *src, int *mode, int *reg)
   return 0;
 }
 
+/* Like parse_reg_without_prefix, but this version supports
+   $-prefixed register names if enabled by the user.  */
+
+static unsigned int
+parse_reg (char *src, int *mode, int *reg)
+{
+  unsigned int prefix;
+  unsigned int consumed;
+
+  if (src[0] == '$')
+    {
+      if (allow_dollar_register_prefix)
+       {
+         src ++;
+         prefix = 1;
+       }
+      else
+       return 0;
+    }
+  else
+    prefix = 0;
+  
+  consumed = parse_reg_without_prefix (src, mode, reg);
+
+  if (consumed == 0)
+    return 0;
+
+  return consumed + prefix;
+}
+
 static char *
 parse_exp (char *s, sh_operand_info *op)
 {
@@ -1263,7 +1306,15 @@ parse_at (char *src, sh_operand_info *op)
   int len;
   int mode;
   src++;
-  if (src[0] == '-')
+  if (src[0] == '@')
+    {
+      src = parse_at (src, op);
+      if (op->type == A_DISP_TBR)
+       op->type = A_DISP2_TBR;
+      else
+       as_bad (_("illegal double indirection"));
+    }
+  else if (src[0] == '-')
     {
       /* Must be predecrement.  */
       src++;
@@ -1336,6 +1387,10 @@ parse_at (char *src, sh_operand_info *op)
                {
                  op->type = A_DISP_GBR;
                }
+             else if (mode == A_TBR)
+               {
+                 op->type = A_DISP_TBR;
+               }
              else if (mode == A_PC)
                {
                  /* We want @(expr, pc) to uniformly address . + expr,
@@ -1537,6 +1592,36 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
          sh_operand_info *user = operands + n;
          sh_arg_type arg = this_try->arg[n];
 
+         if (SH_MERGE_ARCH_SET_VALID (valid_arch, arch_sh2a_nofpu_up)
+             && (   arg == A_DISP_REG_M
+                 || arg == A_DISP_REG_N))
+           {
+             /* Check a few key IMM* fields for overflow.  */
+             int opf;
+             long val = user->immediate.X_add_number;
+
+             for (opf = 0; opf < 4; opf ++)
+               switch (this_try->nibbles[opf])
+                 {
+                 case IMM0_4:
+                 case IMM1_4:
+                   if (val < 0 || val > 15)
+                     goto fail;
+                   break;
+                 case IMM0_4BY2:
+                 case IMM1_4BY2:
+                   if (val < 0 || val > 15 * 2)
+                     goto fail;
+                   break;
+                 case IMM0_4BY4:
+                 case IMM1_4BY4:
+                   if (val < 0 || val > 15 * 4)
+                     goto fail;
+                   break;
+                 default:
+                   break;
+                 }
+           }
          switch (arg)
            {
            case A_DISP_PC:
@@ -1547,6 +1632,7 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
            case A_BDISP12:
            case A_BDISP8:
            case A_DISP_GBR:
+           case A_DISP2_TBR:
            case A_MACH:
            case A_PR:
            case A_MACL:
@@ -1591,6 +1677,7 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
              reg_n = user->reg;
              break;
            case A_GBR:
+           case A_TBR:
            case A_SR:
            case A_VBR:
            case A_DSR:
@@ -1611,6 +1698,22 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
              reg_b = user->reg;
              break;
 
+           case A_INC_R15:
+             if (user->type != A_INC_N)
+               goto fail;
+             if (user->reg != 15)
+               goto fail;
+             reg_n = user->reg;
+             break;
+
+           case A_DEC_R15:
+             if (user->type != A_DEC_N)
+               goto fail;
+             if (user->reg != 15)
+               goto fail;
+             reg_n = user->reg;
+             break;
+
            case A_REG_M:
            case A_INC_M:
            case A_DEC_M:
@@ -1631,7 +1734,7 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
                goto fail;
              reg_n = user->reg;
              break;
-             
+
            case AS_INC_N:
              if (user->type != A_INC_N)
                goto fail;
@@ -1639,7 +1742,7 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
                goto fail;
              reg_n = user->reg;
              break;
-             
+
            case AS_IND_N:
              if (user->type != A_IND_N)
                goto fail;
@@ -1647,7 +1750,7 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
                goto fail;
              reg_n = user->reg;
              break;
-             
+
            case AS_PMOD_N:
              if (user->type != AX_PMOD_N)
                goto fail;
@@ -1655,7 +1758,7 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
                goto fail;
              reg_n = user->reg;
              break;
-             
+
            case AX_INC_N:
              if (user->type != A_INC_N)
                goto fail;
@@ -1663,7 +1766,7 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
                goto fail;
              reg_n = user->reg;
              break;
-             
+
            case AX_IND_N:
              if (user->type != A_IND_N)
                goto fail;
@@ -1671,7 +1774,7 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
                goto fail;
              reg_n = user->reg;
              break;
-             
+
            case AX_PMOD_N:
              if (user->type != AX_PMOD_N)
                goto fail;
@@ -1679,7 +1782,7 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
                goto fail;
              reg_n = user->reg;
              break;
-             
+
            case AXY_INC_N:
              if (user->type != A_INC_N)
                goto fail;
@@ -1688,7 +1791,7 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
                goto fail;
              reg_n = user->reg;
              break;
-             
+
            case AXY_IND_N:
              if (user->type != A_IND_N)
                goto fail;
@@ -1697,7 +1800,7 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
                goto fail;
              reg_n = user->reg;
              break;
-             
+
            case AXY_PMOD_N:
              if (user->type != AX_PMOD_N)
                goto fail;
@@ -1706,7 +1809,7 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
                goto fail;
              reg_n = user->reg;
              break;
-             
+
            case AY_INC_N:
              if (user->type != A_INC_N)
                goto fail;
@@ -1714,7 +1817,7 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
                goto fail;
              reg_n = user->reg;
              break;
-             
+
            case AY_IND_N:
              if (user->type != A_IND_N)
                goto fail;
@@ -1722,7 +1825,7 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
                goto fail;
              reg_n = user->reg;
              break;
-             
+
            case AY_PMOD_N:
              if (user->type != AY_PMOD_N)
                goto fail;
@@ -1739,7 +1842,7 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
                goto fail;
              reg_n = user->reg;
              break;
-             
+
            case AYX_IND_N:
              if (user->type != A_IND_N)
                goto fail;
@@ -1748,7 +1851,7 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
                goto fail;
              reg_n = user->reg;
              break;
-             
+
            case AYX_PMOD_N:
              if (user->type != AY_PMOD_N)
                goto fail;
@@ -2013,9 +2116,9 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
              goto fail;
            }
        }
-      if ( !(valid_arch & this_try->arch))
+      if ( !SH_MERGE_ARCH_SET_VALID (valid_arch, this_try->arch))
        goto fail;
-      valid_arch &= this_try->arch;
+      valid_arch = SH_MERGE_ARCH_SET (valid_arch, this_try->arch);
       return this_try;
     fail:
       ;
@@ -2035,6 +2138,16 @@ insert (char *where, int how, int pcrel, sh_operand_info *op)
               how);
 }
 
+static void
+insert4 (char * where, int how, int pcrel, sh_operand_info * op)
+{
+  fix_new_exp (frag_now,
+              where - frag_now->fr_literal,
+              4,
+              & op->immediate,
+              pcrel,
+              how);
+}
 static void
 build_relax (sh_opcode_info *opcode, sh_operand_info *op)
 {
@@ -2121,16 +2234,31 @@ static unsigned int
 build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
 {
   int index;
-  char nbuf[4];
-  char *output = frag_more (2);
+  char nbuf[8];
+  char *output;
   unsigned int size = 2;
   int low_byte = target_big_endian ? 1 : 0;
+  int max_index = 4;
+
   nbuf[0] = 0;
   nbuf[1] = 0;
   nbuf[2] = 0;
   nbuf[3] = 0;
+  nbuf[4] = 0;
+  nbuf[5] = 0;
+  nbuf[6] = 0;
+  nbuf[7] = 0;
 
-  for (index = 0; index < 4; index++)
+  if (SH_MERGE_ARCH_SET (opcode->arch, arch_op32))
+    {
+      output = frag_more (4);
+      size = 4;
+      max_index = 8;
+    }
+  else
+    output = frag_more (2);
+
+  for (index = 0; index < max_index; index++)
     {
       sh_nibble_type i = opcode->nibbles[index];
       if (i < 16)
@@ -2142,6 +2270,7 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
          switch (i)
            {
            case REG_N:
+           case REG_N_D:
              nbuf[index] = reg_n;
              break;
            case REG_M:
@@ -2158,6 +2287,51 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
            case REG_B:
              nbuf[index] = reg_b | 0x08;
              break;
+           case REG_N_B01:
+             nbuf[index] = reg_n | 0x01;
+             break;
+           case IMM0_3s:
+             nbuf[index] |= 0x08;
+           case IMM0_3c:
+             insert (output + low_byte, BFD_RELOC_SH_IMM3, 0, operand);
+             break;
+           case IMM0_3Us:
+             nbuf[index] |= 0x80;
+           case IMM0_3Uc:
+             insert (output + low_byte, BFD_RELOC_SH_IMM3U, 0, operand);
+             break;
+           case DISP0_12:
+             insert (output + 2, BFD_RELOC_SH_DISP12, 0, operand);
+             break;
+           case DISP0_12BY2:
+             insert (output + 2, BFD_RELOC_SH_DISP12BY2, 0, operand);
+             break;
+           case DISP0_12BY4:
+             insert (output + 2, BFD_RELOC_SH_DISP12BY4, 0, operand);
+             break;
+           case DISP0_12BY8:
+             insert (output + 2, BFD_RELOC_SH_DISP12BY8, 0, operand);
+             break;
+           case DISP1_12:
+             insert (output + 2, BFD_RELOC_SH_DISP12, 0, operand+1);
+             break;
+           case DISP1_12BY2:
+             insert (output + 2, BFD_RELOC_SH_DISP12BY2, 0, operand+1);
+             break;
+           case DISP1_12BY4:
+             insert (output + 2, BFD_RELOC_SH_DISP12BY4, 0, operand+1);
+             break;
+           case DISP1_12BY8:
+             insert (output + 2, BFD_RELOC_SH_DISP12BY8, 0, operand+1);
+             break;
+           case IMM0_20_4:
+             break;
+           case IMM0_20:
+             insert4 (output, BFD_RELOC_SH_DISP20, 0, operand);
+             break;
+           case IMM0_20BY8:
+             insert4 (output, BFD_RELOC_SH_DISP20BY8, 0, operand);
+             break;
            case IMM0_4BY4:
              insert (output + low_byte, BFD_RELOC_SH_IMM4BY4, 0, operand);
              break;
@@ -2222,6 +2396,19 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
       output[0] = (nbuf[0] << 4) | (nbuf[1]);
       output[1] = (nbuf[2] << 4) | (nbuf[3]);
     }
+  if (SH_MERGE_ARCH_SET (opcode->arch, arch_op32))
+    {
+      if (!target_big_endian)
+       {
+         output[3] = (nbuf[4] << 4) | (nbuf[5]);
+         output[2] = (nbuf[6] << 4) | (nbuf[7]);
+       }
+      else
+       {
+         output[2] = (nbuf[4] << 4) | (nbuf[5]);
+         output[3] = (nbuf[6] << 4) | (nbuf[7]);
+       }
+    }
   return size;
 }
 
@@ -2245,7 +2432,7 @@ find_cooked_opcode (char **str_p)
      The pre-processor will eliminate whitespace in front of
      any '@' after the first argument; we may be called from
      assemble_ppi, so the opcode might be terminated by an '@'.  */
-  for (op_start = op_end = (unsigned char *) (str);
+  for (op_start = op_end = (unsigned char *) str;
        *op_end
        && nlen < 20
        && !is_end_of_line[*op_end] && *op_end != ' ' && *op_end != '@';
@@ -2264,7 +2451,7 @@ find_cooked_opcode (char **str_p)
     }
 
   name[nlen] = 0;
-  *str_p = op_end;
+  *str_p = (char *) op_end;
 
   if (nlen == 0)
     as_bad (_("can't find opcode "));
@@ -2477,9 +2664,9 @@ assemble_ppi (char *op_end, sh_opcode_info *opcode)
                field_b -= 0x8100;
              /* pclr Dz pmuls Se,Sf,Dg */
              else if ((field_b & 0xff00) == 0x8d00
-                      && (valid_arch & arch_sh4al_dsp_up))
+                      && (SH_MERGE_ARCH_SET_VALID (valid_arch, arch_sh4al_dsp_up)))
                {
-                 valid_arch &= arch_sh4al_dsp_up;
+                 valid_arch = SH_MERGE_ARCH_SET (valid_arch, arch_sh4al_dsp_up);
                  field_b -= 0x8cf0;
                }
              else
@@ -2579,10 +2766,11 @@ assemble_ppi (char *op_end, sh_opcode_info *opcode)
 void
 md_assemble (char *str)
 {
-  unsigned char *op_end;
+  char *op_end;
   sh_operand_info operand[3];
   sh_opcode_info *opcode;
   unsigned int size = 0;
+  char *initial_str = str;
 
 #ifdef HAVE_SH64
   if (sh64_isa_mode == sh64_isa_shmedia)
@@ -2609,7 +2797,46 @@ md_assemble (char *str)
 
   if (opcode == NULL)
     {
-      as_bad (_("unknown opcode"));
+      /* The opcode is not in the hash table.
+        This means we definately have an assembly failure,
+        but the instruction may be valid in another CPU variant.
+        In this case emit something better than 'unknown opcode'.
+        Search the full table in sh-opc.h to check. */
+
+      char *name = initial_str;
+      int name_length = 0;
+      const sh_opcode_info *op;
+      int found = 0;
+
+      /* identify opcode in string */
+      while (ISSPACE (*name))
+       {
+         name++;
+       }
+      while (!ISSPACE (name[name_length]))
+       {
+         name_length++;
+       }
+
+      /* search for opcode in full list */
+      for (op = sh_table; op->name; op++)
+       {
+         if (strncasecmp (op->name, name, name_length) == 0
+             && op->name[name_length] == '\0')
+           {
+             found = 1;
+             break;
+           }
+       }
+
+      if ( found )
+       {
+         as_bad (_("opcode not valid for this cpu variant"));
+       }
+      else
+       {
+         as_bad (_("unknown opcode"));
+       }
       return;
     }
 
@@ -2634,8 +2861,8 @@ md_assemble (char *str)
        {
          /* Since we skip get_specific here, we have to check & update
             valid_arch now.  */
-         if (valid_arch & opcode->arch)
-           valid_arch &= opcode->arch;
+         if (SH_MERGE_ARCH_SET_VALID (valid_arch, opcode->arch))
+           valid_arch = SH_MERGE_ARCH_SET (valid_arch, opcode->arch);
          else
            as_bad (_("Delayed branches not available on SH1"));
          parse_exp (op_end + 1, &operand[0]);
@@ -2676,16 +2903,14 @@ md_assemble (char *str)
        }
     }
 
-#ifdef BFD_ASSEMBLER
   dwarf2_emit_insn (size);
-#endif
 }
 
 /* This routine is called each time a label definition is seen.  It
    emits a BFD_RELOC_SH_LABEL reloc if necessary.  */
 
 void
-sh_frob_label (void)
+sh_frob_label (symbolS *sym)
 {
   static fragS *last_label_frag;
   static int last_label_offset;
@@ -2704,6 +2929,8 @@ sh_frob_label (void)
          last_label_offset = offset;
        }
     }
+
+  dwarf2_emit_label (sym);
 }
 
 /* This routine is called when the assembler is about to output some
@@ -2727,24 +2954,6 @@ md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
   return 0;
 }
 
-#ifdef OBJ_COFF
-#ifndef BFD_ASSEMBLER
-
-void
-tc_crawl_symbol_chain (object_headers *headers ATTRIBUTE_UNUSED)
-{
-  printf (_("call to tc_crawl_symbol_chain \n"));
-}
-
-void
-tc_headers_hook (object_headers *headers ATTRIBUTE_UNUSED)
-{
-  printf (_("call to tc_headers_hook \n"));
-}
-
-#endif
-#endif
-
 /* Various routines to kill one day.  */
 /* Equal to MAX_PRECISION in atof-ieee.c.  */
 #define MAX_LITTLENUMS 6
@@ -2830,28 +3039,39 @@ s_uses (int ignore ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 \f
+enum options
+{
+  OPTION_RELAX = OPTION_MD_BASE,
+  OPTION_BIG,
+  OPTION_LITTLE,
+  OPTION_SMALL,
+  OPTION_DSP,
+  OPTION_ISA,
+  OPTION_RENESAS,
+  OPTION_ALLOW_REG_PREFIX,
+#ifdef HAVE_SH64
+  OPTION_ABI,
+  OPTION_NO_MIX,
+  OPTION_SHCOMPACT_CONST_CRANGE,
+  OPTION_NO_EXPAND,
+  OPTION_PT32,
+#endif
+  OPTION_DUMMY  /* Not used.  This is just here to make it easy to add and subtract options from this enum.  */
+};
+
 const char *md_shortopts = "";
 struct option md_longopts[] =
 {
-#define OPTION_RELAX  (OPTION_MD_BASE)
-#define OPTION_BIG (OPTION_MD_BASE + 1)
-#define OPTION_LITTLE (OPTION_BIG + 1)
-#define OPTION_SMALL (OPTION_LITTLE + 1)
-#define OPTION_DSP (OPTION_SMALL + 1)
-#define OPTION_ISA                    (OPTION_DSP + 1)
-
   {"relax", no_argument, NULL, OPTION_RELAX},
   {"big", no_argument, NULL, OPTION_BIG},
   {"little", no_argument, NULL, OPTION_LITTLE},
   {"small", no_argument, NULL, OPTION_SMALL},
   {"dsp", no_argument, NULL, OPTION_DSP},
-  {"isa",                    required_argument, NULL, OPTION_ISA},
+  {"isa", required_argument, NULL, OPTION_ISA},
+  {"renesas", no_argument, NULL, OPTION_RENESAS},
+  {"allow-reg-prefix", no_argument, NULL, OPTION_ALLOW_REG_PREFIX},
+
 #ifdef HAVE_SH64
-#define OPTION_ABI                    (OPTION_ISA + 1)
-#define OPTION_NO_MIX                 (OPTION_ABI + 1)
-#define OPTION_SHCOMPACT_CONST_CRANGE (OPTION_NO_MIX + 1)
-#define OPTION_NO_EXPAND              (OPTION_SHCOMPACT_CONST_CRANGE + 1)
-#define OPTION_PT32                   (OPTION_NO_EXPAND + 1)
   {"abi",                    required_argument, NULL, OPTION_ABI},
   {"no-mix",                 no_argument, NULL, OPTION_NO_MIX},
   {"shcompact-const-crange", no_argument, NULL, OPTION_SHCOMPACT_CONST_CRANGE},
@@ -2885,20 +3105,24 @@ md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
       break;
 
     case OPTION_DSP:
-      preset_target_arch = arch_sh1_up & ~arch_sh2e_up;
+      preset_target_arch = arch_sh_up & ~(arch_sh_sp_fpu|arch_sh_dp_fpu);
+      break;
+
+    case OPTION_RENESAS:
+      dont_adjust_reloc_32 = 1;
+      break;
+
+    case OPTION_ALLOW_REG_PREFIX:
+      allow_dollar_register_prefix = 1;
       break;
 
     case OPTION_ISA:
-      if (strcasecmp (arg, "sh4") == 0)
-       preset_target_arch = arch_sh4;
-      else if (strcasecmp (arg, "sh4a") == 0)
-       preset_target_arch = arch_sh4a;
-      else if (strcasecmp (arg, "dsp") == 0)
-       preset_target_arch = arch_sh1_up & ~arch_sh2e_up;
+      if (strcasecmp (arg, "dsp") == 0)
+       preset_target_arch = arch_sh_up & ~(arch_sh_sp_fpu|arch_sh_dp_fpu);
       else if (strcasecmp (arg, "fp") == 0)
-       preset_target_arch = arch_sh2e_up;
+       preset_target_arch = arch_sh_up & ~arch_sh_has_dsp;
       else if (strcasecmp (arg, "any") == 0)
-       preset_target_arch = arch_sh1_up;
+       preset_target_arch = arch_sh_up;
 #ifdef HAVE_SH64
       else if (strcasecmp (arg, "shmedia") == 0)
        {
@@ -2916,7 +3140,35 @@ md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
        }
 #endif /* HAVE_SH64 */
       else
-       as_bad ("Invalid argument to --isa option: %s", arg);
+       {
+         extern const bfd_arch_info_type bfd_sh_arch;
+         bfd_arch_info_type const *bfd_arch = &bfd_sh_arch;
+
+         preset_target_arch = 0;
+         for (; bfd_arch; bfd_arch=bfd_arch->next)
+           {
+             int len = strlen(bfd_arch->printable_name);
+             
+             if (bfd_arch->mach == bfd_mach_sh5)
+               continue;
+             
+             if (strncasecmp (bfd_arch->printable_name, arg, len) != 0)
+               continue;
+
+             if (arg[len] == '\0')
+               preset_target_arch =
+                 sh_get_arch_from_bfd_mach (bfd_arch->mach);
+             else if (strcasecmp(&arg[len], "-up") == 0)
+               preset_target_arch =
+                 sh_get_arch_up_from_bfd_mach (bfd_arch->mach);
+             else
+               continue;
+             break;
+           }
+         
+         if (!preset_target_arch)
+           as_bad ("Invalid argument to --isa option: %s", arg);
+       }
       break;
 
 #ifdef HAVE_SH64
@@ -2968,36 +3220,45 @@ md_show_usage (FILE *stream)
 {
   fprintf (stream, _("\
 SH options:\n\
--little                        generate little endian code\n\
--big                   generate big endian code\n\
--relax                 alter jump instructions for long displacements\n\
--small                 align sections to 4 byte boundaries, not 16\n\
--dsp                   enable sh-dsp insns, and disable floating-point ISAs.\n"));
-  fprintf (stream, _("\
--isa=[sh4\n\
-    | sh4a\n\
-    | dsp              same as '-dsp'\n\
-    | fp\n"
+--little               generate little endian code\n\
+--big                  generate big endian code\n\
+--relax                        alter jump instructions for long displacements\n\
+--renesas              disable optimization with section symbol for\n\
+                       compatibility with Renesas assembler.\n\
+--small                        align sections to 4 byte boundaries, not 16\n\
+--dsp                  enable sh-dsp insns, and disable floating-point ISAs.\n\
+--allow-reg-prefix     allow '$' as a register name prefix.\n\
+--isa=[any             use most appropriate isa\n\
+    | dsp               same as '-dsp'\n\
+    | fp"));
+  {
+    extern const bfd_arch_info_type bfd_sh_arch;
+    bfd_arch_info_type const *bfd_arch = &bfd_sh_arch;
+
+    for (; bfd_arch; bfd_arch=bfd_arch->next)
+      if (bfd_arch->mach != bfd_mach_sh5)
+       {
+         fprintf (stream, "\n    | %s", bfd_arch->printable_name);
+         fprintf (stream, "\n    | %s-up", bfd_arch->printable_name);
+       }
+  }
+  fprintf (stream, "]\n");
 #ifdef HAVE_SH64
-"\
-    | shmedia          set default instruction set for SH64\n\
+  fprintf (stream, _("\
+--isa=[shmedia         set as the default instruction set for SH64\n\
     | SHmedia\n\
     | shcompact\n\
-    | SHcompact\n"
-#endif
-"\
-    | any]\n"));
-#ifdef HAVE_SH64
+    | SHcompact]\n"));
   fprintf (stream, _("\
--abi=[32|64]           set size of expanded SHmedia operands and object\n\
+--abi=[32|64]          set size of expanded SHmedia operands and object\n\
                        file type\n\
--shcompact-const-crange        emit code-range descriptors for constants in\n\
+--shcompact-const-crange  emit code-range descriptors for constants in\n\
                        SHcompact code sections\n\
--no-mix                        disallow SHmedia code in the same section as\n\
+--no-mix               disallow SHmedia code in the same section as\n\
                        constants and SHcompact code\n\
--no-expand             do not expand MOVI, PT, PTA or PTB instructions\n\
--expand-pt32           with -abi=64, expand PT, PTA and PTB instructions\n\
-                       to 32 bits only"));
+--no-expand            do not expand MOVI, PT, PTA or PTB instructions\n\
+--expand-pt32          with -abi=64, expand PT, PTA and PTB instructions\n\
+                       to 32 bits only\n"));
 #endif /* HAVE_SH64 */
 }
 \f
@@ -3013,8 +3274,7 @@ struct sh_count_relocs
 };
 
 /* Count the number of fixups in a section which refer to a particular
-   symbol.  When using BFD_ASSEMBLER, this is called via
-   bfd_map_over_sections.  */
+   symbol.  This is called via bfd_map_over_sections.  */
 
 static void
 sh_count_relocs (bfd *abfd ATTRIBUTE_UNUSED, segT sec, void *data)
@@ -3039,8 +3299,8 @@ sh_count_relocs (bfd *abfd ATTRIBUTE_UNUSED, segT sec, void *data)
     }
 }
 
-/* Handle the count relocs for a particular section.  When using
-   BFD_ASSEMBLER, this is called via bfd_map_over_sections.  */
+/* Handle the count relocs for a particular section.
+   This is called via bfd_map_over_sections.  */
 
 static void
 sh_frob_section (bfd *abfd ATTRIBUTE_UNUSED, segT sec,
@@ -3070,9 +3330,6 @@ sh_frob_section (bfd *abfd ATTRIBUTE_UNUSED, segT sec,
          || fix->fx_subsy != NULL
          || fix->fx_addnumber != 0
          || S_GET_SEGMENT (sym) != sec
-#if ! defined (BFD_ASSEMBLER) && defined (OBJ_COFF)
-         || S_GET_STORAGE_CLASS (sym) == C_EXT
-#endif
          || S_IS_EXTERNAL (sym))
        {
          as_warn_where (fix->fx_file, fix->fx_line,
@@ -3112,9 +3369,6 @@ sh_frob_section (bfd *abfd ATTRIBUTE_UNUSED, segT sec,
          || fscan->fx_subsy != NULL
          || fscan->fx_addnumber != 0
          || S_GET_SEGMENT (sym) != sec
-#if ! defined (BFD_ASSEMBLER) && defined (OBJ_COFF)
-         || S_GET_STORAGE_CLASS (sym) == C_EXT
-#endif
          || S_IS_EXTERNAL (sym))
        {
          as_warn_where (fix->fx_file, fix->fx_line,
@@ -3126,16 +3380,7 @@ sh_frob_section (bfd *abfd ATTRIBUTE_UNUSED, segT sec,
         counting the number of times we find a reference to sym.  */
       info.sym = sym;
       info.count = 0;
-#ifdef BFD_ASSEMBLER
       bfd_map_over_sections (stdoutput, sh_count_relocs, &info);
-#else
-      {
-       int iscan;
-
-       for (iscan = SEG_E0; iscan < SEG_UNKNOWN; iscan++)
-         sh_count_relocs ((bfd *) NULL, iscan, &info);
-      }
-#endif
 
       if (info.count < 1)
        abort ();
@@ -3170,28 +3415,14 @@ sh_frob_file (void)
   if (! sh_relax)
     return;
 
-#ifdef BFD_ASSEMBLER
   bfd_map_over_sections (stdoutput, sh_frob_section, NULL);
-#else
-  {
-    int iseg;
-
-    for (iseg = SEG_E0; iseg < SEG_UNKNOWN; iseg++)
-      sh_frob_section ((bfd *) NULL, iseg, NULL);
-  }
-#endif
 }
 
 /* Called after relaxing.  Set the correct sizes of the fragments, and
-   create relocs so that md_apply_fix3 will fill in the correct values.  */
+   create relocs so that md_apply_fix will fill in the correct values.  */
 
 void
-#ifdef BFD_ASSEMBLER
 md_convert_frag (bfd *headers ATTRIBUTE_UNUSED, segT seg, fragS *fragP)
-#else
-md_convert_frag (object_headers *headers ATTRIBUTE_UNUSED, segT seg,
-                fragS *fragP)
-#endif
 {
   int donerelax = 0;
 
@@ -3264,12 +3495,7 @@ md_convert_frag (object_headers *headers ATTRIBUTE_UNUSED, segT seg,
 
        /* Build a relocation to six / four bytes farther on.  */
        subseg_change (seg, 0);
-       fix_new (fragP, fragP->fr_fix, 2,
-#ifdef BFD_ASSEMBLER
-                section_symbol (seg),
-#else
-                seg_info (seg)->dot,
-#endif
+       fix_new (fragP, fragP->fr_fix, 2, section_symbol (seg),
                 fragP->fr_address + fragP->fr_fix + (delay ? 4 : 6),
                 1, BFD_RELOC_SH_PCDISP8BY2);
 
@@ -3336,17 +3562,12 @@ md_convert_frag (object_headers *headers ATTRIBUTE_UNUSED, segT seg,
 valueT
 md_section_align (segT seg ATTRIBUTE_UNUSED, valueT size)
 {
-#ifdef BFD_ASSEMBLER
 #ifdef OBJ_ELF
   return size;
 #else /* ! OBJ_ELF */
   return ((size + (1 << bfd_get_section_alignment (stdoutput, seg)) - 1)
          & (-1 << bfd_get_section_alignment (stdoutput, seg)));
 #endif /* ! OBJ_ELF */
-#else /* ! BFD_ASSEMBLER */
-  return ((size + (1 << section_alignment[(int) seg]) - 1)
-         & (-1 << section_alignment[(int) seg]));
-#endif /* ! BFD_ASSEMBLER */
 }
 
 /* This static variable is set by s_uacons to tell sh_cons_align that
@@ -3518,6 +3739,7 @@ sh_fix_adjustable (fixS *fixP)
   if (fixP->fx_r_type == BFD_RELOC_32_PLT_PCREL
       || fixP->fx_r_type == BFD_RELOC_32_GOT_PCREL
       || fixP->fx_r_type == BFD_RELOC_SH_GOTPC
+      || ((fixP->fx_r_type == BFD_RELOC_32) && dont_adjust_reloc_32)
       || fixP->fx_r_type == BFD_RELOC_RVA)
     return 0;
 
@@ -3542,33 +3764,16 @@ sh_elf_final_processing (void)
   if (sh64_isa_mode != sh64_isa_unspecified)
     val = EF_SH5;
   else
+#elif defined TARGET_SYMBIAN
+    if (1)
+      {
+       extern int sh_symbian_find_elf_flags (unsigned int);
+
+       val = sh_symbian_find_elf_flags (valid_arch);
+      }
+    else
 #endif /* HAVE_SH64 */
-  if (valid_arch & arch_sh1)
-    val = EF_SH1;
-  else if (valid_arch & arch_sh2)
-    val = EF_SH2;
-  else if (valid_arch & arch_sh2e)
-    val = EF_SH2E;
-  else if (valid_arch & arch_sh_dsp)
-    val = EF_SH_DSP;
-  else if (valid_arch & arch_sh3)
-    val = EF_SH3;
-  else if (valid_arch & arch_sh3_dsp)
-    val = EF_SH3_DSP;
-  else if (valid_arch & arch_sh3e)
-    val = EF_SH3E;
-  else if (valid_arch & arch_sh4_nofpu)
-    val = EF_SH4_NOFPU;
-  else if (valid_arch & arch_sh4)
-    val = EF_SH4;
-  else if (valid_arch & arch_sh4a_nofpu)
-    val = EF_SH4A_NOFPU;
-  else if (valid_arch & arch_sh4a)
-    val = EF_SH4A;
-  else if (valid_arch & arch_sh4al_dsp)
-    val = EF_SH4AL_DSP;
-  else
-    abort ();
+    val = sh_find_elf_flags (valid_arch);
 
   elf_elfheader (stdoutput)->e_flags &= ~EF_SH_MACH_MASK;
   elf_elfheader (stdoutput)->e_flags |= val;
@@ -3578,7 +3783,7 @@ sh_elf_final_processing (void)
 /* Apply a fixup to the object file.  */
 
 void
-md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
+md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 {
   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
   int lowbyte = target_big_endian ? 1 : 0;
@@ -3587,7 +3792,6 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
   long max, min;
   int shift;
 
-#ifdef BFD_ASSEMBLER
   /* A difference between two symbols, the second of which is in the
      current section, is transformed in a PC-relative relocation to
      the other symbol.  We have to adjust the relocation type here.  */
@@ -3633,29 +3837,65 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       && fixP->fx_addsy != NULL
       && S_IS_WEAK (fixP->fx_addsy))
     val -= S_GET_VALUE  (fixP->fx_addsy);
-#endif
 
-#ifdef BFD_ASSEMBLER
   if (SWITCH_TABLE (fixP))
     val -= S_GET_VALUE  (fixP->fx_subsy);
-#else
-  if (fixP->fx_r_type == 0)
-    {
-      if (fixP->fx_size == 2)
-       fixP->fx_r_type = BFD_RELOC_16;
-      else if (fixP->fx_size == 4)
-       fixP->fx_r_type = BFD_RELOC_32;
-      else if (fixP->fx_size == 1)
-       fixP->fx_r_type = BFD_RELOC_8;
-      else
-       abort ();
-    }
-#endif
 
   max = min = 0;
   shift = 0;
   switch (fixP->fx_r_type)
     {
+    case BFD_RELOC_SH_IMM3:
+      max = 0x7;
+      * buf = (* buf & 0xf8) | (val & 0x7);
+      break;
+    case BFD_RELOC_SH_IMM3U:
+      max = 0x7;
+      * buf = (* buf & 0x8f) | ((val & 0x7) << 4);
+      break;
+    case BFD_RELOC_SH_DISP12:
+      max = 0xfff;
+      buf[lowbyte] = val & 0xff;
+      buf[highbyte] |= (val >> 8) & 0x0f;
+      break;
+    case BFD_RELOC_SH_DISP12BY2:
+      max = 0xfff;
+      shift = 1;
+      buf[lowbyte] = (val >> 1) & 0xff;
+      buf[highbyte] |= (val >> 9) & 0x0f;
+      break;
+    case BFD_RELOC_SH_DISP12BY4:
+      max = 0xfff;
+      shift = 2;
+      buf[lowbyte] = (val >> 2) & 0xff;
+      buf[highbyte] |= (val >> 10) & 0x0f;
+      break;
+    case BFD_RELOC_SH_DISP12BY8:
+      max = 0xfff;
+      shift = 3;
+      buf[lowbyte] = (val >> 3) & 0xff;
+      buf[highbyte] |= (val >> 11) & 0x0f;
+      break;
+    case BFD_RELOC_SH_DISP20:
+      if (! target_big_endian)
+       abort();
+      max = 0x7ffff;
+      min = -0x80000;
+      buf[1] = (buf[1] & 0x0f) | ((val >> 12) & 0xf0);
+      buf[2] = (val >> 8) & 0xff;
+      buf[3] = val & 0xff;
+      break;
+    case BFD_RELOC_SH_DISP20BY8:
+      if (!target_big_endian)
+       abort();
+      max = 0x7ffff;
+      min = -0x80000;
+      shift = 8;
+      buf[1] = (buf[1] & 0x0f) | ((val >> 20) & 0xf0);
+      buf[2] = (val >> 16) & 0xff;
+      buf[3] = (val >> 8) & 0xff;
+      break;
+
     case BFD_RELOC_SH_IMM4:
       max = 0xf;
       *buf = (*buf & 0xf0) | (val & 0xf);
@@ -3748,7 +3988,7 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       break;
 
     case BFD_RELOC_SH_USES:
-      /* Pass the value into sh_coff_reloc_mangle.  */
+      /* Pass the value into sh_reloc().  */
       fixP->fx_addnumber = val;
       break;
 
@@ -3823,7 +4063,7 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 
     default:
 #ifdef HAVE_SH64
-      shmedia_md_apply_fix3 (fixP, valP);
+      shmedia_md_apply_fix (fixP, valP);
       return;
 #else
       abort ();
@@ -3940,8 +4180,7 @@ md_number_to_chars (char *ptr, valueT use, int nbytes)
     number_to_chars_bigendian (ptr, use, nbytes);
 }
 
-/* This version is used in obj-coff.c when not using BFD_ASSEMBLER.
-   eg for the sh-hms target.  */
+/* This version is used in obj-coff.c eg. for the sh-hms target.  */
 
 long
 md_pcrel_from (fixS *fixP)
@@ -3967,167 +4206,6 @@ md_pcrel_from_section (fixS *fixP, segT sec)
   return md_pcrel_from (fixP);
 }
 
-#ifdef OBJ_COFF
-
-int
-tc_coff_sizemachdep (fragS *frag)
-{
-  return md_relax_table[frag->fr_subtype].rlx_length;
-}
-
-#endif /* OBJ_COFF */
-
-#ifndef BFD_ASSEMBLER
-#ifdef OBJ_COFF
-
-/* Map BFD relocs to SH COFF relocs.  */
-
-struct reloc_map
-{
-  bfd_reloc_code_real_type bfd_reloc;
-  int sh_reloc;
-};
-
-static const struct reloc_map coff_reloc_map[] =
-{
-  { BFD_RELOC_32, R_SH_IMM32 },
-  { BFD_RELOC_16, R_SH_IMM16 },
-  { BFD_RELOC_8, R_SH_IMM8 },
-  { BFD_RELOC_SH_PCDISP8BY2, R_SH_PCDISP8BY2 },
-  { BFD_RELOC_SH_PCDISP12BY2, R_SH_PCDISP },
-  { BFD_RELOC_SH_IMM4, R_SH_IMM4 },
-  { BFD_RELOC_SH_IMM4BY2, R_SH_IMM4BY2 },
-  { BFD_RELOC_SH_IMM4BY4, R_SH_IMM4BY4 },
-  { BFD_RELOC_SH_IMM8, R_SH_IMM8 },
-  { BFD_RELOC_SH_IMM8BY2, R_SH_IMM8BY2 },
-  { BFD_RELOC_SH_IMM8BY4, R_SH_IMM8BY4 },
-  { BFD_RELOC_SH_PCRELIMM8BY2, R_SH_PCRELIMM8BY2 },
-  { BFD_RELOC_SH_PCRELIMM8BY4, R_SH_PCRELIMM8BY4 },
-  { BFD_RELOC_8_PCREL, R_SH_SWITCH8 },
-  { BFD_RELOC_SH_SWITCH16, R_SH_SWITCH16 },
-  { BFD_RELOC_SH_SWITCH32, R_SH_SWITCH32 },
-  { BFD_RELOC_SH_USES, R_SH_USES },
-  { BFD_RELOC_SH_COUNT, R_SH_COUNT },
-  { BFD_RELOC_SH_ALIGN, R_SH_ALIGN },
-  { BFD_RELOC_SH_CODE, R_SH_CODE },
-  { BFD_RELOC_SH_DATA, R_SH_DATA },
-  { BFD_RELOC_SH_LABEL, R_SH_LABEL },
-  { BFD_RELOC_UNUSED, 0 }
-};
-
-/* Adjust a reloc for the SH.  This is similar to the generic code,
-   but does some minor tweaking.  */
-
-void
-sh_coff_reloc_mangle (segment_info_type *seg, fixS *fix,
-                     struct internal_reloc *intr, unsigned int paddr)
-{
-  symbolS *symbol_ptr = fix->fx_addsy;
-  symbolS *dot;
-
-  intr->r_vaddr = paddr + fix->fx_frag->fr_address + fix->fx_where;
-
-  if (! SWITCH_TABLE (fix))
-    {
-      const struct reloc_map *rm;
-
-      for (rm = coff_reloc_map; rm->bfd_reloc != BFD_RELOC_UNUSED; rm++)
-       if (rm->bfd_reloc == (bfd_reloc_code_real_type) fix->fx_r_type)
-         break;
-      if (rm->bfd_reloc == BFD_RELOC_UNUSED)
-       as_bad_where (fix->fx_file, fix->fx_line,
-                     _("Can not represent %s relocation in this object file format"),
-                     bfd_get_reloc_code_name (fix->fx_r_type));
-      intr->r_type = rm->sh_reloc;
-      intr->r_offset = 0;
-    }
-  else
-    {
-      know (sh_relax);
-
-      if (fix->fx_r_type == BFD_RELOC_16)
-       intr->r_type = R_SH_SWITCH16;
-      else if (fix->fx_r_type == BFD_RELOC_8)
-       intr->r_type = R_SH_SWITCH8;
-      else if (fix->fx_r_type == BFD_RELOC_32)
-       intr->r_type = R_SH_SWITCH32;
-      else
-       abort ();
-
-      /* For a switch reloc, we set r_offset to the difference between
-         the reloc address and the subtrahend.  When the linker is
-         doing relaxing, it can use the determine the starting and
-         ending points of the switch difference expression.  */
-      intr->r_offset = intr->r_vaddr - S_GET_VALUE (fix->fx_subsy);
-    }
-
-  /* PC relative relocs are always against the current section.  */
-  if (symbol_ptr == NULL)
-    {
-      switch (fix->fx_r_type)
-       {
-       case BFD_RELOC_SH_PCRELIMM8BY2:
-       case BFD_RELOC_SH_PCRELIMM8BY4:
-       case BFD_RELOC_SH_PCDISP8BY2:
-       case BFD_RELOC_SH_PCDISP12BY2:
-       case BFD_RELOC_SH_USES:
-         symbol_ptr = seg->dot;
-         break;
-       default:
-         break;
-       }
-    }
-
-  if (fix->fx_r_type == BFD_RELOC_SH_USES)
-    {
-      /* We can't store the offset in the object file, since this
-        reloc does not take up any space, so we store it in r_offset.
-        The fx_addnumber field was set in md_apply_fix3.  */
-      intr->r_offset = fix->fx_addnumber;
-    }
-  else if (fix->fx_r_type == BFD_RELOC_SH_COUNT)
-    {
-      /* We can't store the count in the object file, since this reloc
-         does not take up any space, so we store it in r_offset.  The
-         fx_offset field was set when the fixup was created in
-         sh_coff_frob_file.  */
-      intr->r_offset = fix->fx_offset;
-      /* This reloc is always absolute.  */
-      symbol_ptr = NULL;
-    }
-  else if (fix->fx_r_type == BFD_RELOC_SH_ALIGN)
-    {
-      /* Store the alignment in the r_offset field.  */
-      intr->r_offset = fix->fx_offset;
-      /* This reloc is always absolute.  */
-      symbol_ptr = NULL;
-    }
-  else if (fix->fx_r_type == BFD_RELOC_SH_CODE
-          || fix->fx_r_type == BFD_RELOC_SH_DATA
-          || fix->fx_r_type == BFD_RELOC_SH_LABEL)
-    {
-      /* These relocs are always absolute.  */
-      symbol_ptr = NULL;
-    }
-
-  /* Turn the segment of the symbol into an offset.  */
-  if (symbol_ptr != NULL)
-    {
-      dot = segment_info[S_GET_SEGMENT (symbol_ptr)].dot;
-      if (dot != NULL)
-       intr->r_symndx = dot->sy_number;
-      else
-       intr->r_symndx = symbol_ptr->sy_number;
-    }
-  else
-    intr->r_symndx = -1;
-}
-
-#endif /* OBJ_COFF */
-#endif /* ! BFD_ASSEMBLER */
-
-#ifdef BFD_ASSEMBLER
-
 /* Create a reloc.  */
 
 arelent *
@@ -4185,10 +4263,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
     rel->addend = 0;
 
   rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
-#ifdef OBJ_ELF
-  if (rel->howto->type == R_SH_IND12W)
-      rel->addend += fixp->fx_offset - 4;
-#endif
+
   if (rel->howto == NULL)
     {
       as_bad_where (fixp->fx_file, fixp->fx_line,
@@ -4198,6 +4273,10 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
       rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
       assert (rel->howto != NULL);
     }
+#ifdef OBJ_ELF
+  else if (rel->howto->type == R_SH_IND12W)
+    rel->addend += fixp->fx_offset - 4;
+#endif
 
   return rel;
 }
@@ -4216,7 +4295,10 @@ sh_end_of_match (char *cont, char *what)
 }
 
 int
-sh_parse_name (char const *name, expressionS *exprP, char *nextcharP)
+sh_parse_name (char const *name,
+              expressionS *exprP,
+              enum expr_mode mode,
+              char *nextcharP)
 {
   char *next = input_line_pointer;
   char *next_end;
@@ -4233,15 +4315,15 @@ sh_parse_name (char const *name, expressionS *exprP, char *nextcharP)
       exprP->X_add_symbol = GOT_symbol;
     no_suffix:
       /* If we have an absolute symbol or a reg, then we know its
-            value now.  */
+        value now.  */
       segment = S_GET_SEGMENT (exprP->X_add_symbol);
-      if (segment == absolute_section)
+      if (mode != expr_defer && segment == absolute_section)
        {
          exprP->X_op = O_constant;
          exprP->X_add_number = S_GET_VALUE (exprP->X_add_symbol);
          exprP->X_add_symbol = NULL;
        }
-      else if (segment == reg_section)
+      else if (mode != expr_defer && segment == reg_section)
        {
          exprP->X_op = O_register;
          exprP->X_add_number = S_GET_VALUE (exprP->X_add_symbol);
@@ -4292,5 +4374,53 @@ sh_parse_name (char const *name, expressionS *exprP, char *nextcharP)
 
   return 1;
 }
-#endif
-#endif /* BFD_ASSEMBLER */
+
+void
+sh_cfi_frame_initial_instructions (void)
+{
+  cfi_add_CFA_def_cfa (15, 0);
+}
+
+int
+sh_regname_to_dw2regnum (const char *regname)
+{
+  unsigned int regnum = -1;
+  unsigned int i;
+  const char *p;
+  char *q;
+  static struct { char *name; int dw2regnum; } regnames[] =
+    {
+      { "pr", 17 }, { "t", 18 }, { "gbr", 19 }, { "mach", 20 },
+      { "macl", 21 }, { "fpul", 23 }
+    };
+
+  for (i = 0; i < ARRAY_SIZE (regnames); ++i)
+    if (strcmp (regnames[i].name, regname) == 0)
+      return regnames[i].dw2regnum;
+
+  if (regname[0] == 'r')
+    {
+      p = regname + 1;
+      regnum = strtoul (p, &q, 10);
+      if (p == q || *q || regnum >= 16)
+       return -1;
+    }
+  else if (regname[0] == 'f' && regname[1] == 'r')
+    {
+      p = regname + 2;
+      regnum = strtoul (p, &q, 10);
+      if (p == q || *q || regnum >= 16)
+       return -1;
+      regnum += 25;
+    }
+  else if (regname[0] == 'x' && regname[1] == 'd')
+    {
+      p = regname + 2;
+      regnum = strtoul (p, &q, 10);
+      if (p == q || *q || regnum >= 8)
+       return -1;
+      regnum += 87;
+    }
+  return regnum;
+}
+#endif /* OBJ_ELF */
This page took 0.069691 seconds and 4 git commands to generate.