import insight-2000-02-04 snapshot (2nd try)
[external/binutils.git] / gas / config / tc-sh.c
index b35dcfe..9f7a6c1 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-sh.c -- Assemble code for the Hitachi Super-H
-   Copyright (C) 1993, 94, 95, 96, 1997 Free Software Foundation.
+   Copyright (C) 1993, 94, 95, 96, 97, 98, 1999 Free Software Foundation.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -80,6 +80,10 @@ const pseudo_typeS md_pseudo_table[] =
 
 int sh_relax;          /* set if -relax seen */
 
+/* Whether -small was seen.  */
+
+int sh_small;
+
 const char EXP_CHARS[] = "eE";
 
 /* Chars that mean this number is a floating point constant */
@@ -93,9 +97,11 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
 #define ENCODE_RELAX(what,length) (((what) << 4) + (length))
 #define GET_WHAT(x) ((x>>4))
 
-/* These are the two types of relaxable instrction */
+/* These are the three types of relaxable instrction */
 #define COND_JUMP 1
-#define UNCOND_JUMP  2
+#define COND_JUMP_DELAY 2
+#define UNCOND_JUMP  3
+#define END 4
 
 #define UNDEF_DISP 0
 #define COND8  1
@@ -104,7 +110,6 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
 #define UNCOND12 1
 #define UNCOND32 2
 #define UNDEF_WORD_DISP 4
-#define END 5
 
 #define UNCOND12 1
 #define UNCOND32 2
@@ -121,6 +126,8 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
 #define COND12_M -4090
 #define COND12_LENGTH 6
 
+#define COND12_DELAY_LENGTH 4
+
 /* ??? The minimum and maximum values are wrong, but this does not matter
    since this relocation type is not supported yet.  */
 #define COND32_F (1<<30)
@@ -152,6 +159,16 @@ const relax_typeS md_relax_table[C (END, 0)] = {
   { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
 
   { 0 },
+  /* C (COND_JUMP_DELAY, COND8) */
+  { COND8_F, COND8_M, COND8_LENGTH, C (COND_JUMP_DELAY, COND12) },
+  /* C (COND_JUMP_DELAY, COND12) */
+  { COND12_F, COND12_M, COND12_DELAY_LENGTH, C (COND_JUMP_DELAY, COND32), },
+  /* C (COND_JUMP_DELAY, COND32) */
+  { COND32_F, COND32_M, COND32_LENGTH, 0, },
+  { 0 }, { 0 }, { 0 }, { 0 },
+  { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+
+  { 0 },
   /* C (UNCOND_JUMP, UNCOND12) */
   { UNCOND12_F, UNCOND12_M, UNCOND12_LENGTH, C (UNCOND_JUMP, UNCOND32), },
   /* C (UNCOND_JUMP, UNCOND32) */
@@ -223,7 +240,7 @@ parse_reg (src, mode, reg)
   if (src[0] == 'r')
     {
       if (src[1] >= '0' && src[1] <= '7' && strncmp(&src[2], "_bank", 5) == 0
-         && ! isalnum (src[7]))
+         && ! isalnum ((unsigned char) src[7]))
        {
          *mode = A_REG_B;
          *reg  = (src[1] - '0');
@@ -235,14 +252,16 @@ parse_reg (src, mode, reg)
     {
       if (src[1] == '1')
        {
-         if (src[2] >= '0' && src[2] <= '5' && ! isalnum (src[3]))
+         if (src[2] >= '0' && src[2] <= '5'
+             && ! isalnum ((unsigned char) src[3]))
            {
              *mode = A_REG_N;
              *reg = 10 + src[2] - '0';
              return 3;
            }
        }
-      if (src[1] >= '0' && src[1] <= '9' && ! isalnum (src[2]))
+      if (src[1] >= '0' && src[1] <= '9'
+         && ! isalnum ((unsigned char) src[2]))
        {
          *mode = A_REG_N;
          *reg = (src[1] - '0');
@@ -250,53 +269,73 @@ parse_reg (src, mode, reg)
        }
     }
 
-  if (src[0] == 's' && src[1] == 's' && src[2] == 'r' && ! isalnum (src[3]))
+  if (src[0] == 's'
+      && src[1] == 's'
+      && src[2] == 'r' && ! isalnum ((unsigned char) src[3]))
     {
       *mode = A_SSR;
       return 3;
     }
 
-  if (src[0] == 's' && src[1] == 'p' && src[2] == 'c' && ! isalnum (src[3]))
+  if (src[0] == 's' && src[1] == 'p' && src[2] == 'c'
+      && ! isalnum ((unsigned char) src[3]))
     {
       *mode = A_SPC;
       return 3;
     }
 
-  if (src[0] == 's' && src[1] == 'r' && ! isalnum (src[2]))
+  if (src[0] == 's' && src[1] == 'g' && src[2] == 'r'
+      && ! isalnum ((unsigned char) src[3]))
+    {
+      *mode = A_SGR;
+      return 3;
+    }
+
+  if (src[0] == 'd' && src[1] == 'b' && src[2] == 'r'
+      && ! isalnum ((unsigned char) src[3]))
+    {
+      *mode = A_DBR;
+      return 3;
+    }
+
+  if (src[0] == 's' && src[1] == 'r' && ! isalnum ((unsigned char) src[2]))
     {
       *mode = A_SR;
       return 2;
     }
 
-  if (src[0] == 's' && src[1] == 'p' && ! isalnum (src[2]))
+  if (src[0] == 's' && src[1] == 'p' && ! isalnum ((unsigned char) src[2]))
     {
       *mode = A_REG_N;
       *reg = 15;
       return 2;
     }
 
-  if (src[0] == 'p' && src[1] == 'r' && ! isalnum (src[2]))
+  if (src[0] == 'p' && src[1] == 'r' && ! isalnum ((unsigned char) src[2]))
     {
       *mode = A_PR;
       return 2;
     }
-  if (src[0] == 'p' && src[1] == 'c' && ! isalnum (src[2]))
+  if (src[0] == 'p' && src[1] == 'c' && ! isalnum ((unsigned char) src[2]))
     {
       *mode = A_DISP_PC;
       return 2;
     }
-  if (src[0] == 'g' && src[1] == 'b' && src[2] == 'r' && ! isalnum (src[3]))
+  if (src[0] == 'g' && src[1] == 'b' && src[2] == 'r'
+      && ! isalnum ((unsigned char) src[3]))
     {
       *mode = A_GBR;
       return 3;
     }
-  if (src[0] == 'v' && src[1] == 'b' && src[2] == 'r' && ! isalnum (src[3]))
+  if (src[0] == 'v' && src[1] == 'b' && src[2] == 'r'
+      && ! isalnum ((unsigned char) src[3]))
     {
       *mode = A_VBR;
       return 3;
     }
 
-  if (src[0] == 'm' && src[1] == 'a' && src[2] == 'c' && ! isalnum (src[4]))
+  if (src[0] == 'm' && src[1] == 'a' && src[2] == 'c'
+      && ! isalnum ((unsigned char) src[4]))
     {
       if (src[3] == 'l')
        {
@@ -313,34 +352,99 @@ parse_reg (src, mode, reg)
     {
       if (src[2] == '1')
        {
-         if (src[3] >= '0' && src[3] <= '5' && ! isalnum (src[4]))
+         if (src[3] >= '0' && src[3] <= '5'
+             && ! isalnum ((unsigned char) src[4]))
            {
              *mode = F_REG_N;
              *reg = 10 + src[3] - '0';
              return 4;
            }
        }
-      if (src[2] >= '0' && src[2] <= '9' && ! isalnum (src[3]))
+      if (src[2] >= '0' && src[2] <= '9'
+         && ! isalnum ((unsigned char) src[3]))
        {
          *mode = F_REG_N;
          *reg = (src[2] - '0');
          return 3;
        }
     }
+  if (src[0] == 'd' && src[1] == 'r')
+    {
+      if (src[2] == '1')
+       {
+         if (src[3] >= '0' && src[3] <= '4' && ! ((src[3] - '0') & 1)
+             && ! isalnum ((unsigned char) src[4]))
+           {
+             *mode = D_REG_N;
+             *reg = 10 + src[3] - '0';
+             return 4;
+           }
+       }
+      if (src[2] >= '0' && src[2] <= '8' && ! ((src[2] - '0') & 1)
+         && ! isalnum ((unsigned char) src[3]))
+       {
+         *mode = D_REG_N;
+         *reg = (src[2] - '0');
+         return 3;
+       }
+    }
+  if (src[0] == 'x' && src[1] == 'd')
+    {
+      if (src[2] == '1')
+       {
+         if (src[3] >= '0' && src[3] <= '4' && ! ((src[3] - '0') & 1)
+             && ! isalnum ((unsigned char) src[4]))
+           {
+             *mode = X_REG_N;
+             *reg = 11 + src[3] - '0';
+             return 4;
+           }
+       }
+      if (src[2] >= '0' && src[2] <= '8' && ! ((src[2] - '0') & 1)
+         && ! isalnum ((unsigned char) src[3]))
+       {
+         *mode = X_REG_N;
+         *reg = (src[2] - '0') + 1;
+         return 3;
+       }
+    }
+  if (src[0] == 'f' && src[1] == 'v')
+    {
+      if (src[2] == '1'&& src[3] == '2' && ! isalnum ((unsigned char) src[4]))
+       {
+         *mode = V_REG_N;
+         *reg = 12;
+         return 4;
+       }
+      if ((src[2] == '0' || src[2] == '4' || src[2] == '8')
+         && ! isalnum ((unsigned char) src[3]))
+       {
+         *mode = V_REG_N;
+         *reg = (src[2] - '0');
+         return 3;
+       }
+    }
   if (src[0] == 'f' && src[1] == 'p' && src[2] == 'u' && src[3] == 'l'
-      && ! isalnum (src[4]))
+      && ! isalnum ((unsigned char) src[4]))
     {
       *mode = FPUL_N;
       return 4;
     }
 
   if (src[0] == 'f' && src[1] == 'p' && src[2] == 's' && src[3] == 'c'
-      && src[4] == 'r' && ! isalnum (src[5]))
+      && src[4] == 'r' && ! isalnum ((unsigned char) src[5]))
     {
       *mode = FPSCR_N;
       return 5;
     }
 
+  if (src[0] == 'x' && src[1] == 'm' && src[2] == 't' && src[3] == 'r'
+      && src[4] == 'x' && ! isalnum ((unsigned char) src[5]))
+    {
+      *mode = XMTRX_M4;
+      return 5;
+    }
+
   return 0;
 }
 
@@ -371,7 +475,7 @@ parse_exp (s)
   input_line_pointer = s;
   expression (&immediate);
   if (immediate.X_op == O_absent)
-    as_bad ("missing operand");
+    as_bad (_("missing operand"));
   new = input_line_pointer;
   input_line_pointer = save;
   return new;
@@ -414,7 +518,7 @@ parse_at (src, op)
 
       len = parse_reg (src, &mode, &(op->reg));
       if (mode != A_REG_N)
-       as_bad ("illegal register after @-");
+       as_bad (_("illegal register after @-"));
 
       op->type = A_DEC_N;
       src += len;
@@ -430,7 +534,7 @@ parse_at (src, op)
          src += len;
          if (op->reg != 0)
            {
-             as_bad ("must be @(r0,...)");
+             as_bad (_("must be @(r0,...)"));
            }
          if (src[0] == ',')
            src++;
@@ -446,7 +550,7 @@ parse_at (src, op)
            }
          else
            {
-             as_bad ("syntax error in @(r0,...)");
+             as_bad (_("syntax error in @(r0,...)"));
            }
        }
       else
@@ -478,17 +582,17 @@ parse_at (src, op)
                }
              else
                {
-                 as_bad ("syntax error in @(disp,[Rn, gbr, pc])");
+                 as_bad (_("syntax error in @(disp,[Rn, gbr, pc])"));
                }
            }
          else
            {
-             as_bad ("syntax error in @(disp,[Rn, gbr, pc])");
+             as_bad (_("syntax error in @(disp,[Rn, gbr, pc])"));
            }
        }
       src += len;
       if (src[0] != ')')
-       as_bad ("expecting )");
+       as_bad (_("expecting )"));
       else
        src++;
     }
@@ -497,7 +601,7 @@ parse_at (src, op)
       src += parse_reg (src, &mode, &(op->reg));
       if (mode != A_REG_N)
        {
-         as_bad ("illegal register after @");
+         as_bad (_("illegal register after @"));
        }
       if (src[0] == '+')
        {
@@ -665,6 +769,9 @@ get_specific (opcode, operands)
            case A_IND_R0_REG_N:
            case A_DISP_REG_N:
            case F_REG_N:
+           case D_REG_N:
+           case X_REG_N:
+           case V_REG_N:
            case FPUL_N:
            case FPSCR_N:
              /* Opcode needs rn */
@@ -672,11 +779,23 @@ get_specific (opcode, operands)
                goto fail;
              reg_n = user->reg;
              break;
+           case FD_REG_N:
+             if (user->type != F_REG_N && user->type != D_REG_N)
+               goto fail;
+             reg_n = user->reg;
+             break;
+           case DX_REG_N:
+             if (user->type != D_REG_N && user->type != X_REG_N)
+               goto fail;
+             reg_n = user->reg;
+             break;
            case A_GBR:
            case A_SR:
            case A_VBR:
            case A_SSR:
            case A_SPC:
+           case A_SGR:
+           case A_DBR:
              if (user->type != arg)
                goto fail;
              break;
@@ -700,6 +819,9 @@ get_specific (opcode, operands)
              break;
 
            case F_REG_M:
+           case D_REG_M:
+           case X_REG_M:
+           case V_REG_M:
            case FPUL_M:
            case FPSCR_M:
              /* Opcode needs rn */
@@ -707,9 +829,19 @@ get_specific (opcode, operands)
                goto fail;
              reg_m = user->reg;
              break;
+           case DX_REG_M:
+             if (user->type != D_REG_N && user->type != X_REG_N)
+               goto fail;
+             reg_m = user->reg;
+             break;
+           case XMTRX_M4:
+             if (user->type != XMTRX_M4)
+               goto fail;
+             reg_m = 4;
+             break;
        
            default:
-             printf ("unhandled %d\n", arg);
+             printf (_("unhandled %d\n"), arg);
              goto fail;
            }
        }
@@ -730,7 +862,7 @@ check (operand, low, high)
       || operand->X_add_number < low
       || operand->X_add_number > high)
     {
-      as_bad ("operand must be absolute in range %d..%d", low, high);
+      as_bad (_("operand must be absolute in range %d..%d"), low, high);
     }
   return operand->X_add_number;
 }
@@ -759,10 +891,11 @@ build_relax (opcode)
 
   if (opcode->arg[0] == A_BDISP8)
     {
+      int what = (opcode->nibbles[1] & 4) ? COND_JUMP_DELAY : COND_JUMP;
       p = frag_var (rs_machine_dependent,
-                   md_relax_table[C (COND_JUMP, COND32)].rlx_length,
-                   md_relax_table[C (COND_JUMP, COND8)].rlx_length,
-                   C (COND_JUMP, 0),
+                   md_relax_table[C (what, COND32)].rlx_length,
+                   md_relax_table[C (what, COND8)].rlx_length,
+                   C (what, 0),
                    immediate.X_add_symbol,
                    immediate.X_add_number,
                    0);
@@ -816,6 +949,9 @@ build_Mytes (opcode, operand)
            case REG_M:
              nbuf[index] = reg_m;
              break;
+           case REG_NM:
+             nbuf[index] = reg_n | (reg_m >> 2);
+             break;
             case REG_B:
              nbuf[index] = reg_b | 0x08;
              break;
@@ -847,7 +983,7 @@ build_Mytes (opcode, operand)
              insert (output, BFD_RELOC_SH_PCRELIMM8BY2, 1);
              break;
            default:
-             printf ("failed for %d\n", i);
+             printf (_("failed for %d\n"), i);
            }
        }
     }
@@ -887,21 +1023,28 @@ md_assemble (str)
        && !is_end_of_line[*op_end] && *op_end != ' ';
        op_end++)
     {
-      name[nlen] = op_start[nlen];
+      unsigned char c = op_start[nlen];
+
+      /* The machine independent code will convert CMP/EQ into cmp/EQ
+        because it thinks the '/' is the end of the symbol.  Instead of
+        hacking up the machine independent code, we just deal with it
+        here.  */
+      c = isupper (c) ? tolower (c) : c;
+      name[nlen] = c;
       nlen++;
     }
   name[nlen] = 0;
 
   if (nlen == 0)
     {
-      as_bad ("can't find opcode ");
+      as_bad (_("can't find opcode "));
     }
 
   opcode = (sh_opcode_info *) hash_find (opcode_hash_control, name);
 
   if (opcode == NULL)
     {
-      as_bad ("unknown opcode");
+      as_bad (_("unknown opcode"));
       return;
     }
 
@@ -923,9 +1066,16 @@ md_assemble (str)
     }
   else
     {
-      if (opcode->arg[0] != A_END)
+      if (opcode->arg[0] == A_END)
        {
-         get_operands (opcode, op_end, operand);
+         /* Ignore trailing whitespace.  If there is any, it has already
+            been compressed to a single space.  */
+         if (*op_end == ' ')
+           op_end++;
+       }
+      else
+       {
+         op_end = get_operands (opcode, op_end, operand);
        }
       opcode = get_specific (opcode, operand);
 
@@ -936,10 +1086,13 @@ md_assemble (str)
 
          where[0] = 0x0;
          where[1] = 0x0;
-         as_bad ("invalid operands for opcode");
+         as_bad (_("invalid operands for opcode"));
          return;
        }
 
+      if (*op_end)
+       as_bad (_("excess operands: '%s'"), op_end);
+
       build_Mytes (opcode, operand);
     }
 
@@ -998,14 +1151,14 @@ void
 DEFUN (tc_crawl_symbol_chain, (headers),
        object_headers * headers)
 {
-  printf ("call to tc_crawl_symbol_chain \n");
+  printf (_("call to tc_crawl_symbol_chain \n"));
 }
 
 void
 DEFUN (tc_headers_hook, (headers),
        object_headers * headers)
 {
-  printf ("call to tc_headers_hook \n");
+  printf (_("call to tc_headers_hook \n"));
 }
 
 #endif
@@ -1041,7 +1194,7 @@ md_atof (type, litP, sizeP)
 
     default:
       *sizeP = 0;
-      return "bad call to md_atof";
+      return _("bad call to md_atof");
     }
 
   t = atof_ieee (input_line_pointer, type, words);
@@ -1082,13 +1235,13 @@ s_uses (ignore)
   expressionS ex;
 
   if (! sh_relax)
-    as_warn (".uses pseudo-op seen when not relaxing");
+    as_warn (_(".uses pseudo-op seen when not relaxing"));
 
   expression (&ex);
 
   if (ex.X_op != O_symbol || ex.X_add_number != 0)
     {
-      as_bad ("bad .uses format");
+      as_bad (_("bad .uses format"));
       ignore_rest_of_line ();
       return;
     }
@@ -1102,10 +1255,12 @@ CONST char *md_shortopts = "";
 struct option md_longopts[] = {
 
 #define OPTION_RELAX  (OPTION_MD_BASE)
-#define OPTION_LITTLE (OPTION_MD_BASE+1)
+#define OPTION_LITTLE (OPTION_MD_BASE + 1)
+#define OPTION_SMALL (OPTION_LITTLE + 1)
 
   {"relax", no_argument, NULL, OPTION_RELAX},
   {"little", no_argument, NULL, OPTION_LITTLE},
+  {"small", no_argument, NULL, OPTION_SMALL},
   {NULL, no_argument, NULL, 0}
 };
 size_t md_longopts_size = sizeof(md_longopts);
@@ -1120,11 +1275,16 @@ md_parse_option (c, arg)
     case OPTION_RELAX:
       sh_relax = 1;
       break;
+
     case OPTION_LITTLE:
       shl = 1;
       target_big_endian = 0;
       break;
 
+    case OPTION_SMALL:
+      sh_small = 1;
+      break;
+
     default:
       return 0;
     }
@@ -1136,42 +1296,20 @@ void
 md_show_usage (stream)
      FILE *stream;
 {
-  fprintf(stream, "\
+  fprintf(stream, _("\
 SH options:\n\
 -little                        generate little endian code\n\
--relax                 alter jump instructions for long displacements\n");
+-relax                 alter jump instructions for long displacements\n\
+-small                 align sections to 4 byte boundaries, not 16\n"));
 }
 \f
-int md_short_jump_size;
-
 void
 tc_Nout_fix_to_chars ()
 {
-  printf ("call to tc_Nout_fix_to_chars \n");
+  printf (_("call to tc_Nout_fix_to_chars \n"));
   abort ();
 }
 
-void
-md_create_short_jump (ptr, from_Nddr, to_Nddr, frag, to_symbol)
-     char *ptr;
-     addressT from_Nddr;
-     addressT to_Nddr;
-     fragS *frag;
-     symbolS *to_symbol;
-{
-  as_fatal ("failed sanity check.");
-}
-
-void
-md_create_long_jump (ptr, from_Nddr, to_Nddr, frag, to_symbol)
-     char *ptr;
-     addressT from_Nddr, to_Nddr;
-     fragS *frag;
-     symbolS *to_symbol;
-{
-  as_fatal ("failed sanity check.");
-}
-
 /* This struct is used to pass arguments to sh_count_relocs through
    bfd_map_over_sections.  */
 
@@ -1254,7 +1392,7 @@ sh_frob_section (abfd, sec, ignore)
          || S_IS_EXTERNAL (sym))
        {
          as_warn_where (fix->fx_file, fix->fx_line,
-                        ".uses does not refer to a local symbol in the same section");
+                        _(".uses does not refer to a local symbol in the same section"));
          continue;
        }
 
@@ -1273,7 +1411,7 @@ sh_frob_section (abfd, sec, ignore)
       if (fscan == NULL)
        {
          as_warn_where (fix->fx_file, fix->fx_line,
-                        "can't find fixup pointed to by .uses");
+                        _("can't find fixup pointed to by .uses"));
          continue;
        }
 
@@ -1296,7 +1434,7 @@ sh_frob_section (abfd, sec, ignore)
          || S_IS_EXTERNAL (sym))
        {
          as_warn_where (fix->fx_file, fix->fx_line,
-                        ".uses target does not refer to a local symbol in the same section");
+                        _(".uses target does not refer to a local symbol in the same section"));
          continue;
        }
 
@@ -1322,7 +1460,8 @@ sh_frob_section (abfd, sec, ignore)
         We have already adjusted the value of sym to include the
         fragment address, so we undo that adjustment here.  */
       subseg_change (sec, 0);
-      fix_new (sym->sy_frag, S_GET_VALUE (sym) - sym->sy_frag->fr_address,
+      fix_new (symbol_get_frag (sym),
+              S_GET_VALUE (sym) - symbol_get_frag (sym)->fr_address,
               4, &abs_symbol, info.count, 0, BFD_RELOC_SH_COUNT);
     }
 }
@@ -1373,6 +1512,7 @@ md_convert_frag (headers, seg, fragP)
   switch (fragP->fr_subtype)
     {
     case C (COND_JUMP, COND8):
+    case C (COND_JUMP_DELAY, COND8):
       subseg_change (seg, 0);
       fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
               1, BFD_RELOC_SH_PCDISP8BY2);
@@ -1391,12 +1531,15 @@ md_convert_frag (headers, seg, fragP)
     case C (UNCOND_JUMP, UNCOND32):
     case C (UNCOND_JUMP, UNDEF_WORD_DISP):
       if (fragP->fr_symbol == NULL)
-       as_bad ("at 0x%lx, displacement overflows 12-bit field",
+       as_bad (_("at 0x%lx, displacement overflows 12-bit field"),
                (unsigned long) fragP->fr_address);
+      else if (S_IS_DEFINED (fragP->fr_symbol))
+       as_bad (_("at 0x%lx, displacement to defined symbol %s overflows 12-bit field"),
+               (unsigned long) fragP->fr_address,              
+               S_GET_NAME (fragP->fr_symbol));
       else
-       as_bad ("at 0x%lx, displacement to %sdefined symbol %s overflows 12-bit field",
+       as_bad (_("at 0x%lx, displacement to undefined symbol %s overflows 12-bit field"),
                (unsigned long) fragP->fr_address,              
-               S_IS_DEFINED (fragP->fr_symbol) ? "" : "un",
                S_GET_NAME (fragP->fr_symbol));
 
 #if 0                          /* This code works, but generates poor code and the compiler
@@ -1442,17 +1585,36 @@ md_convert_frag (headers, seg, fragP)
       break;
 
     case C (COND_JUMP, COND12):
+    case C (COND_JUMP_DELAY, COND12):
       /* A bcond won't fit, so turn it into a b!cond; bra disp; nop */
+      /* I found that a relax failure for gcc.c-torture/execute/930628-1.c
+        was due to gas incorrectly relaxing an out-of-range conditional
+        branch with delay slot.  It turned:
+                     bf.s    L6              (slot mov.l   r12,@(44,r0))
+         into:
+   
+2c:  8f 01 a0 8b     bf.s    32 <_main+32>   (slot bra       L6)
+30:  00 09           nop
+32:  10 cb           mov.l   r12,@(44,r0)
+         Therefore, branches with delay slots have to be handled
+        differently from ones without delay slots.  */
       {
        unsigned char *buffer =
          (unsigned char *) (fragP->fr_fix + fragP->fr_literal);
        int highbyte = target_big_endian ? 0 : 1;
        int lowbyte = target_big_endian ? 1 : 0;
+       int delay = fragP->fr_subtype == C (COND_JUMP_DELAY, COND12);
 
        /* Toggle the true/false bit of the bcond.  */
        buffer[highbyte] ^= 0x2;
 
-       /* Build a relocation to six bytes farther on.  */
+       /* If this is a dalayed branch, we may not put the the bra in the
+          slot.  So we change it to a non-delayed branch, like that:
+          b! cond slot_label; bra disp; slot_label: slot_insn
+          ??? We should try if swapping the conditional branch and
+          its delay-slot insn already makes the branch reach.  */
+
+       /* Build a relocation to six / four bytes farther on.  */
        subseg_change (seg, 0);
        fix_new (fragP, fragP->fr_fix, 2,
 #ifdef BFD_ASSEMBLER
@@ -1460,7 +1622,7 @@ md_convert_frag (headers, seg, fragP)
 #else
                 seg_info (seg)->dot,
 #endif
-                fragP->fr_address + fragP->fr_fix + 6,
+                fragP->fr_address + fragP->fr_fix + (delay ? 4 : 6),
                 1, BFD_RELOC_SH_PCDISP8BY2);
 
        /* Set up a jump instruction.  */
@@ -1469,25 +1631,38 @@ md_convert_frag (headers, seg, fragP)
        fix_new (fragP, fragP->fr_fix + 2, 2, fragP->fr_symbol,
                 fragP->fr_offset, 1, BFD_RELOC_SH_PCDISP12BY2);
 
-       /* Fill in a NOP instruction.  */
-       buffer[highbyte + 4] = 0x0;
-       buffer[lowbyte + 4] = 0x9;
-
-       fragP->fr_fix += 6;
+       if (delay)
+         {
+           buffer[highbyte] &= ~0x4; /* Removes delay slot from branch.  */
+           fragP->fr_fix += 4;
+         }
+       else
+         {
+           /* Fill in a NOP instruction.  */
+           buffer[highbyte + 4] = 0x0;
+           buffer[lowbyte + 4] = 0x9;
+
+           fragP->fr_fix += 6;
+         }
        fragP->fr_var = 0;
        donerelax = 1;
       }
       break;
 
     case C (COND_JUMP, COND32):
+    case C (COND_JUMP_DELAY, COND32):
     case C (COND_JUMP, UNDEF_WORD_DISP):
+    case C (COND_JUMP_DELAY, UNDEF_WORD_DISP):
       if (fragP->fr_symbol == NULL)
-       as_bad ("at 0x%lx, displacement overflows 8-bit field"
+       as_bad (_("at 0x%lx, displacement overflows 8-bit field")
                (unsigned long) fragP->fr_address);
-      else  
-       as_bad ("at 0x%lx, displacement to %sdefined symbol %s overflows 8-bit field ",
+      else if (S_IS_DEFINED (fragP->fr_symbol))
+       as_bad (_("at 0x%lx, displacement to defined symbol %s overflows 8-bit field "),
+               (unsigned long) fragP->fr_address,              
+               S_GET_NAME (fragP->fr_symbol));
+      else
+       as_bad (_("at 0x%lx, displacement to undefined symbol %s overflows 8-bit field "),
                (unsigned long) fragP->fr_address,              
-               S_IS_DEFINED (fragP->fr_symbol) ? "" : "un",
                S_GET_NAME (fragP->fr_symbol));
 
 #if 0                          /* This code works, but generates poor code, and the compiler
@@ -1539,7 +1714,7 @@ md_convert_frag (headers, seg, fragP)
 
   if (donerelax && !sh_relax)
     as_warn_where (fragP->fr_file, fragP->fr_line,
-                  "overflow in branch to %s; converted into longer instruction sequence",
+                  _("overflow in branch to %s; converted into longer instruction sequence"),
                   (fragP->fr_symbol != NULL
                    ? S_GET_NAME (fragP->fr_symbol)
                    : ""));
@@ -1614,7 +1789,7 @@ sh_cons_align (nbytes)
   if (now_seg == absolute_section)
     {
       if ((abs_section_offset & ((1 << nalign) - 1)) != 0)
-       as_warn ("misaligned data");
+       as_warn (_("misaligned data"));
       return;
     }
 
@@ -1642,7 +1817,7 @@ sh_handle_align (frag)
 
   if (frag->fr_type == rs_align_code
       && frag->fr_next->fr_address - frag->fr_address - frag->fr_fix != 0)
-    as_warn_where (frag->fr_file, frag->fr_line, "misaligned data");
+    as_warn_where (frag->fr_file, frag->fr_line, _("misaligned data"));
 }
 
 /* This macro decides whether a particular reloc is an entry in a
@@ -1656,6 +1831,7 @@ sh_handle_align (frag)
 #define SWITCH_TABLE_CONS(fix)                         \
   ((fix)->fx_r_type == 0                               \
    && ((fix)->fx_size == 2                             \
+       || (fix)->fx_size == 1                          \
        || (fix)->fx_size == 4))
 #endif
 
@@ -1666,6 +1842,7 @@ sh_handle_align (frag)
    && S_GET_SEGMENT ((fix)->fx_subsy) == text_section  \
    && ((fix)->fx_r_type == BFD_RELOC_32                        \
        || (fix)->fx_r_type == BFD_RELOC_16             \
+       || (fix)->fx_r_type == BFD_RELOC_8              \
        || SWITCH_TABLE_CONS (fix)))
 
 /* See whether we need to force a relocation into the output file.
@@ -1676,6 +1853,11 @@ int
 sh_force_relocation (fix)
      fixS *fix;
 {
+
+  if (fix->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+      || fix->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+    return 1;
+
   if (! sh_relax)
     return 0;
 
@@ -1688,6 +1870,24 @@ sh_force_relocation (fix)
          || fix->fx_r_type == BFD_RELOC_SH_LABEL);
 }
 
+#ifdef OBJ_ELF
+boolean
+sh_fix_adjustable (fixP)
+   fixS *fixP;
+{
+
+  if (fixP->fx_addsy == NULL)
+    return 1;
+  
+  /* We need the symbol name for the VTABLE entries */
+  if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+      || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+    return 0;
+
+  return 1;
+}
+#endif
+
 /* Apply a fixup to the object file.  */
 
 #ifdef BFD_ASSEMBLER
@@ -1708,6 +1908,18 @@ md_apply_fix (fixP, val)
 #ifdef BFD_ASSEMBLER
   long val = *valp;
 #endif
+  long max, min;
+  int shift;
+
+#ifdef BFD_ASSEMBLER
+  /* adjust_reloc_syms won't convert a reloc against a weak symbol
+     into a reloc against a section, but bfd_install_relocation will
+     screw up if the symbol is defined, so we have to adjust val here
+     to avoid the screw up later.  */
+  if (fixP->fx_addsy != NULL
+      && S_IS_WEAK (fixP->fx_addsy))
+    val -= S_GET_VALUE  (fixP->fx_addsy);
+#endif
 
 #ifndef BFD_ASSEMBLER
   if (fixP->fx_r_type == 0)
@@ -1717,36 +1929,53 @@ md_apply_fix (fixP, val)
       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_SH_IMM8;
+       fixP->fx_r_type = BFD_RELOC_8;
       else
        abort ();
     }
 #endif
 
+  max = min = 0;
+  shift = 0;
   switch (fixP->fx_r_type)
     {
     case BFD_RELOC_SH_IMM4:
+      max = 0xf;
       *buf = (*buf & 0xf0) | (val & 0xf);
       break;
 
     case BFD_RELOC_SH_IMM4BY2:
+      max = 0xf;
+      shift = 1;
       *buf = (*buf & 0xf0) | ((val >> 1) & 0xf);
       break;
 
     case BFD_RELOC_SH_IMM4BY4:
+      max = 0xf;
+      shift = 2;
       *buf = (*buf & 0xf0) | ((val >> 2) & 0xf);
       break;
 
     case BFD_RELOC_SH_IMM8BY2:
+      max = 0xff;
+      shift = 1;
       *buf = val >> 1;
       break;
 
     case BFD_RELOC_SH_IMM8BY4:
+      max = 0xff;
+      shift = 2;
       *buf = val >> 2;
       break;
 
     case BFD_RELOC_8:
     case BFD_RELOC_SH_IMM8:
+      /* Sometimes the 8 bit value is sign extended (e.g., add) and
+         sometimes it is not (e.g., and).  We permit any 8 bit value.
+         Note that adding further restrictions may invalidate
+         reasonable looking assembly code, such as ``and -0x1,r0''.  */
+      max = 0xff;
+      min = - 0xff;
       *buf++ = val;
       break;
 
@@ -1766,28 +1995,28 @@ md_apply_fix (fixP, val)
         variable val.  */
       val = (val + 2) / 4;
       if (val & ~0xff)
-       as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far");
+       as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far"));
       buf[lowbyte] = val;
       break;
 
     case BFD_RELOC_SH_PCRELIMM8BY2:
       val /= 2;
       if (val & ~0xff)
-       as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far");
+       as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far"));
       buf[lowbyte] = val;
       break;
 
     case BFD_RELOC_SH_PCDISP8BY2:
       val /= 2;
       if (val < -0x80 || val > 0x7f)
-       as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far");
+       as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far"));
       buf[lowbyte] = val;
       break;
 
     case BFD_RELOC_SH_PCDISP12BY2:
       val /= 2;
       if (val < -0x800 || val >= 0x7ff)
-       as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far");
+       as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far"));
       buf[lowbyte] = val & 0xff;
       buf[highbyte] |= (val >> 8) & 0xf;
       break;
@@ -1835,17 +2064,37 @@ md_apply_fix (fixP, val)
       /* Nothing to do here.  */
       break;
 
+    case BFD_RELOC_VTABLE_INHERIT:
+    case BFD_RELOC_VTABLE_ENTRY:
+      fixP->fx_done = 0;
+#ifdef BFD_ASSEMBLER
+      return 0;
+#else
+      return;
+#endif
+
     default:
       abort ();
     }
 
+  if (shift != 0)
+    {
+      if ((val & ((1 << shift) - 1)) != 0)
+       as_bad_where (fixP->fx_file, fixP->fx_line, _("misaligned offset"));
+      if (val >= 0)
+       val >>= shift;
+      else
+       val = ((val >> shift)
+              | ((long) -1 & ~ ((long) -1 >> shift)));
+    }
+  if (max != 0 && (val < min || val > max))
+    as_bad_where (fixP->fx_file, fixP->fx_line, _("offset out of range"));
+
 #ifdef BFD_ASSEMBLER
   return 0;
 #endif
 }
 
-int md_long_jump_size;
-
 /* Called just before address relaxation.  Return the length
    by which a fragment must grow to reach it's destination.  */
 
@@ -1879,27 +2128,31 @@ md_estimate_size_before_relax (fragP, segment_type)
     default:
       abort ();
     case C (COND_JUMP, UNDEF_DISP):
+    case C (COND_JUMP_DELAY, UNDEF_DISP):
       /* used to be a branch to somewhere which was unknown */
       if (fragP->fr_symbol
          && S_GET_SEGMENT (fragP->fr_symbol) == segment_type)
        {
+         int what = GET_WHAT (fragP->fr_subtype);
          /* Got a symbol and it's defined in this segment, become byte
             sized - maybe it will fix up */
-         fragP->fr_subtype = C (COND_JUMP, COND8);
-         fragP->fr_var = md_relax_table[C (COND_JUMP, COND8)].rlx_length;
+         fragP->fr_subtype = C (what, COND8);
+         fragP->fr_var = md_relax_table[C (what, COND8)].rlx_length;
        }
       else if (fragP->fr_symbol)
        {
+         int what = GET_WHAT (fragP->fr_subtype);
          /* Its got a segment, but its not ours, so it will always be long */
-         fragP->fr_subtype = C (COND_JUMP, UNDEF_WORD_DISP);
-         fragP->fr_var = md_relax_table[C (COND_JUMP, COND32)].rlx_length;
-         return md_relax_table[C (COND_JUMP, COND32)].rlx_length;
+         fragP->fr_subtype = C (what, UNDEF_WORD_DISP);
+         fragP->fr_var = md_relax_table[C (what, COND32)].rlx_length;
+         return md_relax_table[C (what, COND32)].rlx_length;
        }
       else
        {
+         int what = GET_WHAT (fragP->fr_subtype);
          /* We know the abs value */
-         fragP->fr_subtype = C (COND_JUMP, COND8);
-         fragP->fr_var = md_relax_table[C (COND_JUMP, COND8)].rlx_length;
+         fragP->fr_subtype = C (what, COND8);
+         fragP->fr_var = md_relax_table[C (what, COND8)].rlx_length;
        }
 
       break;
@@ -1949,12 +2202,7 @@ sh_do_align (n, fill, len, max)
      int max;
 {
   if (fill == NULL
-#ifdef BFD_ASSEMBLER
-      && (now_seg->flags & SEC_CODE) != 0
-#else
-      && now_seg != data_section
-      && now_seg != bss_section
-#endif
+      && subseg_text_p (now_seg)
       && n > 1)
     {
       static const unsigned char big_nop_pattern[] = { 0x00, 0x09 };
@@ -2000,6 +2248,7 @@ static const struct reloc_map coff_reloc_map[] =
   { 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 },
@@ -2035,7 +2284,7 @@ sh_coff_reloc_mangle (seg, fix, intr, paddr)
          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",
+                     _("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;
@@ -2046,6 +2295,8 @@ sh_coff_reloc_mangle (seg, fix, intr, paddr)
 
       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
@@ -2136,7 +2387,8 @@ tc_gen_reloc (section, fixp)
   bfd_reloc_code_real_type r_type;
 
   rel = (arelent *) xmalloc (sizeof (arelent));
-  rel->sym_ptr_ptr = &fixp->fx_addsy->bsym;
+  rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
   r_type = fixp->fx_r_type;
@@ -2146,6 +2398,8 @@ tc_gen_reloc (section, fixp)
       rel->addend = rel->address - S_GET_VALUE (fixp->fx_subsy);
       if (r_type == BFD_RELOC_16)
        r_type = BFD_RELOC_SH_SWITCH16;
+      else if (r_type == BFD_RELOC_8)
+       r_type = BFD_RELOC_8_PCREL;
       else if (r_type == BFD_RELOC_32)
        r_type = BFD_RELOC_SH_SWITCH32;
       else
@@ -2157,6 +2411,9 @@ tc_gen_reloc (section, fixp)
     rel->addend = fixp->fx_offset;
   else if (r_type == BFD_RELOC_SH_ALIGN)
     rel->addend = fixp->fx_offset;
+  else if (r_type == BFD_RELOC_VTABLE_INHERIT
+           || r_type == BFD_RELOC_VTABLE_ENTRY)
+    rel->addend = fixp->fx_offset;
   else if (fixp->fx_pcrel)
     rel->addend = fixp->fx_addnumber;
   else
@@ -2166,7 +2423,7 @@ tc_gen_reloc (section, fixp)
   if (rel->howto == NULL)
     {
       as_bad_where (fixp->fx_file, fixp->fx_line,
-                   "Cannot represent relocation type %s",
+                   _("Cannot represent relocation type %s"),
                    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);