Thu Aug 30 12:05:13 2001 J"orn Rennecke <amylaar@redhat.com>
[binutils-gdb.git] / gas / config / tc-sh.c
index f2f27ade3d98ca882336d4914066dbbfa17a73a8..a1cb874743d4a0d35b901c7835c9e688c4a74758 100644 (file)
@@ -1,5 +1,6 @@
 /* tc-sh.c -- Assemble code for the Hitachi Super-H
-   Copyright (C) 1993, 94, 95, 96, 97, 98, 99, 2000 Free Software Foundation.
+   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+   Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -34,7 +35,6 @@
 #endif
 
 #include "dwarf2dbg.h"
-struct dwarf2_line_info debug_line;
 
 const char comment_chars[] = "!";
 const char line_separator_chars[] = ";";
@@ -93,8 +93,14 @@ const pseudo_typeS md_pseudo_table[] =
   {"uses", s_uses, 0},
   {"uaword", s_uacons, 2},
   {"ualong", s_uacons, 4},
-  { "file", dwarf2_directive_file, 0 },
-  { "loc", dwarf2_directive_loc, 0 },
+  {"uaquad", s_uacons, 8},
+  {"2byte", s_uacons, 2},
+  {"4byte", s_uacons, 4},
+  {"8byte", s_uacons, 8},
+#ifdef BFD_ASSEMBLER
+  {"file", dwarf2_directive_file, 0 },
+  {"loc", dwarf2_directive_loc, 0 },
+#endif
   {0, 0, 0}
 };
 
@@ -123,7 +129,6 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
 
 #define C(a,b) ENCODE_RELAX(a,b)
 
-#define JREG 14                        /* Register used as a temp when relaxing */
 #define ENCODE_RELAX(what,length) (((what) << 4) + (length))
 #define GET_WHAT(x) ((x>>4))
 
@@ -137,8 +142,6 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
 #define COND8  1
 #define COND12 2
 #define COND32 3
-#define UNCOND12 1
-#define UNCOND32 2
 #define UNDEF_WORD_DISP 4
 
 #define UNCOND12 1
@@ -187,7 +190,9 @@ const relax_typeS md_relax_table[C (END, 0)] = {
   { COND12_F, COND12_M, COND12_LENGTH, C (COND_JUMP, COND32), },
   /* C (COND_JUMP, COND32) */
   { COND32_F, COND32_M, COND32_LENGTH, 0, },
-  EMPTY, EMPTY, EMPTY, EMPTY,
+  /* C (COND_JUMP, UNDEF_WORD_DISP) */
+  { 0, 0, COND32_LENGTH, 0, },
+  EMPTY, EMPTY, EMPTY,
   EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
 
   EMPTY,
@@ -197,7 +202,9 @@ const relax_typeS md_relax_table[C (END, 0)] = {
   { COND12_F, COND12_M, COND12_DELAY_LENGTH, C (COND_JUMP_DELAY, COND32), },
   /* C (COND_JUMP_DELAY, COND32) */
   { COND32_F, COND32_M, COND32_LENGTH, 0, },
-  EMPTY, EMPTY, EMPTY, EMPTY,
+  /* C (COND_JUMP_DELAY, UNDEF_WORD_DISP) */
+  { 0, 0, COND32_LENGTH, 0, },
+  EMPTY, EMPTY, EMPTY,
   EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
 
   EMPTY,
@@ -205,7 +212,10 @@ const relax_typeS md_relax_table[C (END, 0)] = {
   { UNCOND12_F, UNCOND12_M, UNCOND12_LENGTH, C (UNCOND_JUMP, UNCOND32), },
   /* C (UNCOND_JUMP, UNCOND32) */
   { UNCOND32_F, UNCOND32_M, UNCOND32_LENGTH, 0, },
-  EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
+  EMPTY,
+  /* C (UNCOND_JUMP, UNDEF_WORD_DISP) */
+  { 0, 0, UNCOND32_LENGTH, 0, },
+  EMPTY, EMPTY, EMPTY,
   EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
 };
 
@@ -235,7 +245,7 @@ sh_elf_suffix (str_p, exp_p, new_exp_p)
   int len;
   struct map_bfd *ptr;
 
-#define MAP(str,reloc) { str, sizeof(str)-1, reloc }
+#define MAP(str,reloc) { str, sizeof (str)-1, reloc }
 
   static struct map_bfd mapping[] = {
     MAP ("got",                BFD_RELOC_32_GOT_PCREL),
@@ -390,7 +400,7 @@ sh_elf_cons (nbytes)
   input_line_pointer--;                /* Put terminator back into stream.  */
   if (*input_line_pointer == '#' || *input_line_pointer == '!')
     {
-       while (! is_end_of_line[*input_line_pointer++]);
+       while (! is_end_of_line[(unsigned char) *input_line_pointer++]);
     }
   else
     demand_empty_rest_of_line ();
@@ -464,13 +474,16 @@ parse_reg (src, mode, reg)
      int *mode;
      int *reg;
 {
+  char l0 = tolower (src[0]);
+  char l1 = l0 ? tolower (src[1]) : 0;
+
   /* We use ! IDENT_CHAR for the next character after the register name, to
      make sure that we won't accidentally recognize a symbol name such as
      'sram' or sr_ram as being a reference to the register 'sr'.  */
 
-  if (src[0] == 'r')
+  if (l0 == 'r')
     {
-      if (src[1] == '1')
+      if (l1 == '1')
        {
          if (src[2] >= '0' && src[2] <= '5'
              && ! IDENT_CHAR ((unsigned char) src[3]))
@@ -480,36 +493,36 @@ parse_reg (src, mode, reg)
              return 3;
            }
        }
-      if (src[1] >= '0' && src[1] <= '9'
+      if (l1 >= '0' && l1 <= '9'
          && ! IDENT_CHAR ((unsigned char) src[2]))
        {
          *mode = A_REG_N;
-         *reg = (src[1] - '0');
+         *reg = (l1 - '0');
          return 2;
        }
-      if (src[1] >= '0' && src[1] <= '7' && strncmp (&src[2], "_bank", 5) == 0
+      if (l1 >= '0' && l1 <= '7' && strncasecmp (&src[2], "_bank", 5) == 0
          && ! IDENT_CHAR ((unsigned char) src[7]))
        {
          *mode = A_REG_B;
-         *reg  = (src[1] - '0');
+         *reg  = (l1 - '0');
          return 7;
        }
 
-      if (src[1] == 'e' && ! IDENT_CHAR ((unsigned char) src[2]))
+      if (l1 == 'e' && ! IDENT_CHAR ((unsigned char) src[2]))
        {
          *mode = A_RE;
          return 2;
        }
-      if (src[1] == 's' && ! IDENT_CHAR ((unsigned char) src[2]))
+      if (l1 == 's' && ! IDENT_CHAR ((unsigned char) src[2]))
        {
          *mode = A_RS;
          return 2;
        }
     }
 
-  if (src[0] == 'a')
+  if (l0 == 'a')
     {
-      if (src[1] == '0')
+      if (l1 == '0')
        {
          if (! IDENT_CHAR ((unsigned char) src[2]))
            {
@@ -517,14 +530,14 @@ parse_reg (src, mode, reg)
              *reg = A_A0_NUM;
              return 2;
            }
-         if (src[2] == 'g' && ! IDENT_CHAR ((unsigned char) src[3]))
+         if (tolower (src[2]) == 'g' && ! IDENT_CHAR ((unsigned char) src[3]))
            {
              *mode = DSP_REG_N;
              *reg = A_A0G_NUM;
              return 3;
            }
        }
-      if (src[1] == '1')
+      if (l1 == '1')
        {
          if (! IDENT_CHAR ((unsigned char) src[2]))
            {
@@ -532,7 +545,7 @@ parse_reg (src, mode, reg)
              *reg = A_A1_NUM;
              return 2;
            }
-         if (src[2] == 'g' && ! IDENT_CHAR ((unsigned char) src[3]))
+         if (tolower (src[2]) == 'g' && ! IDENT_CHAR ((unsigned char) src[3]))
            {
              *mode = DSP_REG_N;
              *reg = A_A1G_NUM;
@@ -540,24 +553,24 @@ parse_reg (src, mode, reg)
            }
        }
 
-      if (src[1] == 'x' && src[2] >= '0' && src[2] <= '1'
+      if (l1 == 'x' && src[2] >= '0' && src[2] <= '1'
          && ! IDENT_CHAR ((unsigned char) src[3]))
        {
          *mode = A_REG_N;
-         *reg = 4 + (src[1] - '0');
+         *reg = 4 + (l1 - '0');
          return 3;
        }
-      if (src[1] == 'y' && src[2] >= '0' && src[2] <= '1'
+      if (l1 == 'y' && src[2] >= '0' && src[2] <= '1'
          && ! IDENT_CHAR ((unsigned char) src[3]))
        {
          *mode = A_REG_N;
-         *reg = 6 + (src[1] - '0');
+         *reg = 6 + (l1 - '0');
          return 3;
        }
-      if (src[1] == 's' && src[2] >= '0' && src[2] <= '3'
+      if (l1 == 's' && src[2] >= '0' && src[2] <= '3'
          && ! IDENT_CHAR ((unsigned char) src[3]))
        {
-         int n = src[1] - '0';
+         int n = l1 - '0';
 
          *mode = A_REG_N;
          *reg = n | ((~n & 2) << 1);
@@ -565,21 +578,21 @@ parse_reg (src, mode, reg)
        }
     }
 
-  if (src[0] == 'i' && src[1] && ! IDENT_CHAR ((unsigned char) src[3]))
+  if (l0 == 'i' && l1 && ! IDENT_CHAR ((unsigned char) src[3]))
     {
-      if (src[1] == 's')
+      if (l1 == 's')
        {
          *mode = A_REG_N;
          *reg = 8;
          return 2;
        }
-      if (src[1] == 'x')
+      if (l1 == 'x')
        {
          *mode = A_REG_N;
          *reg = 8;
          return 2;
        }
-      if (src[1] == 'y')
+      if (l1 == 'y')
        {
          *mode = A_REG_N;
          *reg = 9;
@@ -587,125 +600,125 @@ parse_reg (src, mode, reg)
        }
     }
 
-  if (src[0] == 'x' && src[1] >= '0' && src[1] <= '1'
+  if (l0 == 'x' && l1 >= '0' && l1 <= '1'
       && ! IDENT_CHAR ((unsigned char) src[2]))
     {
       *mode = DSP_REG_N;
-      *reg = A_X0_NUM + src[1] - '0';
+      *reg = A_X0_NUM + l1 - '0';
       return 2;
     }
 
-  if (src[0] == 'y' && src[1] >= '0' && src[1] <= '1'
+  if (l0 == 'y' && l1 >= '0' && l1 <= '1'
       && ! IDENT_CHAR ((unsigned char) src[2]))
     {
       *mode = DSP_REG_N;
-      *reg = A_Y0_NUM + src[1] - '0';
+      *reg = A_Y0_NUM + l1 - '0';
       return 2;
     }
 
-  if (src[0] == 'm' && src[1] >= '0' && src[1] <= '1'
+  if (l0 == 'm' && l1 >= '0' && l1 <= '1'
       && ! IDENT_CHAR ((unsigned char) src[2]))
     {
       *mode = DSP_REG_N;
-      *reg = src[1] == '0' ? A_M0_NUM : A_M1_NUM;
+      *reg = l1 == '0' ? A_M0_NUM : A_M1_NUM;
       return 2;
     }
 
-  if (src[0] == 's'
-      && src[1] == 's'
-      && src[2] == 'r' && ! IDENT_CHAR ((unsigned char) src[3]))
+  if (l0 == 's'
+      && l1 == 's'
+      && tolower (src[2]) == 'r' && ! IDENT_CHAR ((unsigned char) src[3]))
     {
       *mode = A_SSR;
       return 3;
     }
 
-  if (src[0] == 's' && src[1] == 'p' && src[2] == 'c'
+  if (l0 == 's' && l1 == 'p' && tolower (src[2]) == 'c'
       && ! IDENT_CHAR ((unsigned char) src[3]))
     {
       *mode = A_SPC;
       return 3;
     }
 
-  if (src[0] == 's' && src[1] == 'g' && src[2] == 'r'
+  if (l0 == 's' && l1 == 'g' && tolower (src[2]) == 'r'
       && ! IDENT_CHAR ((unsigned char) src[3]))
     {
       *mode = A_SGR;
       return 3;
     }
 
-  if (src[0] == 'd' && src[1] == 's' && src[2] == 'r'
+  if (l0 == 'd' && l1 == 's' && tolower (src[2]) == 'r'
       && ! IDENT_CHAR ((unsigned char) src[3]))
     {
       *mode = A_DSR;
       return 3;
     }
 
-  if (src[0] == 'd' && src[1] == 'b' && src[2] == 'r'
+  if (l0 == 'd' && l1 == 'b' && tolower (src[2]) == 'r'
       && ! IDENT_CHAR ((unsigned char) src[3]))
     {
       *mode = A_DBR;
       return 3;
     }
 
-  if (src[0] == 's' && src[1] == 'r' && ! IDENT_CHAR ((unsigned char) src[2]))
+  if (l0 == 's' && l1 == 'r' && ! IDENT_CHAR ((unsigned char) src[2]))
     {
       *mode = A_SR;
       return 2;
     }
 
-  if (src[0] == 's' && src[1] == 'p' && ! IDENT_CHAR ((unsigned char) src[2]))
+  if (l0 == 's' && l1 == 'p' && ! IDENT_CHAR ((unsigned char) src[2]))
     {
       *mode = A_REG_N;
       *reg = 15;
       return 2;
     }
 
-  if (src[0] == 'p' && src[1] == 'r' && ! IDENT_CHAR ((unsigned char) src[2]))
+  if (l0 == 'p' && l1 == 'r' && ! IDENT_CHAR ((unsigned char) src[2]))
     {
       *mode = A_PR;
       return 2;
     }
-  if (src[0] == 'p' && src[1] == 'c' && ! IDENT_CHAR ((unsigned char) src[2]))
+  if (l0 == 'p' && l1 == 'c' && ! IDENT_CHAR ((unsigned char) src[2]))
     {
       /* Don't use A_DISP_PC here - that would accept stuff like 'mova pc,r0'
          and use an uninitialized immediate.  */
       *mode = A_PC;
       return 2;
     }
-  if (src[0] == 'g' && src[1] == 'b' && src[2] == 'r'
+  if (l0 == 'g' && l1 == 'b' && tolower (src[2]) == 'r'
       && ! IDENT_CHAR ((unsigned char) src[3]))
     {
       *mode = A_GBR;
       return 3;
     }
-  if (src[0] == 'v' && src[1] == 'b' && src[2] == 'r'
+  if (l0 == 'v' && l1 == 'b' && tolower (src[2]) == 'r'
       && ! IDENT_CHAR ((unsigned char) src[3]))
     {
       *mode = A_VBR;
       return 3;
     }
 
-  if (src[0] == 'm' && src[1] == 'a' && src[2] == 'c'
+  if (l0 == 'm' && l1 == 'a' && tolower (src[2]) == 'c'
       && ! IDENT_CHAR ((unsigned char) src[4]))
     {
-      if (src[3] == 'l')
+      if (tolower (src[3]) == 'l')
        {
          *mode = A_MACL;
          return 4;
        }
-      if (src[3] == 'h')
+      if (tolower (src[3]) == 'h')
        {
          *mode = A_MACH;
          return 4;
        }
     }
-  if (src[0] == 'm' && src[1] == 'o' && src[2] == 'd'
+  if (l0 == 'm' && l1 == 'o' && tolower (src[2]) == 'd'
       && ! IDENT_CHAR ((unsigned char) src[4]))
     {
       *mode = A_MOD;
       return 3;
     }
-  if (src[0] == 'f' && src[1] == 'r')
+  if (l0 == 'f' && l1 == 'r')
     {
       if (src[2] == '1')
        {
@@ -725,7 +738,7 @@ parse_reg (src, mode, reg)
          return 3;
        }
     }
-  if (src[0] == 'd' && src[1] == 'r')
+  if (l0 == 'd' && l1 == 'r')
     {
       if (src[2] == '1')
        {
@@ -745,7 +758,7 @@ parse_reg (src, mode, reg)
          return 3;
        }
     }
-  if (src[0] == 'x' && src[1] == 'd')
+  if (l0 == 'x' && l1 == 'd')
     {
       if (src[2] == '1')
        {
@@ -765,7 +778,7 @@ parse_reg (src, mode, reg)
          return 3;
        }
     }
-  if (src[0] == 'f' && src[1] == 'v')
+  if (l0 == 'f' && l1 == 'v')
     {
       if (src[2] == '1'&& src[3] == '2' && ! IDENT_CHAR ((unsigned char) src[4]))
        {
@@ -781,22 +794,25 @@ parse_reg (src, mode, reg)
          return 3;
        }
     }
-  if (src[0] == 'f' && src[1] == 'p' && src[2] == 'u' && src[3] == 'l'
+  if (l0 == 'f' && l1 == 'p' && tolower (src[2]) == 'u'
+      && tolower (src[3]) == 'l'
       && ! IDENT_CHAR ((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' && ! IDENT_CHAR ((unsigned char) src[5]))
+  if (l0 == 'f' && l1 == 'p' && tolower (src[2]) == 's'
+      && tolower (src[3]) == 'c'
+      && tolower (src[4]) == 'r' && ! IDENT_CHAR ((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' && ! IDENT_CHAR ((unsigned char) src[5]))
+  if (l0 == 'x' && l1 == 'm' && tolower (src[2]) == 't'
+      && tolower (src[3]) == 'r'
+      && tolower (src[4]) == 'x' && ! IDENT_CHAR ((unsigned char) src[5]))
     {
       *mode = XMTRX_M4;
       return 5;
@@ -1863,7 +1879,7 @@ md_assemble (str)
   unsigned char *op_end;
   sh_operand_info operand[3];
   sh_opcode_info *opcode;
-  unsigned int size;
+  unsigned int size = 0;
 
   opcode = find_cooked_opcode (&str);
   op_end = str;
@@ -1931,20 +1947,9 @@ md_assemble (str)
        }
     }
 
-  if (debug_type == DEBUG_DWARF2)
-    {
-      bfd_vma addr;
-
-      /* First update the notion of the current source line.  */
-      dwarf2_where (&debug_line);
-
-      /* We want the offset of the start of this instruction within the
-        the current frag.  may be used later */
-      addr = frag_now->fr_address + frag_now_fix () - size;
-
-      /* And record the information.  */
-      dwarf2_gen_line_info (addr, &debug_line);
-    }
+#ifdef BFD_ASSEMBLER
+  dwarf2_emit_insn (size);
+#endif
 }
 
 /* This routine is called each time a label definition is seen.  It
@@ -2335,8 +2340,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 (symbol_get_frag (sym),
-              S_GET_VALUE (sym) - symbol_get_frag (sym)->fr_address,
+      fix_new (fscan->fx_frag,
+              S_GET_VALUE (sym) - fscan->fx_frag->fr_address,
               4, &abs_symbol, info.count, 0, BFD_RELOC_SH_COUNT);
     }
 }
@@ -2406,58 +2411,19 @@ 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"),
-               (unsigned long) fragP->fr_address);
+       as_bad_where (fragP->fr_file, fragP->fr_line,
+                     _("displacement overflows 12-bit field"));
       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));
+       as_bad_where (fragP->fr_file, fragP->fr_line,
+                     _("displacement to defined symbol %s overflows 12-bit field"),
+                     S_GET_NAME (fragP->fr_symbol));
       else
-       as_bad (_("at 0x%lx, displacement to undefined symbol %s overflows 12-bit field"),
-               (unsigned long) fragP->fr_address,
-               S_GET_NAME (fragP->fr_symbol));
-
-#if 0
-      /* This code works, but generates poor code and the compiler
-        should never produce a sequence that requires it to be used.  */
-
-      /* A jump wont fit in 12 bits, make code which looks like
-        bra foo
-        mov.w @(0, PC), r14
-        .long disp
-        foo: bra @r14
-        */
-      int t = buffer[0] & 0x10;
-
-      buffer[highbyte     ] = 0xa0;    /* branch over move and disp */
-      buffer[lowbyte      ] = 3;
-      buffer[highbyte +  2] = 0xd0 | JREG;     /* Build mov insn */
-      buffer[lowbyte  +  2] = 0x00;
-
-      buffer[highbyte +  4] = 0;       /* space for 32 bit jump disp */
-      buffer[lowbyte  +  4] = 0;
-      buffer[highbyte +  6] = 0;
-      buffer[lowbyte  +  6] = 0;
-
-      buffer[highbyte +  8] = 0x40 | JREG;     /* Build jmp @JREG */
-      buffer[lowbyte  +  8] = t ? 0xb : 0x2b;
-
-      buffer[highbyte + 10] = 0x20; /* build nop */
-      buffer[lowbyte  + 10] = 0x0b;
-
-      /* Make reloc for the long disp.  */
-      fix_new (fragP,
-              fragP->fr_fix + 4,
-              4,
-              fragP->fr_symbol,
-              fragP->fr_offset,
-              0,
-              BFD_RELOC_32);
-      fragP->fr_fix += UNCOND32_LENGTH;
+       as_bad_where (fragP->fr_file, fragP->fr_line,
+                     _("displacement to undefined symbol %s overflows 12-bit field"),
+                     S_GET_NAME (fragP->fr_symbol));
+      /* Stabilize this frag, so we don't trip an assert.  */
+      fragP->fr_fix += fragP->fr_var;
       fragP->fr_var = 0;
-      donerelax = 1;
-#endif
-
       break;
 
     case C (COND_JUMP, COND12):
@@ -2530,59 +2496,19 @@ md_convert_frag (headers, seg, fragP)
     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"),
-               (unsigned long) fragP->fr_address);
+       as_bad_where (fragP->fr_file, fragP->fr_line,
+                     _("displacement 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));
+       as_bad_where (fragP->fr_file, fragP->fr_line,
+                     _("displacement to defined symbol %s overflows 8-bit field"),
+                     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_GET_NAME (fragP->fr_symbol));
-
-#if 0
-      /* This code works, but generates poor code, and the compiler
-        should never produce a sequence that requires it to be used.  */
-
-      /* A bcond won't fit and it won't go into a 12 bit
-        displacement either, the code sequence looks like:
-        b!cond foop
-        mov.w @(n, PC), r14
-        jmp  @r14
-        nop
-        .long where
-        foop:
-        */
-
-      buffer[0] ^= 0x2;                /* Toggle T/F bit */
-#define JREG 14
-      buffer[1] = 5;           /* branch over mov, jump, nop and ptr */
-      buffer[2] = 0xd0 | JREG; /* Build mov insn */
-      buffer[3] = 0x2;
-      buffer[4] = 0x40 | JREG; /* Build jmp @JREG */
-      buffer[5] = 0x0b;
-      buffer[6] = 0x20;                /* build nop */
-      buffer[7] = 0x0b;
-      buffer[8] = 0;           /* space for 32 bit jump disp */
-      buffer[9] = 0;
-      buffer[10] = 0;
-      buffer[11] = 0;
-      buffer[12] = 0;
-      buffer[13] = 0;
-      /* Make reloc for the long disp */
-      fix_new (fragP,
-              fragP->fr_fix + 8,
-              4,
-              fragP->fr_symbol,
-              fragP->fr_offset,
-              0,
-              BFD_RELOC_32);
-      fragP->fr_fix += COND32_LENGTH;
+       as_bad_where (fragP->fr_file, fragP->fr_line,
+                     _("displacement to undefined symbol %s overflows 8-bit field "),
+                     S_GET_NAME (fragP->fr_symbol));
+      /* Stabilize this frag, so we don't trip an assert.  */
+      fragP->fr_fix += fragP->fr_var;
       fragP->fr_var = 0;
-      donerelax = 1;
-#endif
-
       break;
 
     default:
@@ -2599,7 +2525,7 @@ md_convert_frag (headers, seg, fragP)
 
 valueT
 md_section_align (seg, size)
-     segT seg;
+     segT seg ATTRIBUTE_UNUSED;
      valueT size;
 {
 #ifdef BFD_ASSEMBLER
@@ -2670,7 +2596,7 @@ sh_cons_align (nbytes)
       return;
     }
 
-  p = frag_var (rs_align_code, 1, 1, (relax_substateT) 0,
+  p = frag_var (rs_align_test, 1, 1, (relax_substateT) 0,
                (symbolS *) NULL, (offsetT) nalign, (char *) NULL);
 
   record_alignment (now_seg, nalign);
@@ -2684,17 +2610,47 @@ void
 sh_handle_align (frag)
      fragS *frag;
 {
+  int bytes = frag->fr_next->fr_address - frag->fr_address - frag->fr_fix;
+
+  if (frag->fr_type == rs_align_code)
+    {
+      static const unsigned char big_nop_pattern[] = { 0x00, 0x09 };
+      static const unsigned char little_nop_pattern[] = { 0x09, 0x00 };
+
+      char *p = frag->fr_literal + frag->fr_fix;
+
+      if (bytes & 1)
+       {
+         *p++ = 0;
+         bytes--;
+         frag->fr_fix += 1;
+       }
+
+      if (target_big_endian)
+       {
+         memcpy (p, big_nop_pattern, sizeof big_nop_pattern);
+         frag->fr_var = sizeof big_nop_pattern;
+       }
+      else
+       {
+         memcpy (p, little_nop_pattern, sizeof little_nop_pattern);
+         frag->fr_var = sizeof little_nop_pattern;
+       }
+    }
+  else if (frag->fr_type == rs_align_test)
+    {
+      if (bytes != 0)
+       as_warn_where (frag->fr_file, frag->fr_line, _("misaligned data"));
+    }
+
   if (sh_relax
-      && frag->fr_type == rs_align
+      && (frag->fr_type == rs_align
+         || frag->fr_type == rs_align_code)
       && frag->fr_address + frag->fr_fix > 0
       && frag->fr_offset > 1
       && now_seg != bss_section)
     fix_new (frag, frag->fr_fix, 2, &abs_symbol, frag->fr_offset, 0,
             BFD_RELOC_SH_ALIGN);
-
-  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"));
 }
 
 /* This macro decides whether a particular reloc is an entry in a
@@ -2865,8 +2821,17 @@ md_apply_fix (fixP, val)
   /* The function 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
+     to avoid the screw up later.
+
+     For ordinary relocs, this does not happen for ELF, since for ELF,
+     bfd_install_relocation uses the "special function" field of the
+     howto, and does not execute the code that needs to be undone, as long
+     as the special function does not return bfd_reloc_continue.
+     It can happen for GOT- and PLT-type relocs the way they are
+     described in elf32-sh.c as they use bfd_elf_generic_reloc, but it
+     doesn't matter here since those relocs don't use VAL; see below.  */
+  if (OUTPUT_FLAVOR != bfd_target_elf_flavour
+      && fixP->fx_addsy != NULL
       && S_IS_WEAK (fixP->fx_addsy))
     val -= S_GET_VALUE  (fixP->fx_addsy);
 #endif
@@ -2965,7 +2930,7 @@ md_apply_fix (fixP, val)
 
     case BFD_RELOC_SH_PCDISP12BY2:
       val /= 2;
-      if (val < -0x800 || val >= 0x7ff)
+      if (val < -0x800 || val > 0x7ff)
        as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far"));
       buf[lowbyte] = val & 0xff;
       buf[highbyte] |= (val >> 8) & 0xf;
@@ -3072,60 +3037,69 @@ md_estimate_size_before_relax (fragP, segment_type)
      register fragS *fragP;
      register segT segment_type;
 {
+  int what;
+
   switch (fragP->fr_subtype)
     {
+    default:
+      abort ();
+
     case C (UNCOND_JUMP, UNDEF_DISP):
       /* Used to be a branch to somewhere which was unknown.  */
       if (!fragP->fr_symbol)
        {
          fragP->fr_subtype = C (UNCOND_JUMP, UNCOND12);
-         fragP->fr_var = md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_length;
        }
       else if (S_GET_SEGMENT (fragP->fr_symbol) == segment_type)
        {
          fragP->fr_subtype = C (UNCOND_JUMP, UNCOND12);
-         fragP->fr_var = md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_length;
        }
       else
        {
          fragP->fr_subtype = C (UNCOND_JUMP, UNDEF_WORD_DISP);
-         fragP->fr_var = md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_length;
-         return md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_length;
        }
       break;
 
-    default:
-      abort ();
     case C (COND_JUMP, UNDEF_DISP):
     case C (COND_JUMP_DELAY, UNDEF_DISP):
+      what = GET_WHAT (fragP->fr_subtype);
       /* 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 (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 (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 (what, COND8);
-         fragP->fr_var = md_relax_table[C (what, COND8)].rlx_length;
        }
+      break;
 
+    case C (UNCOND_JUMP, UNCOND12):
+    case C (UNCOND_JUMP, UNCOND32):
+    case C (UNCOND_JUMP, UNDEF_WORD_DISP):
+    case C (COND_JUMP, COND8):
+    case C (COND_JUMP, COND12):
+    case C (COND_JUMP, COND32):
+    case C (COND_JUMP, UNDEF_WORD_DISP):
+    case C (COND_JUMP_DELAY, COND8):
+    case C (COND_JUMP_DELAY, COND12):
+    case C (COND_JUMP_DELAY, COND32):
+    case C (COND_JUMP_DELAY, UNDEF_WORD_DISP):
+      /* When relaxing a section for the second time, we don't need to
+        do anything besides return the current size.  */
       break;
     }
+
+  fragP->fr_var = md_relax_table[fragP->fr_subtype].rlx_length;
   return fragP->fr_var;
 }
 
@@ -3161,36 +3135,6 @@ tc_coff_sizemachdep (frag)
 
 #endif /* OBJ_COFF */
 
-/* When we align the .text section, insert the correct NOP pattern.  */
-
-int
-sh_do_align (n, fill, len, max)
-     int n;
-     const char *fill;
-     int len ATTRIBUTE_UNUSED;
-     int max;
-{
-  if (fill == NULL
-      && subseg_text_p (now_seg)
-      && n > 1)
-    {
-      static const unsigned char big_nop_pattern[] = { 0x00, 0x09 };
-      static const unsigned char little_nop_pattern[] = { 0x09, 0x00 };
-
-      /* First align to a 2 byte boundary, in case there is an odd
-         .byte.  */
-      frag_align (1, 0, 0);
-      if (target_big_endian)
-       frag_align_pattern (n, big_nop_pattern, sizeof big_nop_pattern, max);
-      else
-       frag_align_pattern (n, little_nop_pattern, sizeof little_nop_pattern,
-                           max);
-      return 1;
-    }
-
-  return 0;
-}
-
 #ifndef BFD_ASSEMBLER
 #ifdef OBJ_COFF
 
@@ -3413,10 +3357,3 @@ tc_gen_reloc (section, fixp)
 }
 
 #endif /* BFD_ASSEMBLER */
-
-void
-sh_finalize ()
-{
-  if (debug_type == DEBUG_DWARF2)
-    dwarf2_finish ();
-}