]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gas/config/tc-sh.c
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / gas / config / tc-sh.c
index acf62aef21d643947ecf64ef2cf22934a130a23f..78c3fca955a939b52ecf22edd89877fb5c7d46fe 100644 (file)
@@ -1,12 +1,11 @@
 /* tc-sh.c -- Assemble code for the Renesas / SuperH SH
-   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005  Free Software Foundation, Inc.
+   Copyright (C) 1993-2024 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,
 
 /* 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"
 #include "safe-ctype.h"
-#include "struc-symbol.h"
 
 #ifdef OBJ_ELF
 #include "elf/sh.h"
@@ -109,18 +105,6 @@ const pseudo_typeS md_pseudo_table[] =
   {"2byte", s_uacons, 2},
   {"4byte", s_uacons, 4},
   {"8byte", s_uacons, 8},
-#ifdef HAVE_SH64
-  {"mode", s_sh64_mode, 0 },
-
-  /* Have the old name too.  */
-  {"isa", s_sh64_mode, 0 },
-
-  /* Assert that the right ABI is used.  */
-  {"abi", s_sh64_abi, 0 },
-
-  { "vtable_inherit", sh64_vtable_inherit, 0 },
-  { "vtable_entry", sh64_vtable_entry, 0 },
-#endif /* HAVE_SH64 */
   {0, 0, 0}
 };
 
@@ -146,6 +130,11 @@ static unsigned int preset_target_arch;
    accommodate the insns seen so far.  */
 static unsigned int valid_arch;
 
+#ifdef OBJ_ELF
+/* Whether --fdpic was given.  */
+static int sh_fdpic;
+#endif
+
 const char EXP_CHARS[] = "eE";
 
 /* Chars that mean this number is a floating point constant.  */
@@ -165,31 +154,8 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
 #define COND_JUMP_DELAY 2
 #define UNCOND_JUMP  3
 
-#ifdef HAVE_SH64
-
-/* A 16-bit (times four) pc-relative operand, at most expanded to 32 bits.  */
-#define SH64PCREL16_32 4
-/* A 16-bit (times four) pc-relative operand, at most expanded to 64 bits.  */
-#define SH64PCREL16_64 5
-
-/* Variants of the above for adjusting the insn to PTA or PTB according to
-   the label.  */
-#define SH64PCREL16PT_32 6
-#define SH64PCREL16PT_64 7
-
-/* A MOVI expansion, expanding to at most 32 or 64 bits.  */
-#define MOVI_IMM_32 8
-#define MOVI_IMM_32_PCREL 9
-#define MOVI_IMM_64 10
-#define MOVI_IMM_64_PCREL 11
-#define END 12
-
-#else  /* HAVE_SH64 */
-
 #define END 4
 
-#endif /* HAVE_SH64 */
-
 #define UNDEF_DISP 0
 #define COND8  1
 #define COND12 2
@@ -199,24 +165,6 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
 #define UNCOND12 1
 #define UNCOND32 2
 
-#ifdef HAVE_SH64
-#define UNDEF_SH64PCREL 0
-#define SH64PCREL16 1
-#define SH64PCREL32 2
-#define SH64PCREL48 3
-#define SH64PCREL64 4
-#define SH64PCRELPLT 5
-
-#define UNDEF_MOVI 0
-#define MOVI_16 1
-#define MOVI_32 2
-#define MOVI_48 3
-#define MOVI_64 4
-#define MOVI_PLT 5
-#define MOVI_GOTOFF 6
-#define MOVI_GOTPC 7
-#endif /* HAVE_SH64 */
-
 /* Branch displacements are from the address of the branch plus
    four, thus all minimum and maximum values have 4 added to them.  */
 #define COND8_F 258
@@ -247,85 +195,6 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
 #define UNCOND32_M -(1<<30)
 #define UNCOND32_LENGTH 14
 
-#ifdef HAVE_SH64
-/* The trivial expansion of a SH64PCREL16 relaxation is just a "PT label,
-   TRd" as is the current insn, so no extra length.  Note that the "reach"
-   is calculated from the address *after* that insn, but the offset in the
-   insn is calculated from the beginning of the insn.  We also need to
-   take into account the implicit 1 coded as the "A" in PTA when counting
-   forward.  If PTB reaches an odd address, we trap that as an error
-   elsewhere, so we don't have to have different relaxation entries.  We
-   don't add a one to the negative range, since PTB would then have the
-   farthest backward-reaching value skipped, not generated at relaxation.  */
-#define SH64PCREL16_F (32767 * 4 - 4 + 1)
-#define SH64PCREL16_M (-32768 * 4 - 4)
-#define SH64PCREL16_LENGTH 0
-
-/* The next step is to change that PT insn into
-     MOVI ((label - datalabel Ln) >> 16) & 65535, R25
-     SHORI (label - datalabel Ln) & 65535, R25
-    Ln:
-     PTREL R25,TRd
-   which means two extra insns, 8 extra bytes.  This is the limit for the
-   32-bit ABI.
-
-   The expressions look a bit bad since we have to adjust this to avoid overflow on a
-   32-bit host.  */
-#define SH64PCREL32_F ((((long) 1 << 30) - 1) * 2 + 1 - 4)
-#define SH64PCREL32_LENGTH (2 * 4)
-
-/* Similarly, we just change the MOVI and add a SHORI for the 48-bit
-   expansion.  */
-#if BFD_HOST_64BIT_LONG
-/* The "reach" type is long, so we can only do this for a 64-bit-long
-   host.  */
-#define SH64PCREL32_M (((long) -1 << 30) * 2 - 4)
-#define SH64PCREL48_F ((((long) 1 << 47) - 1) - 4)
-#define SH64PCREL48_M (((long) -1 << 47) - 4)
-#define SH64PCREL48_LENGTH (3 * 4)
-#else
-/* If the host does not have 64-bit longs, just make this state identical
-   in reach to the 32-bit state.  Note that we have a slightly incorrect
-   reach, but the correct one above will overflow a 32-bit number.  */
-#define SH64PCREL32_M (((long) -1 << 30) * 2)
-#define SH64PCREL48_F SH64PCREL32_F
-#define SH64PCREL48_M SH64PCREL32_M
-#define SH64PCREL48_LENGTH (3 * 4)
-#endif /* BFD_HOST_64BIT_LONG */
-
-/* And similarly for the 64-bit expansion; a MOVI + SHORI + SHORI + SHORI
-   + PTREL sequence.  */
-#define SH64PCREL64_LENGTH (4 * 4)
-
-/* For MOVI, we make the MOVI + SHORI... expansion you can see in the
-   SH64PCREL expansions.  The PCREL one is similar, but the other has no
-   pc-relative reach; it must be fully expanded in
-   shmedia_md_estimate_size_before_relax.  */
-#define MOVI_16_LENGTH 0
-#define MOVI_16_F (32767 - 4)
-#define MOVI_16_M (-32768 - 4)
-#define MOVI_32_LENGTH 4
-#define MOVI_32_F ((((long) 1 << 30) - 1) * 2 + 1 - 4)
-#define MOVI_48_LENGTH 8
-
-#if BFD_HOST_64BIT_LONG
-/* The "reach" type is long, so we can only do this for a 64-bit-long
-   host.  */
-#define MOVI_32_M (((long) -1 << 30) * 2 - 4)
-#define MOVI_48_F ((((long) 1 << 47) - 1) - 4)
-#define MOVI_48_M (((long) -1 << 47) - 4)
-#else
-/* If the host does not have 64-bit longs, just make this state identical
-   in reach to the 32-bit state.  Note that we have a slightly incorrect
-   reach, but the correct one above will overflow a 32-bit number.  */
-#define MOVI_32_M (((long) -1 << 30) * 2)
-#define MOVI_48_F MOVI_32_F
-#define MOVI_48_M MOVI_32_M
-#endif /* BFD_HOST_64BIT_LONG */
-
-#define MOVI_64_LENGTH 12
-#endif /* HAVE_SH64 */
-
 #define EMPTY { 0, 0, 0, 0 }
 
 const relax_typeS md_relax_table[C (END, 0)] = {
@@ -367,126 +236,15 @@ const relax_typeS md_relax_table[C (END, 0)] = {
   EMPTY, EMPTY, EMPTY,
   EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
 
-#ifdef HAVE_SH64
-  /* C (SH64PCREL16_32, SH64PCREL16) */
-  EMPTY,
-  { SH64PCREL16_F, SH64PCREL16_M, SH64PCREL16_LENGTH, C (SH64PCREL16_32, SH64PCREL32) },
-  /* C (SH64PCREL16_32, SH64PCREL32) */
-  { 0, 0, SH64PCREL32_LENGTH, 0 },
-  EMPTY, EMPTY,
-  /* C (SH64PCREL16_32, SH64PCRELPLT) */
-  { 0, 0, SH64PCREL32_LENGTH, 0 },
-  EMPTY, EMPTY,
-  EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
-
-  /* C (SH64PCREL16_64, SH64PCREL16) */
-  EMPTY,
-  { SH64PCREL16_F, SH64PCREL16_M, SH64PCREL16_LENGTH, C (SH64PCREL16_64, SH64PCREL32) },
-  /* C (SH64PCREL16_64, SH64PCREL32) */
-  { SH64PCREL32_F, SH64PCREL32_M, SH64PCREL32_LENGTH, C (SH64PCREL16_64, SH64PCREL48) },
-  /* C (SH64PCREL16_64, SH64PCREL48) */
-  { SH64PCREL48_F, SH64PCREL48_M, SH64PCREL48_LENGTH, C (SH64PCREL16_64, SH64PCREL64) },
-  /* C (SH64PCREL16_64, SH64PCREL64) */
-  { 0, 0, SH64PCREL64_LENGTH, 0 },
-  /* C (SH64PCREL16_64, SH64PCRELPLT) */
-  { 0, 0, SH64PCREL64_LENGTH, 0 },
-  EMPTY, EMPTY,
-  EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
-
-  /* C (SH64PCREL16PT_32, SH64PCREL16) */
-  EMPTY,
-  { SH64PCREL16_F, SH64PCREL16_M, SH64PCREL16_LENGTH, C (SH64PCREL16PT_32, SH64PCREL32) },
-  /* C (SH64PCREL16PT_32, SH64PCREL32) */
-  { 0, 0, SH64PCREL32_LENGTH, 0 },
-  EMPTY, EMPTY,
-  /* C (SH64PCREL16PT_32, SH64PCRELPLT) */
-  { 0, 0, SH64PCREL32_LENGTH, 0 },
-  EMPTY, EMPTY,
-  EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
-
-  /* C (SH64PCREL16PT_64, SH64PCREL16) */
-  EMPTY,
-  { SH64PCREL16_F, SH64PCREL16_M, SH64PCREL16_LENGTH, C (SH64PCREL16PT_64, SH64PCREL32) },
-  /* C (SH64PCREL16PT_64, SH64PCREL32) */
-  { SH64PCREL32_F,
-    SH64PCREL32_M,
-    SH64PCREL32_LENGTH,
-    C (SH64PCREL16PT_64, SH64PCREL48) },
-  /* C (SH64PCREL16PT_64, SH64PCREL48) */
-  { SH64PCREL48_F, SH64PCREL48_M, SH64PCREL48_LENGTH, C (SH64PCREL16PT_64, SH64PCREL64) },
-  /* C (SH64PCREL16PT_64, SH64PCREL64) */
-  { 0, 0, SH64PCREL64_LENGTH, 0 },
-  /* C (SH64PCREL16PT_64, SH64PCRELPLT) */
-  { 0, 0, SH64PCREL64_LENGTH, 0},
-  EMPTY, EMPTY,
-  EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
-
-  /* C (MOVI_IMM_32, UNDEF_MOVI) */
-  { 0, 0, MOVI_32_LENGTH, 0 },
-  /* C (MOVI_IMM_32, MOVI_16) */
-  { MOVI_16_F, MOVI_16_M, MOVI_16_LENGTH, C (MOVI_IMM_32, MOVI_32) },
-  /* C (MOVI_IMM_32, MOVI_32) */
-  { MOVI_32_F, MOVI_32_M, MOVI_32_LENGTH, 0 },
-  EMPTY, EMPTY, EMPTY,
-  /* C (MOVI_IMM_32, MOVI_GOTOFF) */
-  { 0, 0, MOVI_32_LENGTH, 0 },
-  EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
-
-  /* C (MOVI_IMM_32_PCREL, MOVI_16) */
-  EMPTY,
-  { MOVI_16_F, MOVI_16_M, MOVI_16_LENGTH, C (MOVI_IMM_32_PCREL, MOVI_32) },
-  /* C (MOVI_IMM_32_PCREL, MOVI_32) */
-  { 0, 0, MOVI_32_LENGTH, 0 },
-  EMPTY, EMPTY,
-  /* C (MOVI_IMM_32_PCREL, MOVI_PLT) */
-  { 0, 0, MOVI_32_LENGTH, 0 },
-  EMPTY,
-  /* C (MOVI_IMM_32_PCREL, MOVI_GOTPC) */
-  { 0, 0, MOVI_32_LENGTH, 0 },
-  EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
-
-  /* C (MOVI_IMM_64, UNDEF_MOVI) */
-  { 0, 0, MOVI_64_LENGTH, 0 },
-  /* C (MOVI_IMM_64, MOVI_16) */
-  { MOVI_16_F, MOVI_16_M, MOVI_16_LENGTH, C (MOVI_IMM_64, MOVI_32) },
-  /* C (MOVI_IMM_64, MOVI_32) */
-  { MOVI_32_F, MOVI_32_M, MOVI_32_LENGTH, C (MOVI_IMM_64, MOVI_48) },
-  /* C (MOVI_IMM_64, MOVI_48) */
-  { MOVI_48_F, MOVI_48_M, MOVI_48_LENGTH, C (MOVI_IMM_64, MOVI_64) },
-  /* C (MOVI_IMM_64, MOVI_64) */
-  { 0, 0, MOVI_64_LENGTH, 0 },
-  EMPTY,
-  /* C (MOVI_IMM_64, MOVI_GOTOFF) */
-  { 0, 0, MOVI_64_LENGTH, 0 },
-  EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
-
-  /* C (MOVI_IMM_64_PCREL, MOVI_16) */
-  EMPTY,
-  { MOVI_16_F, MOVI_16_M, MOVI_16_LENGTH, C (MOVI_IMM_64_PCREL, MOVI_32) },
-  /* C (MOVI_IMM_64_PCREL, MOVI_32) */
-  { MOVI_32_F, MOVI_32_M, MOVI_32_LENGTH, C (MOVI_IMM_64_PCREL, MOVI_48) },
-  /* C (MOVI_IMM_64_PCREL, MOVI_48) */
-  { MOVI_48_F, MOVI_48_M, MOVI_48_LENGTH, C (MOVI_IMM_64_PCREL, MOVI_64) },
-  /* C (MOVI_IMM_64_PCREL, MOVI_64) */
-  { 0, 0, MOVI_64_LENGTH, 0 },
-  /* C (MOVI_IMM_64_PCREL, MOVI_PLT) */
-  { 0, 0, MOVI_64_LENGTH, 0 },
-  EMPTY,
-  /* C (MOVI_IMM_64_PCREL, MOVI_GOTPC) */
-  { 0, 0, MOVI_64_LENGTH, 0 },
-  EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
-
-#endif /* HAVE_SH64 */
-
 };
 
 #undef EMPTY
 
-static struct hash_control *opcode_hash_control;       /* Opcode mnemonics */
+static htab_t opcode_hash_control;     /* Opcode mnemonics */
 
 \f
 #ifdef OBJ_ELF
-/* Determinet whether the symbol needs any kind of PIC relocation.  */
+/* Determine whether the symbol needs any kind of PIC relocation.  */
 
 inline static int
 sh_PIC_related_p (symbolS *sym)
@@ -499,11 +257,6 @@ sh_PIC_related_p (symbolS *sym)
   if (sym == GOT_symbol)
     return 1;
 
-#ifdef HAVE_SH64
-  if (sh_PIC_related_p (*symbol_get_tc (sym)))
-    return 1;
-#endif
-
   exp = symbol_get_value_expression (sym);
 
   return (exp->X_op == O_PIC_reloc
@@ -565,47 +318,11 @@ sh_check_fixup (expressionS *main_exp, bfd_reloc_code_real_type *r_type_p)
 
   if (exp->X_op == O_symbol || exp->X_op == O_add || exp->X_op == O_subtract)
     {
-#ifdef HAVE_SH64
-      if (exp->X_add_symbol
-         && (exp->X_add_symbol == GOT_symbol
-             || (GOT_symbol
-                 && *symbol_get_tc (exp->X_add_symbol) == GOT_symbol)))
-       {
-         switch (*r_type_p)
-           {
-           case BFD_RELOC_SH_IMM_LOW16:
-             *r_type_p = BFD_RELOC_SH_GOTPC_LOW16;
-             break;
-
-           case BFD_RELOC_SH_IMM_MEDLOW16:
-             *r_type_p = BFD_RELOC_SH_GOTPC_MEDLOW16;
-             break;
-
-           case BFD_RELOC_SH_IMM_MEDHI16:
-             *r_type_p = BFD_RELOC_SH_GOTPC_MEDHI16;
-             break;
-
-           case BFD_RELOC_SH_IMM_HI16:
-             *r_type_p = BFD_RELOC_SH_GOTPC_HI16;
-             break;
-
-           case BFD_RELOC_NONE:
-           case BFD_RELOC_UNUSED:
-             *r_type_p = BFD_RELOC_SH_GOTPC;
-             break;
-
-           default:
-             abort ();
-           }
-         return 0;
-       }
-#else
       if (exp->X_add_symbol && exp->X_add_symbol == GOT_symbol)
        {
          *r_type_p = BFD_RELOC_SH_GOTPC;
          return 0;
        }
-#endif
       exp = symbol_get_value_expression (exp->X_add_symbol);
       if (! exp)
        return 0;
@@ -613,7 +330,6 @@ sh_check_fixup (expressionS *main_exp, bfd_reloc_code_real_type *r_type_p)
 
   if (exp->X_op == O_PIC_reloc)
     {
-#ifdef HAVE_SH64
       switch (*r_type_p)
        {
        case BFD_RELOC_NONE:
@@ -621,95 +337,23 @@ sh_check_fixup (expressionS *main_exp, bfd_reloc_code_real_type *r_type_p)
          *r_type_p = exp->X_md;
          break;
 
-       case BFD_RELOC_SH_IMM_LOW16:
+       case BFD_RELOC_SH_DISP20:
          switch (exp->X_md)
            {
-           case BFD_RELOC_32_GOTOFF:
-             *r_type_p = BFD_RELOC_SH_GOTOFF_LOW16;
-             break;
-
-           case BFD_RELOC_SH_GOTPLT32:
-             *r_type_p = BFD_RELOC_SH_GOTPLT_LOW16;
-             break;
-
            case BFD_RELOC_32_GOT_PCREL:
-             *r_type_p = BFD_RELOC_SH_GOT_LOW16;
-             break;
-
-           case BFD_RELOC_32_PLT_PCREL:
-             *r_type_p = BFD_RELOC_SH_PLT_LOW16;
+             *r_type_p = BFD_RELOC_SH_GOT20;
              break;
 
-           default:
-             abort ();
-           }
-         break;
-
-       case BFD_RELOC_SH_IMM_MEDLOW16:
-         switch (exp->X_md)
-           {
            case BFD_RELOC_32_GOTOFF:
-             *r_type_p = BFD_RELOC_SH_GOTOFF_MEDLOW16;
-             break;
-
-           case BFD_RELOC_SH_GOTPLT32:
-             *r_type_p = BFD_RELOC_SH_GOTPLT_MEDLOW16;
+             *r_type_p = BFD_RELOC_SH_GOTOFF20;
              break;
 
-           case BFD_RELOC_32_GOT_PCREL:
-             *r_type_p = BFD_RELOC_SH_GOT_MEDLOW16;
+           case BFD_RELOC_SH_GOTFUNCDESC:
+             *r_type_p = BFD_RELOC_SH_GOTFUNCDESC20;
              break;
 
-           case BFD_RELOC_32_PLT_PCREL:
-             *r_type_p = BFD_RELOC_SH_PLT_MEDLOW16;
-             break;
-
-           default:
-             abort ();
-           }
-         break;
-
-       case BFD_RELOC_SH_IMM_MEDHI16:
-         switch (exp->X_md)
-           {
-           case BFD_RELOC_32_GOTOFF:
-             *r_type_p = BFD_RELOC_SH_GOTOFF_MEDHI16;
-             break;
-
-           case BFD_RELOC_SH_GOTPLT32:
-             *r_type_p = BFD_RELOC_SH_GOTPLT_MEDHI16;
-             break;
-
-           case BFD_RELOC_32_GOT_PCREL:
-             *r_type_p = BFD_RELOC_SH_GOT_MEDHI16;
-             break;
-
-           case BFD_RELOC_32_PLT_PCREL:
-             *r_type_p = BFD_RELOC_SH_PLT_MEDHI16;
-             break;
-
-           default:
-             abort ();
-           }
-         break;
-
-       case BFD_RELOC_SH_IMM_HI16:
-         switch (exp->X_md)
-           {
-           case BFD_RELOC_32_GOTOFF:
-             *r_type_p = BFD_RELOC_SH_GOTOFF_HI16;
-             break;
-
-           case BFD_RELOC_SH_GOTPLT32:
-             *r_type_p = BFD_RELOC_SH_GOTPLT_HI16;
-             break;
-
-           case BFD_RELOC_32_GOT_PCREL:
-             *r_type_p = BFD_RELOC_SH_GOT_HI16;
-             break;
-
-           case BFD_RELOC_32_PLT_PCREL:
-             *r_type_p = BFD_RELOC_SH_PLT_HI16;
+           case BFD_RELOC_SH_GOTOFFFUNCDESC:
+             *r_type_p = BFD_RELOC_SH_GOTOFFFUNCDESC20;
              break;
 
            default:
@@ -720,9 +364,6 @@ sh_check_fixup (expressionS *main_exp, bfd_reloc_code_real_type *r_type_p)
        default:
          abort ();
        }
-#else
-      *r_type_p = exp->X_md;
-#endif
       if (exp == main_exp)
        exp->X_op = O_symbol;
       else
@@ -741,9 +382,10 @@ sh_check_fixup (expressionS *main_exp, bfd_reloc_code_real_type *r_type_p)
 /* Add expression EXP of SIZE bytes to offset OFF of fragment FRAG.  */
 
 void
-sh_cons_fix_new (fragS *frag, int off, int size, expressionS *exp)
+sh_cons_fix_new (fragS *frag, int off, int size, expressionS *exp,
+                bfd_reloc_code_real_type r_type)
 {
-  bfd_reloc_code_real_type r_type = BFD_RELOC_UNUSED;
+  r_type = BFD_RELOC_UNUSED;
 
   if (sh_check_fixup (exp, &r_type))
     as_bad (_("Invalid PIC expression."));
@@ -763,11 +405,9 @@ sh_cons_fix_new (fragS *frag, int off, int size, expressionS *exp)
        r_type = BFD_RELOC_32;
        break;
 
-#ifdef HAVE_SH64
       case 8:
        r_type = BFD_RELOC_64;
        break;
-#endif
 
       default:
        goto error;
@@ -788,20 +428,10 @@ sh_cons_fix_new (fragS *frag, int off, int size, expressionS *exp)
 /* Clobbers input_line_pointer, checks end-of-line.  */
 /* NBYTES 1=.byte, 2=.word, 4=.long */
 static void
-sh_elf_cons (register int nbytes)
+sh_elf_cons (int nbytes)
 {
   expressionS exp;
 
-#ifdef HAVE_SH64
-
-  /* Update existing range to include a previous insn, if there was one.  */
-  sh64_update_contents_mark (TRUE);
-
-  /* We need to make sure the contents type is set to data.  */
-  sh64_flag_output ();
-
-#endif /* HAVE_SH64 */
-
   if (is_it_end_of_statement ())
     {
       demand_empty_rest_of_line ();
@@ -827,8 +457,98 @@ 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 bool
+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))
+    {
+      offsetT symval_diff = S_GET_VALUE (l->X_add_symbol)
+                           - S_GET_VALUE (r->X_add_symbol);
+      subtract_from_result (l, r->X_add_number, r->X_extrabit);
+      subtract_from_result (l, frag_off / OCTETS_PER_BYTE, 0);
+      add_to_result (l, symval_diff, symval_diff < 0);
+      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.  */
@@ -837,18 +557,14 @@ void
 md_begin (void)
 {
   const sh_opcode_info *opcode;
-  char *prev_name = "";
+  const char *prev_name = "";
   unsigned int target_arch;
 
   target_arch
     = preset_target_arch ? preset_target_arch : arch_sh_up & ~arch_sh_has_dsp;
   valid_arch = target_arch;
 
-#ifdef HAVE_SH64
-  shmedia_md_begin ();
-#endif
-
-  opcode_hash_control = hash_new ();
+  opcode_hash_control = str_htab_create ();
 
   /* Insert unique names into hash table.  */
   for (opcode = sh_table; opcode->name; opcode++)
@@ -858,7 +574,7 @@ md_begin (void)
          if (!SH_MERGE_ARCH_SET_VALID (opcode->arch, target_arch))
            continue;
          prev_name = opcode->name;
-         hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
+         str_hash_insert (opcode_hash_control, opcode->name, opcode, 0);
        }
     }
 }
@@ -874,7 +590,7 @@ static int reg_b;
 /* Try to parse a reg name.  Return the number of chars consumed.  */
 
 static unsigned int
-parse_reg_without_prefix (char *src, int *mode, int *reg)
+parse_reg_without_prefix (char *src, sh_arg_type *mode, int *reg)
 {
   char l0 = TOLOWER (src[0]);
   char l1 = l0 ? TOLOWER (src[1]) : 0;
@@ -1233,7 +949,7 @@ parse_reg_without_prefix (char *src, int *mode, int *reg)
    $-prefixed register names if enabled by the user.  */
 
 static unsigned int
-parse_reg (char *src, int *mode, int *reg)
+parse_reg (char *src, sh_arg_type *mode, int *reg)
 {
   unsigned int prefix;
   unsigned int consumed;
@@ -1250,7 +966,7 @@ parse_reg (char *src, int *mode, int *reg)
     }
   else
     prefix = 0;
-  
+
   consumed = parse_reg_without_prefix (src, mode, reg);
 
   if (consumed == 0)
@@ -1263,22 +979,16 @@ 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;
   expression (&op->immediate);
   if (op->immediate.X_op == O_absent)
     as_bad (_("missing operand"));
-#ifdef OBJ_ELF
-  else if (op->immediate.X_op == O_PIC_reloc
-          || sh_PIC_related_p (op->immediate.X_add_symbol)
-          || 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:
@@ -1304,7 +1014,7 @@ static char *
 parse_at (char *src, sh_operand_info *op)
 {
   int len;
-  int mode;
+  sh_arg_type mode;
   src++;
   if (src[0] == '@')
     {
@@ -1476,7 +1186,7 @@ static void
 get_operand (char **ptr, sh_operand_info *op)
 {
   char *src = *ptr;
-  int mode = -1;
+  sh_arg_type mode = (sh_arg_type) -1;
   unsigned int len;
 
   if (src[0] == '#')
@@ -1512,6 +1222,10 @@ static char *
 get_operands (sh_opcode_info *info, char *args, sh_operand_info *operand)
 {
   char *ptr = args;
+
+  operand[0].type = 0;
+  operand[1].type = 0;
+  operand[2].type = 0;
   if (info->arg[0])
     {
       /* The pre-processor will eliminate whitespace in front of '@'
@@ -1524,9 +1238,7 @@ get_operands (sh_opcode_info *info, char *args, sh_operand_info *operand)
       if (info->arg[1])
        {
          if (*ptr == ',')
-           {
-             ptr++;
-           }
+           ptr++;
          get_operand (&ptr, operand + 1);
          /* ??? Hack: psha/pshl have a varying operand number depending on
             the type of the first operand.  We handle this by having the
@@ -1537,28 +1249,11 @@ get_operands (sh_opcode_info *info, char *args, sh_operand_info *operand)
          if (info->arg[2] && operand[0].type != A_IMM)
            {
              if (*ptr == ',')
-               {
-                 ptr++;
-               }
+               ptr++;
              get_operand (&ptr, operand + 2);
            }
-         else
-           {
-             operand[2].type = 0;
-           }
-       }
-      else
-       {
-         operand[1].type = 0;
-         operand[2].type = 0;
        }
     }
-  else
-    {
-      operand[0].type = 0;
-      operand[1].type = 0;
-      operand[2].type = 0;
-    }
   return ptr;
 }
 
@@ -1570,7 +1265,7 @@ static sh_opcode_info *
 get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
 {
   sh_opcode_info *this_try = opcode;
-  char *name = opcode->name;
+  const char *name = opcode->name;
   int n = 0;
 
   while (opcode->name)
@@ -1592,36 +1287,6 @@ 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:
@@ -2115,6 +1780,36 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
              printf (_("unhandled %d\n"), arg);
              goto fail;
            }
+         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;
+                 }
+           }
        }
       if ( !SH_MERGE_ARCH_SET_VALID (valid_arch, this_try->arch))
        goto fail;
@@ -2128,7 +1823,8 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
 }
 
 static void
-insert (char *where, int how, int pcrel, sh_operand_info *op)
+insert (char *where, bfd_reloc_code_real_type how, int pcrel,
+               sh_operand_info *op)
 {
   fix_new_exp (frag_now,
               where - frag_now->fr_literal,
@@ -2139,7 +1835,8 @@ insert (char *where, int how, int pcrel, sh_operand_info *op)
 }
 
 static void
-insert4 (char * where, int how, int pcrel, sh_operand_info * op)
+insert4 (char * where, bfd_reloc_code_real_type how, int pcrel,
+        sh_operand_info * op)
 {
   fix_new_exp (frag_now,
               where - frag_now->fr_literal,
@@ -2185,7 +1882,6 @@ build_relax (sh_opcode_info *opcode, sh_operand_info *op)
 static char *
 insert_loop_bounds (char *output, sh_operand_info *operand)
 {
-  char *name;
   symbolS *end_sym;
 
   /* Since the low byte of the opcode will be overwritten by the reloc, we
@@ -2198,6 +1894,8 @@ insert_loop_bounds (char *output, sh_operand_info *operand)
   if (sh_relax)
     {
       static int count = 0;
+      char name[11];
+      expressionS *symval;
 
       /* If the last loop insn is a two-byte-insn, it is in danger of being
         swapped with the insn after it.  To prevent this, create a new
@@ -2206,16 +1904,16 @@ insert_loop_bounds (char *output, sh_operand_info *operand)
         right in the middle, but four byte insns are not swapped anyways.  */
       /* A REPEAT takes 6 bytes.  The SH has a 32 bit address space.
         Hence a 9 digit number should be enough to count all REPEATs.  */
-      name = alloca (11);
       sprintf (name, "_R%x", count++ & 0x3fffffff);
-      end_sym = symbol_new (name, undefined_section, 0, &zero_address_frag);
+      end_sym = symbol_new (name, undefined_section, &zero_address_frag, 0);
       /* Make this a local symbol.  */
 #ifdef OBJ_COFF
       SF_SET_LOCAL (end_sym);
 #endif /* OBJ_COFF */
       symbol_table_insert (end_sym);
-      end_sym->sy_value = operand[1].immediate;
-      end_sym->sy_value.X_add_number += 2;
+      symval = symbol_get_value_expression (end_sym);
+      *symval = operand[1].immediate;
+      symval->X_add_number += 2;
       fix_new (frag_now, frag_now_fix (), 2, end_sym, 0, 1, BFD_RELOC_SH_LABEL);
     }
 
@@ -2233,12 +1931,16 @@ insert_loop_bounds (char *output, sh_operand_info *operand)
 static unsigned int
 build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
 {
-  int index;
+  int indx;
   char nbuf[8];
   char *output;
   unsigned int size = 2;
   int low_byte = target_big_endian ? 1 : 0;
   int max_index = 4;
+  bfd_reloc_code_real_type r_type;
+#ifdef OBJ_ELF
+  int unhandled_pic = 0;
+#endif
 
   nbuf[0] = 0;
   nbuf[1] = 0;
@@ -2249,6 +1951,16 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
   nbuf[6] = 0;
   nbuf[7] = 0;
 
+#ifdef OBJ_ELF
+  for (indx = 0; indx < 3; indx++)
+    if (opcode->arg[indx] == A_IMM
+       && operand[indx].type == A_IMM
+       && (operand[indx].immediate.X_op == O_PIC_reloc
+           || sh_PIC_related_p (operand[indx].immediate.X_add_symbol)
+           || sh_PIC_related_p (operand[indx].immediate.X_op_symbol)))
+      unhandled_pic = 1;
+#endif
+
   if (SH_MERGE_ARCH_SET (opcode->arch, arch_op32))
     {
       output = frag_more (4);
@@ -2258,12 +1970,12 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
   else
     output = frag_more (2);
 
-  for (index = 0; index < max_index; 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
        {
@@ -2271,32 +1983,34 @@ 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[index] |= 0x08;
+             nbuf[indx] |= 0x08;
+             /* Fall through.  */
            case IMM0_3c:
              insert (output + low_byte, BFD_RELOC_SH_IMM3, 0, operand);
              break;
            case IMM0_3Us:
-             nbuf[index] |= 0x80;
+             nbuf[indx] |= 0x80;
+             /* Fall through.  */
            case IMM0_3Uc:
              insert (output + low_byte, BFD_RELOC_SH_IMM3U, 0, operand);
              break;
@@ -2327,7 +2041,13 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
            case IMM0_20_4:
              break;
            case IMM0_20:
-             insert4 (output, BFD_RELOC_SH_DISP20, 0, operand);
+             r_type = BFD_RELOC_SH_DISP20;
+#ifdef OBJ_ELF
+             if (sh_check_fixup (&operand->immediate, &r_type))
+               as_bad (_("Invalid PIC expression."));
+             unhandled_pic = 0;
+#endif
+             insert4 (output, r_type, 0, operand);
              break;
            case IMM0_20BY8:
              insert4 (output, BFD_RELOC_SH_DISP20BY8, 0, operand);
@@ -2356,7 +2076,8 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
            case IMM0_8BY2:
              insert (output + low_byte, BFD_RELOC_SH_IMM8BY2, 0, operand);
              break;
-           case IMM0_8:
+           case IMM0_8U:
+           case IMM0_8S:
              insert (output + low_byte, BFD_RELOC_SH_IMM8, 0, operand);
              break;
            case IMM1_8BY4:
@@ -2378,7 +2099,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:
@@ -2386,6 +2107,10 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
            }
        }
     }
+#ifdef OBJ_ELF
+  if (unhandled_pic)
+    as_bad (_("misplaced PIC operand"));
+#endif
   if (!target_big_endian)
     {
       output[1] = (nbuf[0] << 4) | (nbuf[1]);
@@ -2422,7 +2147,7 @@ find_cooked_opcode (char **str_p)
   unsigned char *op_start;
   unsigned char *op_end;
   char name[20];
-  int nlen = 0;
+  unsigned int nlen = 0;
 
   /* Drop leading whitespace.  */
   while (*str == ' ')
@@ -2434,7 +2159,7 @@ find_cooked_opcode (char **str_p)
      assemble_ppi, so the opcode might be terminated by an '@'.  */
   for (op_start = op_end = (unsigned char *) str;
        *op_end
-       && nlen < 20
+       && nlen < sizeof (name) - 1
        && !is_end_of_line[*op_end] && *op_end != ' ' && *op_end != '@';
        op_end++)
     {
@@ -2456,7 +2181,7 @@ find_cooked_opcode (char **str_p)
   if (nlen == 0)
     as_bad (_("can't find opcode "));
 
-  return (sh_opcode_info *) hash_find (opcode_hash_control, name);
+  return (sh_opcode_info *) str_hash_find (opcode_hash_control, name);
 }
 
 /* Assemble a parallel processing insn.  */
@@ -2465,12 +2190,12 @@ find_cooked_opcode (char **str_p)
 static unsigned int
 assemble_ppi (char *op_end, sh_opcode_info *opcode)
 {
-  int movx = 0;
-  int movy = 0;
-  int cond = 0;
-  int field_b = 0;
+  unsigned int movx = 0;
+  unsigned int movy = 0;
+  unsigned int cond = 0;
+  unsigned int field_b = 0;
   char *output;
-  int move_code;
+  unsigned int move_code;
   unsigned int size;
 
   for (;;)
@@ -2724,7 +2449,7 @@ assemble_ppi (char *op_end, sh_opcode_info *opcode)
   if (field_b)
     {
       /* Parallel processing insn.  */
-      unsigned long ppi_code = (movx | movy | 0xf800) << 16 | field_b;
+      unsigned int ppi_code = (movx | movy | 0xf800) << 16 | field_b;
 
       output = frag_more (4);
       size = 4;
@@ -2772,33 +2497,13 @@ md_assemble (char *str)
   unsigned int size = 0;
   char *initial_str = str;
 
-#ifdef HAVE_SH64
-  if (sh64_isa_mode == sh64_isa_shmedia)
-    {
-      shmedia_md_assemble (str);
-      return;
-    }
-  else
-    {
-      /* If we've seen pseudo-directives, make sure any emitted data or
-        frags are marked as data.  */
-      if (!seen_insn)
-       {
-         sh64_update_contents_mark (TRUE);
-         sh64_set_contents_type (CRT_SH5_ISA16);
-       }
-
-      seen_insn = TRUE;
-    }
-#endif /* HAVE_SH64 */
-
   opcode = find_cooked_opcode (&str);
   op_end = str;
 
   if (opcode == NULL)
     {
       /* The opcode is not in the hash table.
-        This means we definately have an assembly failure,
+        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. */
@@ -2806,37 +2511,31 @@ md_assemble (char *str)
       char *name = initial_str;
       int name_length = 0;
       const sh_opcode_info *op;
-      int found = 0;
+      bool found = false;
 
-      /* identify opcode in string */
+      /* Identify opcode in string.  */
       while (ISSPACE (*name))
-       {
-         name++;
-       }
-      while (!ISSPACE (name[name_length]))
-       {
-         name_length++;
-       }
+       name++;
 
-      /* search for opcode in full list */
+      while (name[name_length] != '\0' && !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;
+             found = true;
              break;
            }
        }
 
-      if ( found )
-       {
-         as_bad (_("opcode not valid for this cpu variant"));
-       }
+      if (found)
+       as_bad (_("opcode not valid for this cpu variant"));
       else
-       {
-         as_bad (_("unknown opcode"));
-       }
+       as_bad (_("unknown opcode"));
+
       return;
     }
 
@@ -2867,6 +2566,9 @@ md_assemble (char *str)
            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
        {
@@ -2955,61 +2657,11 @@ md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
 }
 
 /* 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 *
+const 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
@@ -3049,12 +2701,9 @@ enum options
   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,
+  OPTION_H_TICK_HEX,
+#ifdef OBJ_ELF
+  OPTION_FDPIC,
 #endif
   OPTION_DUMMY  /* Not used.  This is just here to make it easy to add and subtract options from this enum.  */
 };
@@ -3065,26 +2714,28 @@ struct option md_longopts[] =
   {"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},
   {"renesas", no_argument, NULL, OPTION_RENESAS},
   {"allow-reg-prefix", no_argument, NULL, OPTION_ALLOW_REG_PREFIX},
 
-#ifdef HAVE_SH64
-  {"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  },
+
+#ifdef OBJ_ELF
+  {"fdpic", no_argument, NULL, OPTION_FDPIC},
+#endif
 
   {NULL, no_argument, NULL, 0}
 };
 size_t md_longopts_size = sizeof (md_longopts);
 
 int
-md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
+md_parse_option (int c, const char *arg ATTRIBUTE_UNUSED)
 {
   switch (c)
     {
@@ -3123,22 +2774,6 @@ md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
        preset_target_arch = arch_sh_up & ~arch_sh_has_dsp;
       else if (strcasecmp (arg, "any") == 0)
        preset_target_arch = arch_sh_up;
-#ifdef HAVE_SH64
-      else if (strcasecmp (arg, "shmedia") == 0)
-       {
-         if (sh64_isa_mode == sh64_isa_shcompact)
-           as_bad (_("Invalid combination: --isa=SHcompact with --isa=SHmedia"));
-         sh64_isa_mode = sh64_isa_shmedia;
-       }
-      else if (strcasecmp (arg, "shcompact") == 0)
-       {
-         if (sh64_isa_mode == sh64_isa_shmedia)
-           as_bad (_("Invalid combination: --isa=SHmedia with --isa=SHcompact"));
-         if (sh64_abi == sh64_abi_64)
-           as_bad (_("Invalid combination: --abi=64 with --isa=SHcompact"));
-         sh64_isa_mode = sh64_isa_shcompact;
-       }
-#endif /* HAVE_SH64 */
       else
        {
          extern const bfd_arch_info_type bfd_sh_arch;
@@ -3148,10 +2783,7 @@ md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
          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;
 
@@ -3165,48 +2797,21 @@ md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
                continue;
              break;
            }
-         
-         if (!preset_target_arch)
-           as_bad ("Invalid argument to --isa option: %s", arg);
-       }
-      break;
 
-#ifdef HAVE_SH64
-    case OPTION_ABI:
-      if (strcmp (arg, "32") == 0)
-       {
-         if (sh64_abi == sh64_abi_64)
-           as_bad (_("Invalid combination: --abi=32 with --abi=64"));
-         sh64_abi = sh64_abi_32;
-       }
-      else if (strcmp (arg, "64") == 0)
-       {
-         if (sh64_abi == sh64_abi_32)
-           as_bad (_("Invalid combination: --abi=64 with --abi=32"));
-         if (sh64_isa_mode == sh64_isa_shcompact)
-           as_bad (_("Invalid combination: --isa=SHcompact with --abi=64"));
-         sh64_abi = sh64_abi_64;
+         if (!preset_target_arch)
+           as_bad (_("Invalid argument to --isa option: %s"), arg);
        }
-      else
-       as_bad ("Invalid argument to --abi option: %s", arg);
-      break;
-
-    case OPTION_NO_MIX:
-      sh64_mix = FALSE;
       break;
 
-    case OPTION_SHCOMPACT_CONST_CRANGE:
-      sh64_shcompact_const_crange = TRUE;
+    case OPTION_H_TICK_HEX:
+      enable_h_tick_hex = 1;
       break;
 
-    case OPTION_NO_EXPAND:
-      sh64_expand = FALSE;
-      break;
-
-    case OPTION_PT32:
-      sh64_pt32 = TRUE;
+#ifdef OBJ_ELF
+    case OPTION_FDPIC:
+      sh_fdpic = true;
       break;
-#endif /* HAVE_SH64 */
+#endif /* OBJ_ELF */
 
     default:
       return 0;
@@ -3236,30 +2841,16 @@ SH options:\n\
     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    | %s", bfd_arch->printable_name);
+       fprintf (stream, "\n    | %s-up", bfd_arch->printable_name);
+      }
   }
   fprintf (stream, "]\n");
-#ifdef HAVE_SH64
-  fprintf (stream, _("\
---isa=[shmedia         set as the default instruction set for SH64\n\
-    | SHmedia\n\
-    | shcompact\n\
-    | SHcompact]\n"));
+#ifdef OBJ_ELF
   fprintf (stream, _("\
---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 code sections\n\
---no-mix               disallow SHmedia code in the same section as\n\
-                       constants and SHcompact code\n\
---no-expand            do not expand MOVI, PT, PTA or PTB instructions\n\
---expand-pt32          with -abi=64, expand PT, PTA and PTB instructions\n\
-                       to 32 bits only\n"));
-#endif /* HAVE_SH64 */
+--fdpic                        generate an FDPIC object file\n"));
+#endif /* OBJ_ELF */
 }
 \f
 /* This struct is used to pass arguments to sh_count_relocs through
@@ -3408,10 +2999,6 @@ sh_frob_section (bfd *abfd ATTRIBUTE_UNUSED, segT sec,
 void
 sh_frob_file (void)
 {
-#ifdef HAVE_SH64
-  shmedia_frob_file_before_adjust ();
-#endif
-
   if (! sh_relax)
     return;
 
@@ -3479,7 +3066,7 @@ md_convert_frag (bfd *headers ATTRIBUTE_UNUSED, segT seg, fragS *fragP)
         differently from ones without delay slots.  */
       {
        unsigned char *buffer =
-         (unsigned char *) (fragP->fr_fix + fragP->fr_literal);
+         (unsigned char *) (fragP->fr_fix + &fragP->fr_literal[0]);
        int highbyte = target_big_endian ? 0 : 1;
        int lowbyte = target_big_endian ? 1 : 0;
        int delay = fragP->fr_subtype == C (COND_JUMP_DELAY, COND12);
@@ -3544,11 +3131,7 @@ md_convert_frag (bfd *headers ATTRIBUTE_UNUSED, segT seg, fragS *fragP)
       break;
 
     default:
-#ifdef HAVE_SH64
-      shmedia_md_convert_frag (headers, seg, fragP, TRUE);
-#else
       abort ();
-#endif
     }
 
   if (donerelax && !sh_relax)
@@ -3565,8 +3148,8 @@ md_section_align (segT seg ATTRIBUTE_UNUSED, valueT size)
 #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)));
+  return ((size + (1 << bfd_section_alignment (seg)) - 1)
+         & -(1 << bfd_section_alignment (seg)));
 #endif /* ! OBJ_ELF */
 }
 
@@ -3597,7 +3180,6 @@ void
 sh_cons_align (int nbytes)
 {
   int nalign;
-  char *p;
 
   if (sh_no_align_cons)
     {
@@ -3623,8 +3205,8 @@ sh_cons_align (int nbytes)
       return;
     }
 
-  p = frag_var (rs_align_test, 1, 1, (relax_substateT) 0,
-               (symbolS *) NULL, (offsetT) nalign, (char *) NULL);
+  frag_var (rs_align_test, 1, 1, (relax_substateT) 0,
+           (symbolS *) NULL, (offsetT) nalign, (char *) NULL);
 
   record_alignment (now_seg, nalign);
 }
@@ -3666,7 +3248,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
@@ -3681,7 +3263,7 @@ sh_handle_align (fragS *frag)
 
 /* See whether the relocation should be resolved locally.  */
 
-static bfd_boolean
+static bool
 sh_local_pcrel (fixS *fix)
 {
   return (! sh_relax
@@ -3726,19 +3308,22 @@ sh_force_relocation (fixS *fix)
          || fix->fx_r_type == BFD_RELOC_SH_ALIGN
          || fix->fx_r_type == BFD_RELOC_SH_CODE
          || fix->fx_r_type == BFD_RELOC_SH_DATA
-#ifdef HAVE_SH64
-         || fix->fx_r_type == BFD_RELOC_SH_SHMEDIA_CODE
-#endif
          || fix->fx_r_type == BFD_RELOC_SH_LABEL);
 }
 
 #ifdef OBJ_ELF
-bfd_boolean
+bool
 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_GOT20
       || fixP->fx_r_type == BFD_RELOC_SH_GOTPC
+      || fixP->fx_r_type == BFD_RELOC_SH_GOTFUNCDESC
+      || fixP->fx_r_type == BFD_RELOC_SH_GOTFUNCDESC20
+      || fixP->fx_r_type == BFD_RELOC_SH_GOTOFFFUNCDESC
+      || fixP->fx_r_type == BFD_RELOC_SH_GOTOFFFUNCDESC20
+      || fixP->fx_r_type == BFD_RELOC_SH_FUNCDESC
       || ((fixP->fx_r_type == BFD_RELOC_32) && dont_adjust_reloc_32)
       || fixP->fx_r_type == BFD_RELOC_RVA)
     return 0;
@@ -3758,28 +3343,51 @@ sh_elf_final_processing (void)
 
   /* Set file-specific flags to indicate if this code needs
      a processor with the sh-dsp / sh2e ISA to execute.  */
-#ifdef HAVE_SH64
-  /* SH5 and above don't know about the valid_arch arch_sh* bits defined
-     in sh-opc.h, so check SH64 mode before checking valid_arch.  */
-  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 */
-    val = sh_find_elf_flags (valid_arch);
+  val = sh_find_elf_flags (valid_arch);
 
   elf_elfheader (stdoutput)->e_flags &= ~EF_SH_MACH_MASK;
   elf_elfheader (stdoutput)->e_flags |= val;
+
+  if (sh_fdpic)
+    elf_elfheader (stdoutput)->e_flags |= EF_SH_FDPIC;
 }
 #endif
 
+#ifdef TE_UCLINUX
+/* Return the target format for uClinux.  */
+
+const char *
+sh_uclinux_target_format (void)
+{
+  if (sh_fdpic)
+    return (!target_big_endian ? "elf32-sh-fdpic" : "elf32-shbig-fdpic");
+  else
+    return (!target_big_endian ? "elf32-shl" : "elf32-sh");
+}
+#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
@@ -3937,6 +3545,23 @@ md_apply_fix (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
@@ -3980,11 +3605,11 @@ md_apply_fix (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:
@@ -4016,8 +3641,7 @@ md_apply_fix (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:
@@ -4038,7 +3662,7 @@ md_apply_fix (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:
@@ -4047,9 +3671,15 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       S_SET_THREAD_LOCAL (fixP->fx_addsy);
       /* Fallthrough */
     case BFD_RELOC_32_GOT_PCREL:
+    case BFD_RELOC_SH_GOT20:
     case BFD_RELOC_SH_GOTPLT32:
+    case BFD_RELOC_SH_GOTFUNCDESC:
+    case BFD_RELOC_SH_GOTFUNCDESC20:
+    case BFD_RELOC_SH_GOTOFFFUNCDESC:
+    case BFD_RELOC_SH_GOTOFFFUNCDESC20:
+    case BFD_RELOC_SH_FUNCDESC:
       * 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:
@@ -4057,17 +3687,13 @@ md_apply_fix (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);
+    case BFD_RELOC_SH_GOTOFF20:
+      apply_full_field_fix (fixP, buf, val, 4);
       break;
 #endif
 
     default:
-#ifdef HAVE_SH64
-      shmedia_md_apply_fix (fixP, valP);
-      return;
-#else
       abort ();
-#endif
     }
 
   if (shift != 0)
@@ -4080,8 +3706,16 @@ md_apply_fix (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 overflow 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;
@@ -4098,12 +3732,7 @@ md_estimate_size_before_relax (fragS *fragP, segT segment_type)
   switch (fragP->fr_subtype)
     {
     default:
-#ifdef HAVE_SH64
-      return shmedia_md_estimate_size_before_relax (fragP, segment_type);
-#else
       abort ();
-#endif
-
 
     case C (UNCOND_JUMP, UNDEF_DISP):
       /* Used to be a branch to somewhere which was unknown.  */
@@ -4134,7 +3763,7 @@ md_estimate_size_before_relax (fragS *fragP, segT segment_type)
        }
       else if (fragP->fr_symbol)
        {
-         /* Its got a segment, but its not ours, so it will always be long.  */
+         /* It's got a segment, but it's not ours, so it will always be long.  */
          fragP->fr_subtype = C (what, UNDEF_WORD_DISP);
        }
       else
@@ -4169,11 +3798,6 @@ md_estimate_size_before_relax (fragS *fragP, segT segment_type)
 void
 md_number_to_chars (char *ptr, valueT use, int nbytes)
 {
-#ifdef HAVE_SH64
-  /* We might need to set the contents type to data.  */
-  sh64_flag_output ();
-#endif
-
   if (! target_big_endian)
     number_to_chars_littleendian (ptr, use, nbytes);
   else
@@ -4214,8 +3838,8 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
   arelent *rel;
   bfd_reloc_code_real_type r_type;
 
-  rel = (arelent *) xmalloc (sizeof (arelent));
-  rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  rel = XNEW (arelent);
+  rel->sym_ptr_ptr = XNEW (asymbol *);
   *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
@@ -4224,7 +3848,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
   if (SWITCH_TABLE (fixp))
     {
       *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
-      rel->addend = 0;
+      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)
@@ -4251,16 +3875,8 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
       rel->addend = 0;
       rel->address = rel->addend = fixp->fx_offset;
     }
-#ifdef HAVE_SH64
-  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);
 
@@ -4271,7 +3887,7 @@ 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)
@@ -4283,7 +3899,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
 
 #ifdef OBJ_ELF
 inline static char *
-sh_end_of_match (char *cont, char *what)
+sh_end_of_match (char *cont, const char *what)
 {
   int len = strlen (what);
 
@@ -4360,6 +3976,14 @@ sh_parse_name (char const *name,
     reloc_type = BFD_RELOC_SH_TLS_LE_32;
   else if ((next_end = sh_end_of_match (next + 1, "DTPOFF")))
     reloc_type = BFD_RELOC_SH_TLS_LDO_32;
+  else if ((next_end = sh_end_of_match (next + 1, "PCREL")))
+    reloc_type = BFD_RELOC_32_PCREL;
+  else if ((next_end = sh_end_of_match (next + 1, "GOTFUNCDESC")))
+    reloc_type = BFD_RELOC_SH_GOTFUNCDESC;
+  else if ((next_end = sh_end_of_match (next + 1, "GOTOFFFUNCDESC")))
+    reloc_type = BFD_RELOC_SH_GOTOFFFUNCDESC;
+  else if ((next_end = sh_end_of_match (next + 1, "FUNCDESC")))
+    reloc_type = BFD_RELOC_SH_FUNCDESC;
   else
     goto no_suffix;
 
@@ -4382,13 +4006,13 @@ sh_cfi_frame_initial_instructions (void)
 }
 
 int
-sh_regname_to_dw2regnum (const char *regname)
+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[] =
+  static struct { const char *name; int dw2regnum; } regnames[] =
     {
       { "pr", 17 }, { "t", 18 }, { "gbr", 19 }, { "mach", 20 },
       { "macl", 21 }, { "fpul", 23 }