2004-02-23 Andrew Stubbs <andrew.stubbs@superh.com>
[deliverable/binutils-gdb.git] / gas / config / tc-sh.c
index 8bb72bd146ab8ad9e526d1ae7ea8040a3ee8a283..3e410e303850c429e770a862961e44051b9aa3ec 100644 (file)
@@ -1,5 +1,5 @@
-/* tc-sh.c -- Assemble code for the Hitachi Super-H
-   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+/* tc-sh.c -- Assemble code for the Renesas / SuperH SH
+   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
@@ -48,43 +48,17 @@ const char comment_chars[] = "!";
 const char line_separator_chars[] = ";";
 const char line_comment_chars[] = "!#";
 
 const char line_separator_chars[] = ";";
 const char line_comment_chars[] = "!#";
 
-static void s_uses PARAMS ((int));
-
-static void sh_count_relocs PARAMS ((bfd *, segT, PTR));
-static void sh_frob_section PARAMS ((bfd *, segT, PTR));
-
-static void s_uacons PARAMS ((int));
-static sh_opcode_info *find_cooked_opcode PARAMS ((char **));
-static unsigned int assemble_ppi PARAMS ((char *, sh_opcode_info *));
-static void little PARAMS ((int));
-static void big PARAMS ((int));
-static int parse_reg PARAMS ((char *, int *, int *));
-static char *parse_exp PARAMS ((char *, sh_operand_info *));
-static char *parse_at PARAMS ((char *, sh_operand_info *));
-static void get_operand PARAMS ((char **, sh_operand_info *));
-static char *get_operands
-  PARAMS ((sh_opcode_info *, char *, sh_operand_info *));
-static sh_opcode_info *get_specific
-  PARAMS ((sh_opcode_info *, sh_operand_info *));
-static void insert PARAMS ((char *, int, int, sh_operand_info *));
-static void build_relax PARAMS ((sh_opcode_info *, sh_operand_info *));
-static char *insert_loop_bounds PARAMS ((char *, sh_operand_info *));
-static unsigned int build_Mytes
-  PARAMS ((sh_opcode_info *, sh_operand_info *));
+static void s_uses (int);
+static void s_uacons (int);
 
 #ifdef OBJ_ELF
 
 #ifdef OBJ_ELF
-static void sh_elf_cons PARAMS ((int));
-
-inline static int sh_PIC_related_p PARAMS ((symbolS *));
-static int sh_check_fixup PARAMS ((expressionS *, bfd_reloc_code_real_type *));
-inline static char *sh_end_of_match PARAMS ((char *, char *));
+static void sh_elf_cons (int);
 
 symbolS *GOT_symbol;           /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
 #endif
 
 static void
 
 symbolS *GOT_symbol;           /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
 #endif
 
 static void
-big (ignore)
-     int ignore ATTRIBUTE_UNUSED;
+big (int ignore ATTRIBUTE_UNUSED)
 {
   if (! target_big_endian)
     as_bad (_("directive .big encountered when option -big required"));
 {
   if (! target_big_endian)
     as_bad (_("directive .big encountered when option -big required"));
@@ -94,8 +68,7 @@ big (ignore)
 }
 
 static void
 }
 
 static void
-little (ignore)
-     int ignore ATTRIBUTE_UNUSED;
+little (int ignore ATTRIBUTE_UNUSED)
 {
   if (target_big_endian)
     as_bad (_("directive .little encountered when option -little required"));
 {
   if (target_big_endian)
     as_bad (_("directive .little encountered when option -little required"));
@@ -135,10 +108,6 @@ const pseudo_typeS md_pseudo_table[] =
   {"2byte", s_uacons, 2},
   {"4byte", s_uacons, 4},
   {"8byte", 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
 #ifdef HAVE_SH64
   {"mode", s_sh64_mode, 0 },
 
 #ifdef HAVE_SH64
   {"mode", s_sh64_mode, 0 },
 
@@ -162,12 +131,12 @@ int sh_relax;             /* set if -relax seen */
 
 int sh_small;
 
 
 int sh_small;
 
-/* Whether -dsp was seen.  */
+/* preset architecture set, if given; zero otherwise.  */
 
 
-static int sh_dsp;
+static int preset_target_arch;
 
 /* The bit mask of architectures that could
 
 /* The bit mask of architectures that could
-   accomodate the insns seen so far.  */
+   accommodate the insns seen so far.  */
 static int valid_arch;
 
 const char EXP_CHARS[] = "eE";
 static int valid_arch;
 
 const char EXP_CHARS[] = "eE";
@@ -182,7 +151,7 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
 #define ENCODE_RELAX(what,length) (((what) << 4) + (length))
 #define GET_WHAT(x) ((x>>4))
 
 #define ENCODE_RELAX(what,length) (((what) << 4) + (length))
 #define GET_WHAT(x) ((x>>4))
 
-/* These are the three types of relaxable instrction.  */
+/* These are the three types of relaxable instruction.  */
 /* These are the types of relaxable instructions; except for END which is
    a marker.  */
 #define COND_JUMP 1
 /* These are the types of relaxable instructions; except for END which is
    a marker.  */
 #define COND_JUMP 1
@@ -513,8 +482,7 @@ static struct hash_control *opcode_hash_control;    /* Opcode mnemonics */
 /* Determinet whether the symbol needs any kind of PIC relocation.  */
 
 inline static int
 /* Determinet whether the symbol needs any kind of PIC relocation.  */
 
 inline static int
-sh_PIC_related_p (sym)
-     symbolS *sym;
+sh_PIC_related_p (symbolS *sym)
 {
   expressionS *exp;
 
 {
   expressionS *exp;
 
@@ -540,9 +508,7 @@ sh_PIC_related_p (sym)
    expression, that may be rearranged.  */
 
 static int
    expression, that may be rearranged.  */
 
 static int
-sh_check_fixup (main_exp, r_type_p)
-     expressionS *main_exp;
-     bfd_reloc_code_real_type *r_type_p;
+sh_check_fixup (expressionS *main_exp, bfd_reloc_code_real_type *r_type_p)
 {
   expressionS *exp = main_exp;
 
 {
   expressionS *exp = main_exp;
 
@@ -768,10 +734,7 @@ sh_check_fixup (main_exp, r_type_p)
 /* Add expression EXP of SIZE bytes to offset OFF of fragment FRAG.  */
 
 void
 /* Add expression EXP of SIZE bytes to offset OFF of fragment FRAG.  */
 
 void
-sh_cons_fix_new (frag, off, size, exp)
-     fragS *frag;
-     int off, size;
-     expressionS *exp;
+sh_cons_fix_new (fragS *frag, int off, int size, expressionS *exp)
 {
   bfd_reloc_code_real_type r_type = BFD_RELOC_UNUSED;
 
 {
   bfd_reloc_code_real_type r_type = BFD_RELOC_UNUSED;
 
@@ -816,16 +779,16 @@ sh_cons_fix_new (frag, off, size, exp)
    suffixes such as @GOT, @GOTOFF and @PLT, that generate
    machine-specific relocation types.  So we must define it here.  */
 /* Clobbers input_line_pointer, checks end-of-line.  */
    suffixes such as @GOT, @GOTOFF and @PLT, that generate
    machine-specific relocation types.  So we must define it here.  */
 /* Clobbers input_line_pointer, checks end-of-line.  */
+/* NBYTES 1=.byte, 2=.word, 4=.long */
 static void
 static void
-sh_elf_cons (nbytes)
-     register int nbytes;      /* 1=.byte, 2=.word, 4=.long */
+sh_elf_cons (register int nbytes)
 {
   expressionS exp;
 
 #ifdef HAVE_SH64
 
   /* Update existing range to include a previous insn, if there was one.  */
 {
   expressionS exp;
 
 #ifdef HAVE_SH64
 
   /* Update existing range to include a previous insn, if there was one.  */
-  sh64_update_contents_mark (true);
+  sh64_update_contents_mark (TRUE);
 
   /* We need to make sure the contents type is set to data.  */
   sh64_flag_output ();
 
   /* We need to make sure the contents type is set to data.  */
   sh64_flag_output ();
@@ -838,6 +801,10 @@ sh_elf_cons (nbytes)
       return;
     }
 
       return;
     }
 
+#ifdef md_cons_align
+  md_cons_align (nbytes);
+#endif
+
   do
     {
       expression (&exp);
   do
     {
       expression (&exp);
@@ -860,13 +827,14 @@ sh_elf_cons (nbytes)
    set up all the tables, etc that the MD part of the assembler needs.  */
 
 void
    set up all the tables, etc that the MD part of the assembler needs.  */
 
 void
-md_begin ()
+md_begin (void)
 {
 {
-  sh_opcode_info *opcode;
+  const sh_opcode_info *opcode;
   char *prev_name = "";
   int target_arch;
 
   char *prev_name = "";
   int target_arch;
 
-  target_arch = arch_sh1_up & ~(sh_dsp ? arch_sh3e_up : arch_sh_dsp_up);
+  target_arch
+    = preset_target_arch ? preset_target_arch : arch_sh1_up & ~arch_sh_dsp_up;
   valid_arch = target_arch;
 
 #ifdef HAVE_SH64
   valid_arch = target_arch;
 
 #ifdef HAVE_SH64
@@ -878,19 +846,13 @@ md_begin ()
   /* Insert unique names into hash table.  */
   for (opcode = sh_table; opcode->name; opcode++)
     {
   /* Insert unique names into hash table.  */
   for (opcode = sh_table; opcode->name; opcode++)
     {
-      if (strcmp (prev_name, opcode->name))
+      if (strcmp (prev_name, opcode->name) != 0)
        {
          if (! (opcode->arch & target_arch))
            continue;
          prev_name = opcode->name;
          hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
        }
        {
          if (! (opcode->arch & target_arch))
            continue;
          prev_name = opcode->name;
          hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
        }
-      else
-       {
-         /* Make all the opcodes with the same name point to the same
-            string.  */
-         opcode->name = prev_name;
-       }
     }
 }
 
     }
 }
 
@@ -905,10 +867,7 @@ static int reg_b;
 /* Try to parse a reg name.  Return the number of chars consumed.  */
 
 static int
 /* Try to parse a reg name.  Return the number of chars consumed.  */
 
 static int
-parse_reg (src, mode, reg)
-     char *src;
-     int *mode;
-     int *reg;
+parse_reg (char *src, int *mode, int *reg)
 {
   char l0 = TOLOWER (src[0]);
   char l1 = l0 ? TOLOWER (src[1]) : 0;
 {
   char l0 = TOLOWER (src[0]);
   char l1 = l0 ? TOLOWER (src[1]) : 0;
@@ -1258,9 +1217,7 @@ parse_reg (src, mode, reg)
 }
 
 static char *
 }
 
 static char *
-parse_exp (s, op)
-     char *s;
-     sh_operand_info *op;
+parse_exp (char *s, sh_operand_info *op)
 {
   char *save;
   char *new;
 {
   char *save;
   char *new;
@@ -1301,9 +1258,7 @@ parse_exp (s, op)
  */
 
 static char *
  */
 
 static char *
-parse_at (src, op)
-     char *src;
-     sh_operand_info *op;
+parse_at (char *src, sh_operand_info *op)
 {
   int len;
   int mode;
 {
   int len;
   int mode;
@@ -1383,10 +1338,33 @@ parse_at (src, op)
                }
              else if (mode == A_PC)
                {
                }
              else if (mode == A_PC)
                {
-                 op->type = A_DISP_PC_ABS;
-                 /* Such operands don't get corrected for PC==.+4, so
-                    make the correction here.  */
-                 op->immediate.X_add_number -= 4;
+                 /* We want @(expr, pc) to uniformly address . + expr,
+                    no matter if expr is a constant, or a more complex
+                    expression, e.g. sym-. or sym1-sym2.
+                    However, we also used to accept @(sym,pc)
+                    as addressing sym, i.e. meaning the same as plain sym.
+                    Some existing code does use the @(sym,pc) syntax, so
+                    we give it the old semantics for now, but warn about
+                    its use, so that users have some time to fix their code.
+
+                    Note that due to this backward compatibility hack,
+                    we'll get unexpected results when @(offset, pc) is used,
+                    and offset is a symbol that is set later to an an address
+                    difference, or an external symbol that is set to an
+                    address difference in another source file, so we want to
+                    eventually remove it.  */
+                 if (op->immediate.X_op == O_symbol)
+                   {
+                     op->type = A_DISP_PC;
+                     as_warn (_("Deprecated syntax."));
+                   }
+                 else
+                   {
+                     op->type = A_DISP_PC_ABS;
+                     /* Such operands don't get corrected for PC==.+4, so
+                        make the correction here.  */
+                     op->immediate.X_add_number -= 4;
+                   }
                }
              else
                {
                }
              else
                {
@@ -1422,13 +1400,13 @@ parse_at (src, op)
              || (l0 == 'i' && (l1 == 'x' || l1 == 's')))
            {
              src += 2;
              || (l0 == 'i' && (l1 == 'x' || l1 == 's')))
            {
              src += 2;
-             op->type = A_PMOD_N;
+             op->type = AX_PMOD_N;
            }
          else if (   (l0 == 'r' && l1 == '9')
                   || (l0 == 'i' && l1 == 'y'))
            {
              src += 2;
            }
          else if (   (l0 == 'r' && l1 == '9')
                   || (l0 == 'i' && l1 == 'y'))
            {
              src += 2;
-             op->type = A_PMODY_N;
+             op->type = AY_PMOD_N;
            }
          else
            op->type = A_INC_N;
            }
          else
            op->type = A_INC_N;
@@ -1440,9 +1418,7 @@ parse_at (src, op)
 }
 
 static void
 }
 
 static void
-get_operand (ptr, op)
-     char **ptr;
-     sh_operand_info *op;
+get_operand (char **ptr, sh_operand_info *op)
 {
   char *src = *ptr;
   int mode = -1;
 {
   char *src = *ptr;
   int mode = -1;
@@ -1478,10 +1454,7 @@ get_operand (ptr, op)
 }
 
 static char *
 }
 
 static char *
-get_operands (info, args, operand)
-     sh_opcode_info *info;
-     char *args;
-     sh_operand_info *operand;
+get_operands (sh_opcode_info *info, char *args, sh_operand_info *operand)
 {
   char *ptr = args;
   if (info->arg[0])
 {
   char *ptr = args;
   if (info->arg[0])
@@ -1539,9 +1512,7 @@ get_operands (info, args, operand)
    provided.  */
 
 static sh_opcode_info *
    provided.  */
 
 static sh_opcode_info *
-get_specific (opcode, operands)
-     sh_opcode_info *opcode;
-     sh_operand_info *operands;
+get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
 {
   sh_opcode_info *this_try = opcode;
   char *name = opcode->name;
 {
   sh_opcode_info *this_try = opcode;
   char *name = opcode->name;
@@ -1550,7 +1521,7 @@ get_specific (opcode, operands)
   while (opcode->name)
     {
       this_try = opcode++;
   while (opcode->name)
     {
       this_try = opcode++;
-      if (this_try->name != name)
+      if ((this_try->name != name) && (strcmp (this_try->name, name) != 0))
        {
          /* We've looked so far down the table that we've run out of
             opcodes with the same name.  */
        {
          /* We've looked so far down the table that we've run out of
             opcodes with the same name.  */
@@ -1566,27 +1537,6 @@ get_specific (opcode, operands)
          sh_operand_info *user = operands + n;
          sh_arg_type arg = this_try->arg[n];
 
          sh_operand_info *user = operands + n;
          sh_arg_type arg = this_try->arg[n];
 
-         /* If this is a parallel insn check to see if both
-            parts have the same destination register.  */
-         if ((n == 2) && (this_try->nibbles[0] == PPI))
-           {
-             static boolean bIsPPI = false;
-             static int nLastDestReg;
-
-             if (!bIsPPI)
-               {
-                 bIsPPI = true;
-                 nLastDestReg = user->reg;
-               }
-             else /* Second insn.  */
-               {
-                 if (nLastDestReg == user->reg)
-                   as_warn (_("destination register is same for parallel insns"));
-
-                 bIsPPI = false;
-               }
-           }
-
          switch (arg)
            {
            case A_DISP_PC:
          switch (arg)
            {
            case A_DISP_PC:
@@ -1629,8 +1579,6 @@ get_specific (opcode, operands)
            case V_REG_N:
            case FPUL_N:
            case FPSCR_N:
            case V_REG_N:
            case FPUL_N:
            case FPSCR_N:
-           case A_PMOD_N:
-           case A_PMODY_N:
            case DSP_REG_N:
              /* Opcode needs rn */
              if (user->type != arg)
            case DSP_REG_N:
              /* Opcode needs rn */
              if (user->type != arg)
@@ -1676,6 +1624,237 @@ get_specific (opcode, operands)
              reg_m = user->reg;
              break;
 
              reg_m = user->reg;
              break;
 
+           case AS_DEC_N:
+             if (user->type != A_DEC_N)
+               goto fail;
+             if (user->reg < 2 || user->reg > 5)
+               goto fail;
+             reg_n = user->reg;
+             break;
+             
+           case AS_INC_N:
+             if (user->type != A_INC_N)
+               goto fail;
+             if (user->reg < 2 || user->reg > 5)
+               goto fail;
+             reg_n = user->reg;
+             break;
+             
+           case AS_IND_N:
+             if (user->type != A_IND_N)
+               goto fail;
+             if (user->reg < 2 || user->reg > 5)
+               goto fail;
+             reg_n = user->reg;
+             break;
+             
+           case AS_PMOD_N:
+             if (user->type != AX_PMOD_N)
+               goto fail;
+             if (user->reg < 2 || user->reg > 5)
+               goto fail;
+             reg_n = user->reg;
+             break;
+             
+           case AX_INC_N:
+             if (user->type != A_INC_N)
+               goto fail;
+             if (user->reg < 4 || user->reg > 5)
+               goto fail;
+             reg_n = user->reg;
+             break;
+             
+           case AX_IND_N:
+             if (user->type != A_IND_N)
+               goto fail;
+             if (user->reg < 4 || user->reg > 5)
+               goto fail;
+             reg_n = user->reg;
+             break;
+             
+           case AX_PMOD_N:
+             if (user->type != AX_PMOD_N)
+               goto fail;
+             if (user->reg < 4 || user->reg > 5)
+               goto fail;
+             reg_n = user->reg;
+             break;
+             
+           case AXY_INC_N:
+             if (user->type != A_INC_N)
+               goto fail;
+             if ((user->reg < 4 || user->reg > 5)
+                 && (user->reg < 0 || user->reg > 1))
+               goto fail;
+             reg_n = user->reg;
+             break;
+             
+           case AXY_IND_N:
+             if (user->type != A_IND_N)
+               goto fail;
+             if ((user->reg < 4 || user->reg > 5)
+                 && (user->reg < 0 || user->reg > 1))
+               goto fail;
+             reg_n = user->reg;
+             break;
+             
+           case AXY_PMOD_N:
+             if (user->type != AX_PMOD_N)
+               goto fail;
+             if ((user->reg < 4 || user->reg > 5)
+                 && (user->reg < 0 || user->reg > 1))
+               goto fail;
+             reg_n = user->reg;
+             break;
+             
+           case AY_INC_N:
+             if (user->type != A_INC_N)
+               goto fail;
+             if (user->reg < 6 || user->reg > 7)
+               goto fail;
+             reg_n = user->reg;
+             break;
+             
+           case AY_IND_N:
+             if (user->type != A_IND_N)
+               goto fail;
+             if (user->reg < 6 || user->reg > 7)
+               goto fail;
+             reg_n = user->reg;
+             break;
+             
+           case AY_PMOD_N:
+             if (user->type != AY_PMOD_N)
+               goto fail;
+             if (user->reg < 6 || user->reg > 7)
+               goto fail;
+             reg_n = user->reg;
+             break;
+
+           case AYX_INC_N:
+             if (user->type != A_INC_N)
+               goto fail;
+             if ((user->reg < 6 || user->reg > 7)
+                 && (user->reg < 2 || user->reg > 3))
+               goto fail;
+             reg_n = user->reg;
+             break;
+             
+           case AYX_IND_N:
+             if (user->type != A_IND_N)
+               goto fail;
+             if ((user->reg < 6 || user->reg > 7)
+                 && (user->reg < 2 || user->reg > 3))
+               goto fail;
+             reg_n = user->reg;
+             break;
+             
+           case AYX_PMOD_N:
+             if (user->type != AY_PMOD_N)
+               goto fail;
+             if ((user->reg < 6 || user->reg > 7)
+                 && (user->reg < 2 || user->reg > 3))
+               goto fail;
+             reg_n = user->reg;
+             break;
+
+           case DSP_REG_A_M:
+             if (user->type != DSP_REG_N)
+               goto fail;
+             if (user->reg != A_A0_NUM
+                 && user->reg != A_A1_NUM)
+               goto fail;
+             reg_m = user->reg;
+             break;
+
+           case DSP_REG_AX:
+             if (user->type != DSP_REG_N)
+               goto fail;
+             switch (user->reg)
+               {
+               case A_A0_NUM:
+                 reg_x = 0;
+                 break;
+               case A_A1_NUM:
+                 reg_x = 2;
+                 break;
+               case A_X0_NUM:
+                 reg_x = 1;
+                 break;
+               case A_X1_NUM:
+                 reg_x = 3;
+                 break;
+               default:
+                 goto fail;
+               }
+             break;
+
+           case DSP_REG_XY:
+             if (user->type != DSP_REG_N)
+               goto fail;
+             switch (user->reg)
+               {
+               case A_X0_NUM:
+                 reg_x = 0;
+                 break;
+               case A_X1_NUM:
+                 reg_x = 2;
+                 break;
+               case A_Y0_NUM:
+                 reg_x = 1;
+                 break;
+               case A_Y1_NUM:
+                 reg_x = 3;
+                 break;
+               default:
+                 goto fail;
+               }
+             break;
+
+           case DSP_REG_AY:
+             if (user->type != DSP_REG_N)
+               goto fail;
+             switch (user->reg)
+               {
+               case A_A0_NUM:
+                 reg_y = 0;
+                 break;
+               case A_A1_NUM:
+                 reg_y = 1;
+                 break;
+               case A_Y0_NUM:
+                 reg_y = 2;
+                 break;
+               case A_Y1_NUM:
+                 reg_y = 3;
+                 break;
+               default:
+                 goto fail;
+               }
+             break;
+
+           case DSP_REG_YX:
+             if (user->type != DSP_REG_N)
+               goto fail;
+             switch (user->reg)
+               {
+               case A_Y0_NUM:
+                 reg_y = 0;
+                 break;
+               case A_Y1_NUM:
+                 reg_y = 1;
+                 break;
+               case A_X0_NUM:
+                 reg_y = 2;
+                 break;
+               case A_X1_NUM:
+                 reg_y = 3;
+                 break;
+               default:
+                 goto fail;
+               }
+             break;
+
            case DSP_REG_X:
              if (user->type != DSP_REG_N)
                goto fail;
            case DSP_REG_X:
              if (user->type != DSP_REG_N)
                goto fail;
@@ -1846,11 +2025,7 @@ get_specific (opcode, operands)
 }
 
 static void
 }
 
 static void
-insert (where, how, pcrel, op)
-     char *where;
-     int how;
-     int pcrel;
-     sh_operand_info *op;
+insert (char *where, int how, int pcrel, sh_operand_info *op)
 {
   fix_new_exp (frag_now,
               where - frag_now->fr_literal,
 {
   fix_new_exp (frag_now,
               where - frag_now->fr_literal,
@@ -1861,9 +2036,7 @@ insert (where, how, pcrel, op)
 }
 
 static void
 }
 
 static void
-build_relax (opcode, op)
-     sh_opcode_info *opcode;
-     sh_operand_info *op;
+build_relax (sh_opcode_info *opcode, sh_operand_info *op)
 {
   int high_byte = target_big_endian ? 0 : 1;
   char *p;
 {
   int high_byte = target_big_endian ? 0 : 1;
   char *p;
@@ -1897,9 +2070,7 @@ build_relax (opcode, op)
 /* Insert ldrs & ldre with fancy relocations that relaxation can recognize.  */
 
 static char *
 /* Insert ldrs & ldre with fancy relocations that relaxation can recognize.  */
 
 static char *
-insert_loop_bounds (output, operand)
-     char *output;
-     sh_operand_info *operand;
+insert_loop_bounds (char *output, sh_operand_info *operand)
 {
   char *name;
   symbolS *end_sym;
 {
   char *name;
   symbolS *end_sym;
@@ -1947,9 +2118,7 @@ insert_loop_bounds (output, operand)
 /* Now we know what sort of opcodes it is, let's build the bytes.  */
 
 static unsigned int
 /* Now we know what sort of opcodes it is, let's build the bytes.  */
 
 static unsigned int
-build_Mytes (opcode, operand)
-     sh_opcode_info *opcode;
-     sh_operand_info *operand;
+build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
 {
   int index;
   char nbuf[4];
 {
   int index;
   char nbuf[4];
@@ -1973,6 +2142,7 @@ build_Mytes (opcode, operand)
          switch (i)
            {
            case REG_N:
          switch (i)
            {
            case REG_N:
+           case REG_N_D:
              nbuf[index] = reg_n;
              break;
            case REG_M:
              nbuf[index] = reg_n;
              break;
            case REG_M:
@@ -1989,6 +2159,9 @@ build_Mytes (opcode, operand)
            case REG_B:
              nbuf[index] = reg_b | 0x08;
              break;
            case REG_B:
              nbuf[index] = reg_b | 0x08;
              break;
+           case REG_N_B01:
+             nbuf[index] = reg_n | 0x01;
+             break;
            case IMM0_4BY4:
              insert (output + low_byte, BFD_RELOC_SH_IMM4BY4, 0, operand);
              break;
            case IMM0_4BY4:
              insert (output + low_byte, BFD_RELOC_SH_IMM4BY4, 0, operand);
              break;
@@ -2060,8 +2233,7 @@ build_Mytes (opcode, operand)
    *STR_P to the first character after the last one read.  */
 
 static sh_opcode_info *
    *STR_P to the first character after the last one read.  */
 
 static sh_opcode_info *
-find_cooked_opcode (str_p)
-     char **str_p;
+find_cooked_opcode (char **str_p)
 {
   char *str = *str_p;
   unsigned char *op_start;
 {
   char *str = *str_p;
   unsigned char *op_start;
@@ -2108,9 +2280,7 @@ find_cooked_opcode (str_p)
 #define DDT_BASE 0xf000 /* Base value for double data transfer insns */
 
 static unsigned int
 #define DDT_BASE 0xf000 /* Base value for double data transfer insns */
 
 static unsigned int
-assemble_ppi (op_end, opcode)
-     char *op_end;
-     sh_opcode_info *opcode;
+assemble_ppi (char *op_end, sh_opcode_info *opcode)
 {
   int movx = 0;
   int movy = 0;
 {
   int movx = 0;
   int movy = 0;
@@ -2120,17 +2290,19 @@ assemble_ppi (op_end, opcode)
   int move_code;
   unsigned int size;
 
   int move_code;
   unsigned int size;
 
-  /* Some insn ignore one or more register fields, e.g. psts machl,a0.
-     Make sure we encode a defined insn pattern.  */
-  reg_x = 0;
-  reg_y = 0;
-
   for (;;)
     {
       sh_operand_info operand[3];
 
   for (;;)
     {
       sh_operand_info operand[3];
 
+      /* Some insn ignore one or more register fields, e.g. psts machl,a0.
+        Make sure we encode a defined insn pattern.  */
+      reg_x = 0;
+      reg_y = 0;
+      reg_n = 0;
+
       if (opcode->arg[0] != A_END)
        op_end = get_operands (opcode, op_end, operand);
       if (opcode->arg[0] != A_END)
        op_end = get_operands (opcode, op_end, operand);
+    try_another_opcode:
       opcode = get_specific (opcode, operand);
       if (opcode == 0)
        {
       opcode = get_specific (opcode, operand);
       if (opcode == 0)
        {
@@ -2161,9 +2333,43 @@ assemble_ppi (op_end, opcode)
          movy = DDT_BASE;
          break;
 
          movy = DDT_BASE;
          break;
 
+       case MOVX_NOPY:
+         if (movx)
+           as_bad (_("multiple movx specifications"));
+         if ((reg_n < 4 || reg_n > 5)
+             && (reg_n < 0 || reg_n > 1))
+           as_bad (_("invalid movx address register"));
+         if (movy && movy != DDT_BASE)
+           as_bad (_("insn cannot be combined with non-nopy"));
+         movx = ((((reg_n & 1) != 0) << 9)
+                 + (((reg_n & 4) == 0) << 8)
+                 + (reg_x << 6)
+                 + (opcode->nibbles[2] << 4)
+                 + opcode->nibbles[3]
+                 + DDT_BASE);
+         break;
+
+       case MOVY_NOPX:
+         if (movy)
+           as_bad (_("multiple movy specifications"));
+         if ((reg_n < 6 || reg_n > 7)
+             && (reg_n < 2 || reg_n > 3))
+           as_bad (_("invalid movy address register"));
+         if (movx && movx != DDT_BASE)
+           as_bad (_("insn cannot be combined with non-nopx"));
+         movy = ((((reg_n & 1) != 0) << 8)
+                 + (((reg_n & 4) == 0) << 9)
+                 + (reg_y << 6)
+                 + (opcode->nibbles[2] << 4)
+                 + opcode->nibbles[3]
+                 + DDT_BASE);
+         break;
+
        case MOVX:
          if (movx)
            as_bad (_("multiple movx specifications"));
        case MOVX:
          if (movx)
            as_bad (_("multiple movx specifications"));
+         if (movy & 0x2ac)
+           as_bad (_("previous movy requires nopx"));
          if (reg_n < 4 || reg_n > 5)
            as_bad (_("invalid movx address register"));
          if (opcode->nibbles[2] & 8)
          if (reg_n < 4 || reg_n > 5)
            as_bad (_("invalid movx address register"));
          if (opcode->nibbles[2] & 8)
@@ -2185,6 +2391,8 @@ assemble_ppi (op_end, opcode)
        case MOVY:
          if (movy)
            as_bad (_("multiple movy specifications"));
        case MOVY:
          if (movy)
            as_bad (_("multiple movy specifications"));
+         if (movx & 0x153)
+           as_bad (_("previous movx requires nopy"));
          if (opcode->nibbles[2] & 8)
            {
              /* Bit 3 in nibbles[2] is intended for bit 4 of the opcode,
          if (opcode->nibbles[2] & 8)
            {
              /* Bit 3 in nibbles[2] is intended for bit 4 of the opcode,
@@ -2213,11 +2421,31 @@ assemble_ppi (op_end, opcode)
                     | (operand[0].immediate.X_add_number & 127) << 4
                     | reg_n);
          break;
                     | (operand[0].immediate.X_add_number & 127) << 4
                     | reg_n);
          break;
+       case PPI3NC:
+         if (cond)
+           {
+             opcode++;
+             goto try_another_opcode;
+           }
+         /* Fall through.  */
        case PPI3:
          if (field_b)
            as_bad (_("multiple parallel processing specifications"));
          field_b = ((opcode->nibbles[2] << 12) + (opcode->nibbles[3] << 8)
                     + (reg_x << 6) + (reg_y << 4) + reg_n);
        case PPI3:
          if (field_b)
            as_bad (_("multiple parallel processing specifications"));
          field_b = ((opcode->nibbles[2] << 12) + (opcode->nibbles[3] << 8)
                     + (reg_x << 6) + (reg_y << 4) + reg_n);
+         switch (opcode->nibbles[4])
+           {
+           case HEX_0:
+           case HEX_XX00:
+           case HEX_00YY:
+             break;
+           case HEX_1:
+           case HEX_4:
+             field_b += opcode->nibbles[4] << 4;
+             break;
+           default:
+             abort ();
+           }
          break;
        case PDC:
          if (cond)
          break;
        case PDC:
          if (cond)
@@ -2232,13 +2460,34 @@ assemble_ppi (op_end, opcode)
          field_b = ((opcode->nibbles[2] << 12) + (opcode->nibbles[3] << 8)
                     + cond + (reg_x << 6) + (reg_y << 4) + reg_n);
          cond = 0;
          field_b = ((opcode->nibbles[2] << 12) + (opcode->nibbles[3] << 8)
                     + cond + (reg_x << 6) + (reg_y << 4) + reg_n);
          cond = 0;
+         switch (opcode->nibbles[4])
+           {
+           case HEX_0:
+           case HEX_XX00:
+           case HEX_00YY:
+             break;
+           case HEX_1:
+           case HEX_4:
+             field_b += opcode->nibbles[4] << 4;
+             break;
+           default:
+             abort ();
+           }
          break;
        case PMUL:
          if (field_b)
            {
          break;
        case PMUL:
          if (field_b)
            {
-             if ((field_b & 0xef00) != 0xa100)
+             if ((field_b & 0xef00) == 0xa100)
+               field_b -= 0x8100;
+             /* pclr Dz pmuls Se,Sf,Dg */
+             else if ((field_b & 0xff00) == 0x8d00
+                      && (valid_arch & arch_sh4al_dsp_up))
+               {
+                 valid_arch &= arch_sh4al_dsp_up;
+                 field_b -= 0x8cf0;
+               }
+             else
                as_bad (_("insn cannot be combined with pmuls"));
                as_bad (_("insn cannot be combined with pmuls"));
-             field_b -= 0x8100;
              switch (field_b & 0xf)
                {
                case A_X0_NUM:
              switch (field_b & 0xf)
                {
                case A_X0_NUM:
@@ -2254,8 +2503,17 @@ assemble_ppi (op_end, opcode)
                  field_b += 3 - A_A1_NUM;
                  break;
                default:
                  field_b += 3 - A_A1_NUM;
                  break;
                default:
-                 as_bad (_("bad padd / psub pmuls output operand"));
+                 as_bad (_("bad combined pmuls output operand"));
                }
                }
+               /* Generate warning if the destination register for padd / psub
+                  and pmuls is the same ( only for A0 or A1 ).
+                  If the last nibble is 1010 then A0 is used in both
+                  padd / psub and pmuls. If it is 1111 then A1 is used
+                  as destination register in both padd / psub and pmuls.  */
+
+               if ((((field_b | reg_efg) & 0x000F) == 0x000A)
+                   || (((field_b | reg_efg) & 0x000F) == 0x000F))
+                 as_warn (_("destination register is same for parallel insns"));
            }
          field_b += 0x4000 + reg_efg;
          break;
            }
          field_b += 0x4000 + reg_efg;
          break;
@@ -2323,8 +2581,7 @@ assemble_ppi (op_end, opcode)
    the frags/bytes it assembles to.  */
 
 void
    the frags/bytes it assembles to.  */
 
 void
-md_assemble (str)
-     char *str;
+md_assemble (char *str)
 {
   unsigned char *op_end;
   sh_operand_info operand[3];
 {
   unsigned char *op_end;
   sh_operand_info operand[3];
@@ -2341,13 +2598,13 @@ md_assemble (str)
     {
       /* If we've seen pseudo-directives, make sure any emitted data or
         frags are marked as data.  */
     {
       /* If we've seen pseudo-directives, make sure any emitted data or
         frags are marked as data.  */
-      if (seen_insn == false)
+      if (!seen_insn)
        {
        {
-         sh64_update_contents_mark (true);
+         sh64_update_contents_mark (TRUE);
          sh64_set_contents_type (CRT_SH5_ISA16);
        }
 
          sh64_set_contents_type (CRT_SH5_ISA16);
        }
 
-      seen_insn = true;
+      seen_insn = TRUE;
     }
 #endif /* HAVE_SH64 */
 
     }
 #endif /* HAVE_SH64 */
 
@@ -2379,6 +2636,12 @@ md_assemble (str)
       if (opcode->arg[0] == A_BDISP12
          || opcode->arg[0] == A_BDISP8)
        {
       if (opcode->arg[0] == A_BDISP12
          || opcode->arg[0] == A_BDISP8)
        {
+         /* Since we skip get_specific here, we have to check & update
+            valid_arch now.  */
+         if (valid_arch & opcode->arch)
+           valid_arch &= opcode->arch;
+         else
+           as_bad (_("Delayed branches not available on SH1"));
          parse_exp (op_end + 1, &operand[0]);
          build_relax (opcode, &operand[0]);
        }
          parse_exp (op_end + 1, &operand[0]);
          build_relax (opcode, &operand[0]);
        }
@@ -2426,7 +2689,7 @@ md_assemble (str)
    emits a BFD_RELOC_SH_LABEL reloc if necessary.  */
 
 void
    emits a BFD_RELOC_SH_LABEL reloc if necessary.  */
 
 void
-sh_frob_label ()
+sh_frob_label (void)
 {
   static fragS *last_label_frag;
   static int last_label_offset;
 {
   static fragS *last_label_frag;
   static int last_label_offset;
@@ -2451,7 +2714,7 @@ sh_frob_label ()
    data.  It emits a BFD_RELOC_SH_DATA reloc if necessary.  */
 
 void
    data.  It emits a BFD_RELOC_SH_DATA reloc if necessary.  */
 
 void
-sh_flush_pending_output ()
+sh_flush_pending_output (void)
 {
   if (sh_relax
       && seg_info (now_seg)->tc_segment_info_data.in_code)
 {
   if (sh_relax
       && seg_info (now_seg)->tc_segment_info_data.in_code)
@@ -2463,8 +2726,7 @@ sh_flush_pending_output ()
 }
 
 symbolS *
 }
 
 symbolS *
-md_undefined_symbol (name)
-     char *name ATTRIBUTE_UNUSED;
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
 {
   return 0;
 }
 {
   return 0;
 }
@@ -2473,15 +2735,13 @@ md_undefined_symbol (name)
 #ifndef BFD_ASSEMBLER
 
 void
 #ifndef BFD_ASSEMBLER
 
 void
-tc_crawl_symbol_chain (headers)
-     object_headers *headers;
+tc_crawl_symbol_chain (object_headers *headers ATTRIBUTE_UNUSED)
 {
   printf (_("call to tc_crawl_symbol_chain \n"));
 }
 
 void
 {
   printf (_("call to tc_crawl_symbol_chain \n"));
 }
 
 void
-tc_headers_hook (headers)
-     object_headers *headers;
+tc_headers_hook (object_headers *headers ATTRIBUTE_UNUSED)
 {
   printf (_("call to tc_headers_hook \n"));
 }
 {
   printf (_("call to tc_headers_hook \n"));
 }
@@ -2499,10 +2759,7 @@ tc_headers_hook (headers)
    returned, or NULL on OK.  */
 
 char *
    returned, or NULL on OK.  */
 
 char *
-md_atof (type, litP, sizeP)
-     int type;
-     char *litP;
-     int *sizeP;
+md_atof (int type, char *litP, int *sizeP)
 {
   int prec;
   LITTLENUM_TYPE words[4];
 {
   int prec;
   LITTLENUM_TYPE words[4];
@@ -2556,8 +2813,7 @@ md_atof (type, litP, sizeP)
    special reloc for the linker.  */
 
 static void
    special reloc for the linker.  */
 
 static void
-s_uses (ignore)
-     int ignore ATTRIBUTE_UNUSED;
+s_uses (int ignore ATTRIBUTE_UNUSED)
 {
   expressionS ex;
 
 {
   expressionS ex;
 
@@ -2578,7 +2834,7 @@ s_uses (ignore)
   demand_empty_rest_of_line ();
 }
 \f
   demand_empty_rest_of_line ();
 }
 \f
-CONST char *md_shortopts = "";
+const char *md_shortopts = "";
 struct option md_longopts[] =
 {
 #define OPTION_RELAX  (OPTION_MD_BASE)
 struct option md_longopts[] =
 {
 #define OPTION_RELAX  (OPTION_MD_BASE)
@@ -2586,20 +2842,20 @@ struct option md_longopts[] =
 #define OPTION_LITTLE (OPTION_BIG + 1)
 #define OPTION_SMALL (OPTION_LITTLE + 1)
 #define OPTION_DSP (OPTION_SMALL + 1)
 #define OPTION_LITTLE (OPTION_BIG + 1)
 #define OPTION_SMALL (OPTION_LITTLE + 1)
 #define OPTION_DSP (OPTION_SMALL + 1)
+#define OPTION_ISA                    (OPTION_DSP + 1)
 
   {"relax", no_argument, NULL, OPTION_RELAX},
   {"big", no_argument, NULL, OPTION_BIG},
   {"little", no_argument, NULL, OPTION_LITTLE},
   {"small", no_argument, NULL, OPTION_SMALL},
   {"dsp", no_argument, NULL, OPTION_DSP},
 
   {"relax", no_argument, NULL, OPTION_RELAX},
   {"big", no_argument, NULL, OPTION_BIG},
   {"little", no_argument, NULL, OPTION_LITTLE},
   {"small", no_argument, NULL, OPTION_SMALL},
   {"dsp", no_argument, NULL, OPTION_DSP},
+  {"isa",                    required_argument, NULL, OPTION_ISA},
 #ifdef HAVE_SH64
 #ifdef HAVE_SH64
-#define OPTION_ISA                    (OPTION_DSP + 1)
 #define OPTION_ABI                    (OPTION_ISA + 1)
 #define OPTION_NO_MIX                 (OPTION_ABI + 1)
 #define OPTION_SHCOMPACT_CONST_CRANGE (OPTION_NO_MIX + 1)
 #define OPTION_NO_EXPAND              (OPTION_SHCOMPACT_CONST_CRANGE + 1)
 #define OPTION_PT32                   (OPTION_NO_EXPAND + 1)
 #define OPTION_ABI                    (OPTION_ISA + 1)
 #define OPTION_NO_MIX                 (OPTION_ABI + 1)
 #define OPTION_SHCOMPACT_CONST_CRANGE (OPTION_NO_MIX + 1)
 #define OPTION_NO_EXPAND              (OPTION_SHCOMPACT_CONST_CRANGE + 1)
 #define OPTION_PT32                   (OPTION_NO_EXPAND + 1)
-  {"isa",                    required_argument, NULL, OPTION_ISA},
   {"abi",                    required_argument, NULL, OPTION_ABI},
   {"no-mix",                 no_argument, NULL, OPTION_NO_MIX},
   {"shcompact-const-crange", no_argument, NULL, OPTION_SHCOMPACT_CONST_CRANGE},
   {"abi",                    required_argument, NULL, OPTION_ABI},
   {"no-mix",                 no_argument, NULL, OPTION_NO_MIX},
   {"shcompact-const-crange", no_argument, NULL, OPTION_SHCOMPACT_CONST_CRANGE},
@@ -2612,9 +2868,7 @@ struct option md_longopts[] =
 size_t md_longopts_size = sizeof (md_longopts);
 
 int
 size_t md_longopts_size = sizeof (md_longopts);
 
 int
-md_parse_option (c, arg)
-     int c;
-     char *arg ATTRIBUTE_UNUSED;
+md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
 {
   switch (c)
     {
 {
   switch (c)
     {
@@ -2635,12 +2889,22 @@ md_parse_option (c, arg)
       break;
 
     case OPTION_DSP:
       break;
 
     case OPTION_DSP:
-      sh_dsp = 1;
+      preset_target_arch = arch_sh1_up & ~arch_sh2e_up;
       break;
 
       break;
 
-#ifdef HAVE_SH64
     case OPTION_ISA:
     case OPTION_ISA:
-      if (strcasecmp (arg, "shmedia") == 0)
+      if (strcasecmp (arg, "sh4") == 0)
+       preset_target_arch = arch_sh4;
+      else if (strcasecmp (arg, "sh4a") == 0)
+       preset_target_arch = arch_sh4a;
+      else if (strcasecmp (arg, "dsp") == 0)
+       preset_target_arch = arch_sh1_up & ~arch_sh2e_up;
+      else if (strcasecmp (arg, "fp") == 0)
+       preset_target_arch = arch_sh2e_up;
+      else if (strcasecmp (arg, "any") == 0)
+       preset_target_arch = arch_sh1_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"));
        {
          if (sh64_isa_mode == sh64_isa_shcompact)
            as_bad (_("Invalid combination: --isa=SHcompact with --isa=SHmedia"));
@@ -2654,10 +2918,12 @@ md_parse_option (c, arg)
            as_bad (_("Invalid combination: --abi=64 with --isa=SHcompact"));
          sh64_isa_mode = sh64_isa_shcompact;
        }
            as_bad (_("Invalid combination: --abi=64 with --isa=SHcompact"));
          sh64_isa_mode = sh64_isa_shcompact;
        }
+#endif /* HAVE_SH64 */
       else
        as_bad ("Invalid argument to --isa option: %s", arg);
       break;
 
       else
        as_bad ("Invalid argument to --isa option: %s", arg);
       break;
 
+#ifdef HAVE_SH64
     case OPTION_ABI:
       if (strcmp (arg, "32") == 0)
        {
     case OPTION_ABI:
       if (strcmp (arg, "32") == 0)
        {
@@ -2678,19 +2944,19 @@ md_parse_option (c, arg)
       break;
 
     case OPTION_NO_MIX:
       break;
 
     case OPTION_NO_MIX:
-      sh64_mix = false;
+      sh64_mix = FALSE;
       break;
 
     case OPTION_SHCOMPACT_CONST_CRANGE:
       break;
 
     case OPTION_SHCOMPACT_CONST_CRANGE:
-      sh64_shcompact_const_crange = true;
+      sh64_shcompact_const_crange = TRUE;
       break;
 
     case OPTION_NO_EXPAND:
       break;
 
     case OPTION_NO_EXPAND:
-      sh64_expand = false;
+      sh64_expand = FALSE;
       break;
 
     case OPTION_PT32:
       break;
 
     case OPTION_PT32:
-      sh64_pt32 = true;
+      sh64_pt32 = TRUE;
       break;
 #endif /* HAVE_SH64 */
 
       break;
 #endif /* HAVE_SH64 */
 
@@ -2702,8 +2968,7 @@ md_parse_option (c, arg)
 }
 
 void
 }
 
 void
-md_show_usage (stream)
-     FILE *stream;
+md_show_usage (FILE *stream)
 {
   fprintf (stream, _("\
 SH options:\n\
 {
   fprintf (stream, _("\
 SH options:\n\
@@ -2711,13 +2976,18 @@ SH options:\n\
 -big                   generate big endian code\n\
 -relax                 alter jump instructions for long displacements\n\
 -small                 align sections to 4 byte boundaries, not 16\n\
 -big                   generate big endian code\n\
 -relax                 alter jump instructions for long displacements\n\
 -small                 align sections to 4 byte boundaries, not 16\n\
--dsp                   enable sh-dsp insns, and disable sh3e / sh4 insns.\n"));
+-dsp                   enable sh-dsp insns, and disable floating-point ISAs.\n"));
 #ifdef HAVE_SH64
   fprintf (stream, _("\
 #ifdef HAVE_SH64
   fprintf (stream, _("\
--isa=[shmedia          set default instruction set for SH64\n\
-      | SHmedia\n\
-      | shcompact\n\
-      | SHcompact]\n\
+-isa=[sh4\n\
+    | sh4a\n\
+    | dsp              same as '-dsp'\n\
+    | fp\n\
+    | shmedia          set as the default instruction set for SH64\n\
+    | SHmedia\n\
+    | shcompact\n\
+    | SHcompact\n"));
+  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\
 -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\
@@ -2726,7 +2996,14 @@ SH options:\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\
                        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"));
+                       to 32 bits only\n"));
+#else
+  fprintf (stream, _("\
+-isa=[sh4\n\
+    | sh4a\n\
+    | dsp              same as '-dsp'\n\
+    | fp\n\
+    | any]\n"));
 #endif /* HAVE_SH64 */
 }
 \f
 #endif /* HAVE_SH64 */
 }
 \f
@@ -2746,10 +3023,7 @@ struct sh_count_relocs
    bfd_map_over_sections.  */
 
 static void
    bfd_map_over_sections.  */
 
 static void
-sh_count_relocs (abfd, sec, data)
-     bfd *abfd ATTRIBUTE_UNUSED;
-     segT sec;
-     PTR data;
+sh_count_relocs (bfd *abfd ATTRIBUTE_UNUSED, segT sec, void *data)
 {
   struct sh_count_relocs *info = (struct sh_count_relocs *) data;
   segment_info_type *seginfo;
 {
   struct sh_count_relocs *info = (struct sh_count_relocs *) data;
   segment_info_type *seginfo;
@@ -2775,10 +3049,8 @@ sh_count_relocs (abfd, sec, data)
    BFD_ASSEMBLER, this is called via bfd_map_over_sections.  */
 
 static void
    BFD_ASSEMBLER, this is called via bfd_map_over_sections.  */
 
 static void
-sh_frob_section (abfd, sec, ignore)
-     bfd *abfd ATTRIBUTE_UNUSED;
-     segT sec;
-     PTR ignore ATTRIBUTE_UNUSED;
+sh_frob_section (bfd *abfd ATTRIBUTE_UNUSED, segT sec,
+                void *ignore ATTRIBUTE_UNUSED)
 {
   segment_info_type *seginfo;
   fixS *fix;
 {
   segment_info_type *seginfo;
   fixS *fix;
@@ -2861,13 +3133,13 @@ sh_frob_section (abfd, sec, ignore)
       info.sym = sym;
       info.count = 0;
 #ifdef BFD_ASSEMBLER
       info.sym = sym;
       info.count = 0;
 #ifdef BFD_ASSEMBLER
-      bfd_map_over_sections (stdoutput, sh_count_relocs, (PTR) &info);
+      bfd_map_over_sections (stdoutput, sh_count_relocs, &info);
 #else
       {
        int iscan;
 
        for (iscan = SEG_E0; iscan < SEG_UNKNOWN; iscan++)
 #else
       {
        int iscan;
 
        for (iscan = SEG_E0; iscan < SEG_UNKNOWN; iscan++)
-         sh_count_relocs ((bfd *) NULL, iscan, (PTR) &info);
+         sh_count_relocs ((bfd *) NULL, iscan, &info);
       }
 #endif
 
       }
 #endif
 
@@ -2895,7 +3167,7 @@ sh_frob_section (abfd, sec, ignore)
    the stored function address entirely.  */
 
 void
    the stored function address entirely.  */
 
 void
-sh_frob_file ()
+sh_frob_file (void)
 {
 #ifdef HAVE_SH64
   shmedia_frob_file_before_adjust ();
 {
 #ifdef HAVE_SH64
   shmedia_frob_file_before_adjust ();
@@ -2905,13 +3177,13 @@ sh_frob_file ()
     return;
 
 #ifdef BFD_ASSEMBLER
     return;
 
 #ifdef BFD_ASSEMBLER
-  bfd_map_over_sections (stdoutput, sh_frob_section, (PTR) NULL);
+  bfd_map_over_sections (stdoutput, sh_frob_section, NULL);
 #else
   {
     int iseg;
 
     for (iseg = SEG_E0; iseg < SEG_UNKNOWN; iseg++)
 #else
   {
     int iseg;
 
     for (iseg = SEG_E0; iseg < SEG_UNKNOWN; iseg++)
-      sh_frob_section ((bfd *) NULL, iseg, (PTR) NULL);
+      sh_frob_section ((bfd *) NULL, iseg, NULL);
   }
 #endif
 }
   }
 #endif
 }
@@ -2920,14 +3192,12 @@ sh_frob_file ()
    create relocs so that md_apply_fix3 will fill in the correct values.  */
 
 void
    create relocs so that md_apply_fix3 will fill in the correct values.  */
 
 void
-md_convert_frag (headers, seg, fragP)
 #ifdef BFD_ASSEMBLER
 #ifdef BFD_ASSEMBLER
-     bfd *headers ATTRIBUTE_UNUSED;
+md_convert_frag (bfd *headers ATTRIBUTE_UNUSED, segT seg, fragS *fragP)
 #else
 #else
-     object_headers *headers;
+md_convert_frag (object_headers *headers ATTRIBUTE_UNUSED, segT seg,
+                fragS *fragP)
 #endif
 #endif
-     segT seg;
-     fragS *fragP;
 {
   int donerelax = 0;
 
 {
   int donerelax = 0;
 
@@ -3055,7 +3325,7 @@ md_convert_frag (headers, seg, fragP)
 
     default:
 #ifdef HAVE_SH64
 
     default:
 #ifdef HAVE_SH64
-      shmedia_md_convert_frag (headers, seg, fragP, true);
+      shmedia_md_convert_frag (headers, seg, fragP, TRUE);
 #else
       abort ();
 #endif
 #else
       abort ();
 #endif
@@ -3070,9 +3340,7 @@ md_convert_frag (headers, seg, fragP)
 }
 
 valueT
 }
 
 valueT
-md_section_align (seg, size)
-     segT seg ATTRIBUTE_UNUSED;
-     valueT size;
+md_section_align (segT seg ATTRIBUTE_UNUSED, valueT size)
 {
 #ifdef BFD_ASSEMBLER
 #ifdef OBJ_ELF
 {
 #ifdef BFD_ASSEMBLER
 #ifdef OBJ_ELF
@@ -3088,7 +3356,7 @@ md_section_align (seg, size)
 }
 
 /* This static variable is set by s_uacons to tell sh_cons_align that
 }
 
 /* This static variable is set by s_uacons to tell sh_cons_align that
-   the expession does not need to be aligned.  */
+   the expression does not need to be aligned.  */
 
 static int sh_no_align_cons = 0;
 
 
 static int sh_no_align_cons = 0;
 
@@ -3097,8 +3365,7 @@ static int sh_no_align_cons = 0;
    to be aligned.  */
 
 static void
    to be aligned.  */
 
 static void
-s_uacons (bytes)
-     int bytes;
+s_uacons (int bytes)
 {
   /* Tell sh_cons_align not to align this value.  */
   sh_no_align_cons = 1;
 {
   /* Tell sh_cons_align not to align this value.  */
   sh_no_align_cons = 1;
@@ -3112,8 +3379,7 @@ s_uacons (bytes)
    enable this warning?  */
 
 void
    enable this warning?  */
 
 void
-sh_cons_align (nbytes)
-     int nbytes;
+sh_cons_align (int nbytes)
 {
   int nalign;
   char *p;
 {
   int nalign;
   char *p;
@@ -3153,8 +3419,7 @@ sh_cons_align (nbytes)
    also where we check for misaligned data.  */
 
 void
    also where we check for misaligned data.  */
 
 void
-sh_handle_align (frag)
-     fragS *frag;
+sh_handle_align (fragS *frag)
 {
   int bytes = frag->fr_next->fr_address - frag->fr_address - frag->fr_fix;
 
 {
   int bytes = frag->fr_next->fr_address - frag->fr_address - frag->fr_fix;
 
@@ -3199,44 +3464,42 @@ sh_handle_align (frag)
             BFD_RELOC_SH_ALIGN);
 }
 
             BFD_RELOC_SH_ALIGN);
 }
 
-/* This macro decides whether a particular reloc is an entry in a
-   switch table.  It is used when relaxing, because the linker needs
-   to know about all such entries so that it can adjust them if
-   necessary.  */
+/* See whether the relocation should be resolved locally.  */
 
 
-#ifdef BFD_ASSEMBLER
-#define SWITCH_TABLE_CONS(fix) (0)
-#else
-#define SWITCH_TABLE_CONS(fix)                         \
-  ((fix)->fx_r_type == 0                               \
-   && ((fix)->fx_size == 2                             \
-       || (fix)->fx_size == 1                          \
-       || (fix)->fx_size == 4))
-#endif
-
-#define SWITCH_TABLE(fix)                              \
-  ((fix)->fx_addsy != NULL                             \
-   && (fix)->fx_subsy != NULL                          \
-   && S_GET_SEGMENT ((fix)->fx_addsy) == text_section  \
-   && 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)))
+static bfd_boolean
+sh_local_pcrel (fixS *fix)
+{
+  return (! sh_relax
+         && (fix->fx_r_type == BFD_RELOC_SH_PCDISP8BY2
+             || fix->fx_r_type == BFD_RELOC_SH_PCDISP12BY2
+             || fix->fx_r_type == BFD_RELOC_SH_PCRELIMM8BY2
+             || fix->fx_r_type == BFD_RELOC_SH_PCRELIMM8BY4
+             || fix->fx_r_type == BFD_RELOC_8_PCREL
+             || fix->fx_r_type == BFD_RELOC_SH_SWITCH16
+             || fix->fx_r_type == BFD_RELOC_SH_SWITCH32));
+}
 
 /* See whether we need to force a relocation into the output file.
    This is used to force out switch and PC relative relocations when
    relaxing.  */
 
 int
 
 /* See whether we need to force a relocation into the output file.
    This is used to force out switch and PC relative relocations when
    relaxing.  */
 
 int
-sh_force_relocation (fix)
-     fixS *fix;
+sh_force_relocation (fixS *fix)
 {
 {
+  /* These relocations can't make it into a DSO, so no use forcing
+     them for global symbols.  */
+  if (sh_local_pcrel (fix))
+    return 0;
 
 
-  if (fix->fx_r_type == BFD_RELOC_VTABLE_INHERIT
-      || fix->fx_r_type == BFD_RELOC_VTABLE_ENTRY
-      || fix->fx_r_type == BFD_RELOC_SH_LOOP_START
-      || fix->fx_r_type == BFD_RELOC_SH_LOOP_END)
+  /* Make sure some relocations get emitted.  */
+  if (fix->fx_r_type == BFD_RELOC_SH_LOOP_START
+      || fix->fx_r_type == BFD_RELOC_SH_LOOP_END
+      || fix->fx_r_type == BFD_RELOC_SH_TLS_GD_32
+      || fix->fx_r_type == BFD_RELOC_SH_TLS_LD_32
+      || fix->fx_r_type == BFD_RELOC_SH_TLS_IE_32
+      || fix->fx_r_type == BFD_RELOC_SH_TLS_LDO_32
+      || fix->fx_r_type == BFD_RELOC_SH_TLS_LE_32
+      || generic_force_reloc (fix))
     return 1;
 
   if (! sh_relax)
     return 1;
 
   if (! sh_relax)
@@ -3255,24 +3518,12 @@ sh_force_relocation (fix)
 }
 
 #ifdef OBJ_ELF
 }
 
 #ifdef OBJ_ELF
-boolean
-sh_fix_adjustable (fixP)
-   fixS *fixP;
+bfd_boolean
+sh_fix_adjustable (fixS *fixP)
 {
 {
-
-  if (fixP->fx_addsy == NULL)
-    return 1;
-
-  if (fixP->fx_r_type == BFD_RELOC_SH_PCDISP8BY2
-      || fixP->fx_r_type == BFD_RELOC_SH_PCDISP12BY2
-      || fixP->fx_r_type == BFD_RELOC_SH_PCRELIMM8BY2
-      || fixP->fx_r_type == BFD_RELOC_SH_PCRELIMM8BY4
-      || fixP->fx_r_type == BFD_RELOC_8_PCREL
-      || fixP->fx_r_type == BFD_RELOC_SH_SWITCH16
-      || fixP->fx_r_type == BFD_RELOC_SH_SWITCH32)
-    return 1;
-
-  if (! TC_RELOC_RTSYM_LOC_FIXUP (fixP)
+  if (fixP->fx_r_type == BFD_RELOC_32_PLT_PCREL
+      || fixP->fx_r_type == BFD_RELOC_32_GOT_PCREL
+      || fixP->fx_r_type == BFD_RELOC_SH_GOTPC
       || fixP->fx_r_type == BFD_RELOC_RVA)
     return 0;
 
       || fixP->fx_r_type == BFD_RELOC_RVA)
     return 0;
 
@@ -3285,12 +3536,12 @@ sh_fix_adjustable (fixP)
 }
 
 void
 }
 
 void
-sh_elf_final_processing ()
+sh_elf_final_processing (void)
 {
   int val;
 
   /* Set file-specific flags to indicate if this code needs
 {
   int val;
 
   /* Set file-specific flags to indicate if this code needs
-     a processor with the sh-dsp / sh3e ISA to execute.  */
+     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.  */
 #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.  */
@@ -3302,16 +3553,26 @@ sh_elf_final_processing ()
     val = EF_SH1;
   else if (valid_arch & arch_sh2)
     val = EF_SH2;
     val = EF_SH1;
   else if (valid_arch & arch_sh2)
     val = EF_SH2;
+  else if (valid_arch & arch_sh2e)
+    val = EF_SH2E;
   else if (valid_arch & arch_sh_dsp)
     val = EF_SH_DSP;
   else if (valid_arch & arch_sh3)
     val = EF_SH3;
   else if (valid_arch & arch_sh3_dsp)
   else if (valid_arch & arch_sh_dsp)
     val = EF_SH_DSP;
   else if (valid_arch & arch_sh3)
     val = EF_SH3;
   else if (valid_arch & arch_sh3_dsp)
-    val = EF_SH_DSP;
+    val = EF_SH3_DSP;
   else if (valid_arch & arch_sh3e)
     val = EF_SH3E;
   else if (valid_arch & arch_sh3e)
     val = EF_SH3E;
+  else if (valid_arch & arch_sh4_nofpu)
+    val = EF_SH4_NOFPU;
   else if (valid_arch & arch_sh4)
     val = EF_SH4;
   else if (valid_arch & arch_sh4)
     val = EF_SH4;
+  else if (valid_arch & arch_sh4a_nofpu)
+    val = EF_SH4A_NOFPU;
+  else if (valid_arch & arch_sh4a)
+    val = EF_SH4A;
+  else if (valid_arch & arch_sh4al_dsp)
+    val = EF_SH4AL_DSP;
   else
     abort ();
 
   else
     abort ();
 
@@ -3323,10 +3584,7 @@ sh_elf_final_processing ()
 /* Apply a fixup to the object file.  */
 
 void
 /* Apply a fixup to the object file.  */
 
 void
-md_apply_fix3 (fixP, valP, seg)
-     fixS * fixP;
-     valueT * valP;
-     segT seg ATTRIBUTE_UNUSED;
+md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 {
   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
   int lowbyte = target_big_endian ? 1 : 0;
 {
   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
   int lowbyte = target_big_endian ? 1 : 0;
@@ -3383,7 +3641,10 @@ md_apply_fix3 (fixP, valP, seg)
     val -= S_GET_VALUE  (fixP->fx_addsy);
 #endif
 
     val -= S_GET_VALUE  (fixP->fx_addsy);
 #endif
 
-#ifndef BFD_ASSEMBLER
+#ifdef BFD_ASSEMBLER
+  if (SWITCH_TABLE (fixP))
+    val -= S_GET_VALUE  (fixP->fx_subsy);
+#else
   if (fixP->fx_r_type == 0)
     {
       if (fixP->fx_size == 2)
   if (fixP->fx_r_type == 0)
     {
       if (fixP->fx_size == 2)
@@ -3444,7 +3705,7 @@ md_apply_fix3 (fixP, valP, seg)
     case BFD_RELOC_SH_PCRELIMM8BY4:
       /* The lower two bits of the PC are cleared before the
          displacement is added in.  We can assume that the destination
     case BFD_RELOC_SH_PCRELIMM8BY4:
       /* 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 bounday.  If this instruction is also on a 4
+         is on a 4 byte boundary.  If this instruction is also on a 4
          byte boundary, then we want
           (target - here) / 4
         and target - here is a multiple of 4.
          byte boundary, then we want
           (target - here) / 4
         and target - here is a multiple of 4.
@@ -3518,9 +3779,10 @@ md_apply_fix3 (fixP, valP, seg)
       /* Make the jump instruction point to the address of the operand.  At
         runtime we merely add the offset to the actual PLT entry.  */
       * valP = 0xfffffffc;
       /* Make the jump instruction point to the address of the operand.  At
         runtime we merely add the offset to the actual PLT entry.  */
       * valP = 0xfffffffc;
-      val = fixP->fx_addnumber;
+      val = fixP->fx_offset;
       if (fixP->fx_subsy)
        val -= S_GET_VALUE (fixP->fx_subsy);
       if (fixP->fx_subsy)
        val -= S_GET_VALUE (fixP->fx_subsy);
+      fixP->fx_addnumber = val;
       md_number_to_chars (buf, val, 4);
       break;
 
       md_number_to_chars (buf, val, 4);
       break;
 
@@ -3545,12 +3807,21 @@ md_apply_fix3 (fixP, valP, seg)
       md_number_to_chars (buf, val, 4);
       break;
 
       md_number_to_chars (buf, val, 4);
       break;
 
+    case BFD_RELOC_SH_TLS_GD_32:
+    case BFD_RELOC_SH_TLS_LD_32:
+    case BFD_RELOC_SH_TLS_IE_32:
+      S_SET_THREAD_LOCAL (fixP->fx_addsy);
+      /* Fallthrough */
     case BFD_RELOC_32_GOT_PCREL:
     case BFD_RELOC_SH_GOTPLT32:
       * valP = 0; /* Fully resolved at runtime.  No addend.  */
       md_number_to_chars (buf, 0, 4);
       break;
 
     case BFD_RELOC_32_GOT_PCREL:
     case BFD_RELOC_SH_GOTPLT32:
       * valP = 0; /* Fully resolved at runtime.  No addend.  */
       md_number_to_chars (buf, 0, 4);
       break;
 
+    case BFD_RELOC_SH_TLS_LDO_32:
+    case BFD_RELOC_SH_TLS_LE_32:
+      S_SET_THREAD_LOCAL (fixP->fx_addsy);
+      /* Fallthrough */
     case BFD_RELOC_32_GOTOFF:
       md_number_to_chars (buf, val, 4);
       break;
     case BFD_RELOC_32_GOTOFF:
       md_number_to_chars (buf, val, 4);
       break;
@@ -3586,9 +3857,7 @@ md_apply_fix3 (fixP, valP, seg)
    by which a fragment must grow to reach it's destination.  */
 
 int
    by which a fragment must grow to reach it's destination.  */
 
 int
-md_estimate_size_before_relax (fragP, segment_type)
-     register fragS *fragP;
-     register segT segment_type;
+md_estimate_size_before_relax (fragS *fragP, segT segment_type)
 {
   int what;
 
 {
   int what;
 
@@ -3664,10 +3933,7 @@ md_estimate_size_before_relax (fragP, segment_type)
 /* Put number into target byte order.  */
 
 void
 /* Put number into target byte order.  */
 
 void
-md_number_to_chars (ptr, use, nbytes)
-     char *ptr;
-     valueT use;
-     int nbytes;
+md_number_to_chars (char *ptr, valueT use, int nbytes)
 {
 #ifdef HAVE_SH64
   /* We might need to set the contents type to data.  */
 {
 #ifdef HAVE_SH64
   /* We might need to set the contents type to data.  */
@@ -3680,15 +3946,21 @@ md_number_to_chars (ptr, use, nbytes)
     number_to_chars_bigendian (ptr, use, nbytes);
 }
 
     number_to_chars_bigendian (ptr, use, nbytes);
 }
 
+/* This version is used in obj-coff.c when not using BFD_ASSEMBLER.
+   eg for the sh-hms target.  */
+
+long
+md_pcrel_from (fixS *fixP)
+{
+  return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address + 2;
+}
+
 long
 long
-md_pcrel_from_section (fixP, sec)
-     fixS *fixP;
-     segT sec;
+md_pcrel_from_section (fixS *fixP, segT sec)
 {
 {
-  if (fixP->fx_addsy != (symbolS *) NULL
-      && (! S_IS_DEFINED (fixP->fx_addsy)
-         || S_IS_EXTERN (fixP->fx_addsy)
-         || S_IS_WEAK (fixP->fx_addsy)
+  if (! sh_local_pcrel (fixP)
+      && fixP->fx_addsy != (symbolS *) NULL
+      && (generic_force_reloc (fixP)
          || S_GET_SEGMENT (fixP->fx_addsy) != sec))
     {
       /* The symbol is undefined (or is defined but not in this section,
          || S_GET_SEGMENT (fixP->fx_addsy) != sec))
     {
       /* The symbol is undefined (or is defined but not in this section,
@@ -3698,14 +3970,13 @@ md_pcrel_from_section (fixP, sec)
       return fixP->fx_subsy ? fixP->fx_where + fixP->fx_frag->fr_address : 0;
     }
 
       return fixP->fx_subsy ? fixP->fx_where + fixP->fx_frag->fr_address : 0;
     }
 
-  return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address + 2;
+  return md_pcrel_from (fixP);
 }
 
 #ifdef OBJ_COFF
 
 int
 }
 
 #ifdef OBJ_COFF
 
 int
-tc_coff_sizemachdep (frag)
-     fragS *frag;
+tc_coff_sizemachdep (fragS *frag)
 {
   return md_relax_table[frag->fr_subtype].rlx_length;
 }
 {
   return md_relax_table[frag->fr_subtype].rlx_length;
 }
@@ -3754,11 +4025,8 @@ static const struct reloc_map coff_reloc_map[] =
    but does some minor tweaking.  */
 
 void
    but does some minor tweaking.  */
 
 void
-sh_coff_reloc_mangle (seg, fix, intr, paddr)
-     segment_info_type *seg;
-     fixS *fix;
-     struct internal_reloc *intr;
-     unsigned int paddr;
+sh_coff_reloc_mangle (segment_info_type *seg, fixS *fix,
+                     struct internal_reloc *intr, unsigned int paddr)
 {
   symbolS *symbol_ptr = fix->fx_addsy;
   symbolS *dot;
 {
   symbolS *symbol_ptr = fix->fx_addsy;
   symbolS *dot;
@@ -3869,9 +4137,7 @@ sh_coff_reloc_mangle (seg, fix, intr, paddr)
 /* Create a reloc.  */
 
 arelent *
 /* Create a reloc.  */
 
 arelent *
-tc_gen_reloc (section, fixp)
-     asection *section ATTRIBUTE_UNUSED;
-     fixS *fixp;
+tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
 {
   arelent *rel;
   bfd_reloc_code_real_type r_type;
 {
   arelent *rel;
   bfd_reloc_code_real_type r_type;
@@ -3881,18 +4147,12 @@ tc_gen_reloc (section, fixp)
   *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
   *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
-  if (fixp->fx_subsy
-      && S_GET_SEGMENT (fixp->fx_subsy) == absolute_section)
-    {
-      fixp->fx_addnumber -= S_GET_VALUE (fixp->fx_subsy);
-      fixp->fx_subsy = 0;
-    }
-
   r_type = fixp->fx_r_type;
 
   if (SWITCH_TABLE (fixp))
     {
   r_type = fixp->fx_r_type;
 
   if (SWITCH_TABLE (fixp))
     {
-      rel->addend = rel->address - S_GET_VALUE (fixp->fx_subsy);
+      *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
+      rel->addend = 0;
       if (r_type == BFD_RELOC_16)
        r_type = BFD_RELOC_SH_SWITCH16;
       else if (r_type == BFD_RELOC_8)
       if (r_type == BFD_RELOC_16)
        r_type = BFD_RELOC_SH_SWITCH16;
       else if (r_type == BFD_RELOC_8)
@@ -3931,7 +4191,11 @@ tc_gen_reloc (section, fixp)
     rel->addend = 0;
 
   rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
     rel->addend = 0;
 
   rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
-  if (rel->howto == NULL || fixp->fx_subsy)
+#ifdef OBJ_ELF
+  if (rel->howto->type == R_SH_IND12W)
+      rel->addend += fixp->fx_offset - 4;
+#endif
+  if (rel->howto == NULL)
     {
       as_bad_where (fixp->fx_file, fixp->fx_line,
                    _("Cannot represent relocation type %s"),
     {
       as_bad_where (fixp->fx_file, fixp->fx_line,
                    _("Cannot represent relocation type %s"),
@@ -3946,8 +4210,7 @@ tc_gen_reloc (section, fixp)
 
 #ifdef OBJ_ELF
 inline static char *
 
 #ifdef OBJ_ELF
 inline static char *
-sh_end_of_match (cont, what)
-     char *cont, *what;
+sh_end_of_match (char *cont, char *what)
 {
   int len = strlen (what);
 
 {
   int len = strlen (what);
 
@@ -3959,10 +4222,7 @@ sh_end_of_match (cont, what)
 }
 
 int
 }
 
 int
-sh_parse_name (name, exprP, nextcharP)
-     char const *name;
-     expressionS *exprP;
-     char *nextcharP;
+sh_parse_name (char const *name, expressionS *exprP, char *nextcharP)
 {
   char *next = input_line_pointer;
   char *next_end;
 {
   char *next = input_line_pointer;
   char *next_end;
@@ -4014,6 +4274,16 @@ sh_parse_name (name, exprP, nextcharP)
     reloc_type = BFD_RELOC_32_GOT_PCREL;
   else if ((next_end = sh_end_of_match (next + 1, "PLT")))
     reloc_type = BFD_RELOC_32_PLT_PCREL;
     reloc_type = BFD_RELOC_32_GOT_PCREL;
   else if ((next_end = sh_end_of_match (next + 1, "PLT")))
     reloc_type = BFD_RELOC_32_PLT_PCREL;
+  else if ((next_end = sh_end_of_match (next + 1, "TLSGD")))
+    reloc_type = BFD_RELOC_SH_TLS_GD_32;
+  else if ((next_end = sh_end_of_match (next + 1, "TLSLDM")))
+    reloc_type = BFD_RELOC_SH_TLS_LD_32;
+  else if ((next_end = sh_end_of_match (next + 1, "GOTTPOFF")))
+    reloc_type = BFD_RELOC_SH_TLS_IE_32;
+  else if ((next_end = sh_end_of_match (next + 1, "TPOFF")))
+    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
     goto no_suffix;
 
   else
     goto no_suffix;
 
This page took 0.045803 seconds and 4 git commands to generate.