Add -Wshadow to the gcc command line options used when compiling the binutils.
[deliverable/binutils-gdb.git] / gas / config / tc-sh.c
index 3e410e303850c429e770a862961e44051b9aa3ec..42f01e9ba5e0aa0298ebebbb0693be3bc3bd07ce 100644 (file)
@@ -1,12 +1,12 @@
 /* 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, 2006, 2007, 2008, 2009  Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
 
    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>  */
 
-#include <stdio.h>
 #include "as.h"
-#include "bfd.h"
 #include "subsegs.h"
 #define DEFINE_TABLE
 #include "opcodes/sh-opc.h"
@@ -35,6 +33,7 @@
 #endif
 
 #include "dwarf2dbg.h"
+#include "dw2gencfi.h"
 
 typedef struct
   {
@@ -123,21 +122,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 preset_target_arch;
+static int allow_dollar_register_prefix;
+
+/* Preset architecture set, if given; zero otherwise.  */
+
+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";
 
@@ -820,8 +825,97 @@ sh_elf_cons (register int nbytes)
   else
     demand_empty_rest_of_line ();
 }
-#endif /* OBJ_ELF */
 
+/* The regular frag_offset_fixed_p doesn't work for rs_align_test
+   frags.  */
+
+static bfd_boolean
+align_test_frag_offset_fixed_p (const fragS *frag1, const fragS *frag2,
+                               bfd_vma *offset)
+{
+  const fragS *frag;
+  bfd_vma off;
+
+  /* Start with offset initialised to difference between the two frags.
+     Prior to assigning frag addresses this will be zero.  */
+  off = frag1->fr_address - frag2->fr_address;
+  if (frag1 == frag2)
+    {
+      *offset = off;
+      return TRUE;
+    }
+
+  /* Maybe frag2 is after frag1.  */
+  frag = frag1;
+  while (frag->fr_type == rs_fill
+        || frag->fr_type == rs_align_test)
+    {
+      if (frag->fr_type == rs_fill)
+       off += frag->fr_fix + frag->fr_offset * frag->fr_var;
+      else
+       off += frag->fr_fix;
+      frag = frag->fr_next;
+      if (frag == NULL)
+       break;
+      if (frag == frag2)
+       {
+         *offset = off;
+         return TRUE;
+       }
+    }
+
+  /* Maybe frag1 is after frag2.  */
+  off = frag1->fr_address - frag2->fr_address;
+  frag = frag2;
+  while (frag->fr_type == rs_fill
+        || frag->fr_type == rs_align_test)
+    {
+      if (frag->fr_type == rs_fill)
+       off -= frag->fr_fix + frag->fr_offset * frag->fr_var;
+      else
+       off -= frag->fr_fix;
+      frag = frag->fr_next;
+      if (frag == NULL)
+       break;
+      if (frag == frag1)
+       {
+         *offset = off;
+         return TRUE;
+       }
+    }
+
+  return FALSE;
+}
+
+/* Optimize a difference of symbols which have rs_align_test frag if
+   possible.  */
+
+int
+sh_optimize_expr (expressionS *l, operatorT op, expressionS *r)
+{
+  bfd_vma frag_off;
+
+  if (op == O_subtract
+      && l->X_op == O_symbol
+      && r->X_op == O_symbol
+      && S_GET_SEGMENT (l->X_add_symbol) == S_GET_SEGMENT (r->X_add_symbol)
+      && (SEG_NORMAL (S_GET_SEGMENT (l->X_add_symbol))
+         || r->X_add_symbol == l->X_add_symbol)
+      && align_test_frag_offset_fixed_p (symbol_get_frag (l->X_add_symbol),
+                                        symbol_get_frag (r->X_add_symbol),
+                                        &frag_off))
+    {
+      l->X_add_number -= r->X_add_number;
+      l->X_add_number -= frag_off / OCTETS_PER_BYTE;
+      l->X_add_number += (S_GET_VALUE (l->X_add_symbol)
+                         - S_GET_VALUE (r->X_add_symbol));
+      l->X_op = O_constant;
+      l->X_add_symbol = 0;
+      return 1;
+    }
+  return 0;
+}
+#endif /* OBJ_ELF */
 \f
 /* This function is called once, at assembler startup time.  This should
    set up all the tables, etc that the MD part of the assembler needs.  */
@@ -831,10 +925,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 +942,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 +960,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 +1187,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,11 +1316,41 @@ 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)
 {
   char *save;
-  char *new;
+  char *new_pointer;
 
   save = input_line_pointer;
   input_line_pointer = s;
@@ -1233,9 +1363,9 @@ parse_exp (char *s, sh_operand_info *op)
           || sh_PIC_related_p (op->immediate.X_op_symbol))
     as_bad (_("misplaced PIC operand"));
 #endif
-  new = input_line_pointer;
+  new_pointer = input_line_pointer;
   input_line_pointer = save;
-  return new;
+  return new_pointer;
 }
 
 /* The many forms of operand:
@@ -1263,7 +1393,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 +1474,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 +1679,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 +1719,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 +1764,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 +1785,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 +1821,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 +1829,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 +1837,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 +1845,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 +1853,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 +1861,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 +1869,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 +1878,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 +1887,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 +1896,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 +1904,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 +1912,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 +1929,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 +1938,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 +2203,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 +2225,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)
 {
@@ -2120,22 +2320,37 @@ insert_loop_bounds (char *output, sh_operand_info *operand)
 static unsigned int
 build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
 {
-  int index;
-  char nbuf[4];
-  char *output = frag_more (2);
+  int indx;
+  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;
+
+  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 < 4; index++)
+  for (indx = 0; indx < max_index; indx++)
     {
-      sh_nibble_type i = opcode->nibbles[index];
+      sh_nibble_type i = opcode->nibbles[indx];
       if (i < 16)
        {
-         nbuf[index] = i;
+         nbuf[indx] = i;
        }
       else
        {
@@ -2143,24 +2358,66 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
            {
            case REG_N:
            case REG_N_D:
-             nbuf[index] = reg_n;
+             nbuf[indx] = reg_n;
              break;
            case REG_M:
-             nbuf[index] = reg_m;
+             nbuf[indx] = reg_m;
              break;
            case SDT_REG_N:
              if (reg_n < 2 || reg_n > 5)
                as_bad (_("Invalid register: 'r%d'"), reg_n);
-             nbuf[index] = (reg_n & 3) | 4;
+             nbuf[indx] = (reg_n & 3) | 4;
              break;
            case REG_NM:
-             nbuf[index] = reg_n | (reg_m >> 2);
+             nbuf[indx] = reg_n | (reg_m >> 2);
              break;
            case REG_B:
-             nbuf[index] = reg_b | 0x08;
+             nbuf[indx] = reg_b | 0x08;
              break;
            case REG_N_B01:
-             nbuf[index] = reg_n | 0x01;
+             nbuf[indx] = reg_n | 0x01;
+             break;
+           case IMM0_3s:
+             nbuf[indx] |= 0x08;
+           case IMM0_3c:
+             insert (output + low_byte, BFD_RELOC_SH_IMM3, 0, operand);
+             break;
+           case IMM0_3Us:
+             nbuf[indx] |= 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);
@@ -2208,7 +2465,7 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
              break;
            case REPEAT:
              output = insert_loop_bounds (output, operand);
-             nbuf[index] = opcode->nibbles[3];
+             nbuf[indx] = opcode->nibbles[3];
              operand += 2;
              break;
            default:
@@ -2226,6 +2483,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;
 }
 
@@ -2249,7 +2519,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 != '@';
@@ -2268,7 +2538,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 "));
@@ -2481,9 +2751,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
@@ -2583,10 +2853,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)
@@ -2613,7 +2884,46 @@ md_assemble (char *str)
 
   if (opcode == NULL)
     {
-      as_bad (_("unknown opcode"));
+      /* The opcode is not in the hash table.
+        This means we definitely 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;
     }
 
@@ -2638,12 +2948,15 @@ 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]);
          build_relax (opcode, &operand[0]);
+
+         /* All branches are currently 16 bit.  */
+         size = 2;
        }
       else
        {
@@ -2680,16 +2993,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;
@@ -2708,6 +3019,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
@@ -2731,80 +3044,12 @@ 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
-
-/* Turn a string in input_line_pointer into a floating point constant
-   of type TYPE, and store the appropriate bytes in *LITP.  The number
-   of LITTLENUMS emitted is stored in *SIZEP .  An error message is
-   returned, or NULL on OK.  */
 
 char *
 md_atof (int type, char *litP, int *sizeP)
 {
-  int prec;
-  LITTLENUM_TYPE words[4];
-  char *t;
-  int i;
-
-  switch (type)
-    {
-    case 'f':
-      prec = 2;
-      break;
-
-    case 'd':
-      prec = 4;
-      break;
-
-    default:
-      *sizeP = 0;
-      return _("bad call to md_atof");
-    }
-
-  t = atof_ieee (input_line_pointer, type, words);
-  if (t)
-    input_line_pointer = t;
-
-  *sizeP = prec * 2;
-
-  if (! target_big_endian)
-    {
-      for (i = prec - 1; i >= 0; i--)
-       {
-         md_number_to_chars (litP, (valueT) words[i], 2);
-         litP += 2;
-       }
-    }
-  else
-    {
-      for (i = 0; i < prec; i++)
-       {
-         md_number_to_chars (litP, (valueT) words[i], 2);
-         litP += 2;
-       }
-    }
-
-  return NULL;
+  return ieee_md_atof (type, litP, sizeP, target_big_endian);
 }
 
 /* Handle the .uses pseudo-op.  This pseudo-op is used just before a
@@ -2834,34 +3079,51 @@ 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_H_TICK_HEX,
+  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},
+  /* The next two switches are here because the
+     generic parts of the linker testsuite uses them.  */
+  {"EB", no_argument, NULL, OPTION_BIG},
+  {"EL", 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},
   {"no-expand",              no_argument, NULL, OPTION_NO_EXPAND},
   {"expand-pt32",            no_argument, NULL, OPTION_PT32},
 #endif /* HAVE_SH64 */
+  { "h-tick-hex", no_argument,       NULL, OPTION_H_TICK_HEX  },
 
   {NULL, no_argument, NULL, 0}
 };
@@ -2889,20 +3151,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)
        {
@@ -2920,7 +3186,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
@@ -2940,7 +3234,7 @@ md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
          sh64_abi = sh64_abi_64;
        }
       else
-       as_bad ("Invalid argument to --abi option: %s", arg);
+       as_bad (_("Invalid argument to --abi option: %s"), arg);
       break;
 
     case OPTION_NO_MIX:
@@ -2960,6 +3254,10 @@ md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
       break;
 #endif /* HAVE_SH64 */
 
+    case OPTION_H_TICK_HEX:
+      enable_h_tick_hex = 1;
+      break;
+
     default:
       return 0;
     }
@@ -2972,38 +3270,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"));
+--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
   fprintf (stream, _("\
--isa=[sh4\n\
-    | sh4a\n\
-    | dsp              same as '-dsp'\n\
-    | fp\n\
-    | shmedia          set as the default instruction set for SH64\n\
+--isa=[shmedia         set as the default instruction set for SH64\n\
     | SHmedia\n\
     | shcompact\n\
-    | SHcompact\n"));
+    | 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\
+--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"));
-#else
-  fprintf (stream, _("\
--isa=[sh4\n\
-    | sh4a\n\
-    | dsp              same as '-dsp'\n\
-    | fp\n\
-    | any]\n"));
 #endif /* HAVE_SH64 */
 }
 \f
@@ -3019,8 +3324,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)
@@ -3045,8 +3349,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,
@@ -3059,6 +3363,21 @@ sh_frob_section (bfd *abfd ATTRIBUTE_UNUSED, segT sec,
   if (seginfo == NULL)
     return;
 
+  for (fix = seginfo->fix_root; fix != NULL; fix = fix->fx_next)
+    {
+      symbolS *sym;
+
+      sym = fix->fx_addsy;
+      /* Check for a local_symbol.  */
+      if (sym && sym->bsym == NULL)
+       {
+         struct local_symbol *ls = (struct local_symbol *)sym;
+         /* See if it's been converted.  If so, canonicalize.  */
+         if (local_symbol_converted_p (ls))
+           fix->fx_addsy = local_symbol_get_real_symbol (ls);
+       }
+    }
+
   for (fix = seginfo->fix_root; fix != NULL; fix = fix->fx_next)
     {
       symbolS *sym;
@@ -3076,9 +3395,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,
@@ -3118,9 +3434,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,
@@ -3132,16 +3445,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 ();
@@ -3176,28 +3480,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;
 
@@ -3270,12 +3560,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);
 
@@ -3342,17 +3627,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
@@ -3451,7 +3731,7 @@ sh_handle_align (fragS *frag)
   else if (frag->fr_type == rs_align_test)
     {
       if (bytes != 0)
-       as_warn_where (frag->fr_file, frag->fr_line, _("misaligned data"));
+       as_bad_where (frag->fr_file, frag->fr_line, _("misaligned data"));
     }
 
   if (sh_relax
@@ -3524,6 +3804,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;
 
@@ -3548,43 +3829,48 @@ 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;
 }
 #endif
 
+/* Apply fixup FIXP to SIZE-byte field BUF given that VAL is its
+   assembly-time value.  If we're generating a reloc for FIXP,
+   see whether the addend should be stored in-place or whether
+   it should be in an ELF r_addend field.  */
+
+static void
+apply_full_field_fix (fixS *fixP, char *buf, bfd_vma val, int size)
+{
+  reloc_howto_type *howto;
+
+  if (fixP->fx_addsy != NULL || fixP->fx_pcrel)
+    {
+      howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
+      if (howto && !howto->partial_inplace)
+       {
+         fixP->fx_addnumber = val;
+         return;
+       }
+    }
+  md_number_to_chars (buf, val, size);
+}
+
 /* 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;
@@ -3593,7 +3879,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.  */
@@ -3639,29 +3924,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);
@@ -3703,6 +4024,23 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       break;
 
     case BFD_RELOC_SH_PCRELIMM8BY4:
+      /* If we are dealing with a known destination ... */
+      if ((fixP->fx_addsy == NULL || S_IS_DEFINED (fixP->fx_addsy))
+         && (fixP->fx_subsy == NULL || S_IS_DEFINED (fixP->fx_addsy)))
+      {
+       /* Don't silently move the destination due to misalignment.
+          The absolute address is the fragment base plus the offset into
+          the fragment plus the pc relative offset to the label.  */
+       if ((fixP->fx_frag->fr_address + fixP->fx_where + val) & 3)
+         as_bad_where (fixP->fx_file, fixP->fx_line,
+                       _("offset to unaligned destination"));
+
+       /* The displacement cannot be zero or backward even if aligned.
+          Allow -2 because val has already been adjusted somewhere.  */
+       if (val < -2)
+         as_bad_where (fixP->fx_file, fixP->fx_line, _("negative offset"));
+      }
+
       /* The lower two bits of the PC are cleared before the
          displacement is added in.  We can assume that the destination
          is on a 4 byte boundary.  If this instruction is also on a 4
@@ -3746,15 +4084,15 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 
     case BFD_RELOC_32:
     case BFD_RELOC_32_PCREL:
-      md_number_to_chars (buf, val, 4);
+      apply_full_field_fix (fixP, buf, val, 4);
       break;
 
     case BFD_RELOC_16:
-      md_number_to_chars (buf, val, 2);
+      apply_full_field_fix (fixP, buf, val, 2);
       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;
 
@@ -3782,8 +4120,7 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       val = fixP->fx_offset;
       if (fixP->fx_subsy)
        val -= S_GET_VALUE (fixP->fx_subsy);
-      fixP->fx_addnumber = val;
-      md_number_to_chars (buf, val, 4);
+      apply_full_field_fix (fixP, buf, val, 4);
       break;
 
     case BFD_RELOC_SH_GOTPC:
@@ -3804,7 +4141,7 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
          was used to store the correction, but since the expression is
          not pcrel, I felt it would be confusing to do it this way.  */
       * valP -= 1;
-      md_number_to_chars (buf, val, 4);
+      apply_full_field_fix (fixP, buf, val, 4);
       break;
 
     case BFD_RELOC_SH_TLS_GD_32:
@@ -3815,7 +4152,7 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_32_GOT_PCREL:
     case BFD_RELOC_SH_GOTPLT32:
       * valP = 0; /* Fully resolved at runtime.  No addend.  */
-      md_number_to_chars (buf, 0, 4);
+      apply_full_field_fix (fixP, buf, 0, 4);
       break;
 
     case BFD_RELOC_SH_TLS_LDO_32:
@@ -3823,13 +4160,13 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       S_SET_THREAD_LOCAL (fixP->fx_addsy);
       /* Fallthrough */
     case BFD_RELOC_32_GOTOFF:
-      md_number_to_chars (buf, val, 4);
+      apply_full_field_fix (fixP, buf, val, 4);
       break;
 #endif
 
     default:
 #ifdef HAVE_SH64
-      shmedia_md_apply_fix3 (fixP, valP);
+      shmedia_md_apply_fix (fixP, valP);
       return;
 #else
       abort ();
@@ -3846,8 +4183,16 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
        val = ((val >> shift)
               | ((long) -1 & ~ ((long) -1 >> shift)));
     }
+
+  /* Extend sign for 64-bit host.  */
+  val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
   if (max != 0 && (val < min || val > max))
     as_bad_where (fixP->fx_file, fixP->fx_line, _("offset out of range"));
+  else if (max != 0)
+    /* Stop the generic code from trying to overlow check the value as well.
+       It may not have the correct value anyway, as we do not store val back
+       into *valP.  */
+    fixP->fx_no_overflow = 1;
 
   if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
     fixP->fx_done = 1;
@@ -3946,8 +4291,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)
@@ -3973,167 +4317,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 *
@@ -4183,18 +4366,11 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
   else if (shmedia_init_reloc (rel, fixp))
     ;
 #endif
-  else if (fixp->fx_pcrel)
-    rel->addend = fixp->fx_addnumber;
-  else if (r_type == BFD_RELOC_32 || r_type == BFD_RELOC_32_GOTOFF)
-    rel->addend = fixp->fx_addnumber;
   else
-    rel->addend = 0;
+    rel->addend = fixp->fx_addnumber;
 
   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,
@@ -4202,8 +4378,12 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
                    bfd_get_reloc_code_name (r_type));
       /* Set howto to a garbage value so that we can keep going.  */
       rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
-      assert (rel->howto != NULL);
+      gas_assert (rel->howto != NULL);
     }
+#ifdef OBJ_ELF
+  else if (rel->howto->type == R_SH_IND12W)
+    rel->addend += fixp->fx_offset - 4;
+#endif
 
   return rel;
 }
@@ -4222,7 +4402,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;
@@ -4239,15 +4422,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);
@@ -4298,5 +4481,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 (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.058148 seconds and 4 git commands to generate.