2004-05-28 Andrew Stubbs <andrew.stubbs@superh.com>
[deliverable/binutils-gdb.git] / gas / config / tc-sh.c
index c49949185cc227bc7d748b53bc1ab997dc5e602e..a7e60ea9d0b59cce4776908b9d212696ddfe08b5 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-sh.c -- Assemble code for the Renesas / SuperH SH
-   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
-   Free Software Foundation, Inc.
+   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+   2003, 2004  Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -35,6 +35,7 @@
 #endif
 
 #include "dwarf2dbg.h"
+#include "dw2gencfi.h"
 
 typedef struct
   {
@@ -131,13 +132,17 @@ int sh_relax;             /* set if -relax seen */
 
 int sh_small;
 
+/* Flag to generate relocations against symbol values for local symbols.  */
+
+static int dont_adjust_reloc_32;
+
 /* preset architecture set, if given; zero otherwise.  */
 
-static int preset_target_arch;
+static unsigned int preset_target_arch;
 
 /* The bit mask of architectures that could
    accommodate the insns seen so far.  */
-static int valid_arch;
+static unsigned int valid_arch;
 
 const char EXP_CHARS[] = "eE";
 
@@ -831,10 +836,10 @@ md_begin (void)
 {
   const sh_opcode_info *opcode;
   char *prev_name = "";
-  int target_arch;
+  unsigned int target_arch;
 
   target_arch
-    = preset_target_arch ? preset_target_arch : arch_sh1_up & ~arch_sh_dsp_up;
+    = preset_target_arch ? preset_target_arch : arch_sh1_up & ~arch_sh_has_dsp;
   valid_arch = target_arch;
 
 #ifdef HAVE_SH64
@@ -848,7 +853,7 @@ md_begin (void)
     {
       if (strcmp (prev_name, opcode->name) != 0)
        {
-         if (! (opcode->arch & target_arch))
+         if (!SH_MERGE_ARCH_SET_VALID (opcode->arch, target_arch))
            continue;
          prev_name = opcode->name;
          hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
@@ -1400,13 +1405,13 @@ parse_at (char *src, sh_operand_info *op)
              || (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;
-             op->type = A_PMODY_N;
+             op->type = AY_PMOD_N;
            }
          else
            op->type = A_INC_N;
@@ -1579,8 +1584,6 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
            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)
@@ -1626,6 +1629,237 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
              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;
@@ -1784,9 +2018,9 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
              goto fail;
            }
        }
-      if ( !(valid_arch & this_try->arch))
+      if ( !SH_MERGE_ARCH_SET_VALID (valid_arch, this_try->arch))
        goto fail;
-      valid_arch &= this_try->arch;
+      valid_arch = SH_MERGE_ARCH_SET (valid_arch, this_try->arch);
       return this_try;
     fail:
       ;
@@ -1913,6 +2147,7 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
          switch (i)
            {
            case REG_N:
+           case REG_N_D:
              nbuf[index] = reg_n;
              break;
            case REG_M:
@@ -1929,6 +2164,9 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
            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;
@@ -2069,6 +2307,7 @@ assemble_ppi (char *op_end, sh_opcode_info *opcode)
 
       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)
        {
@@ -2099,9 +2338,43 @@ assemble_ppi (char *op_end, sh_opcode_info *opcode)
          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"));
+         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)
@@ -2123,6 +2396,8 @@ assemble_ppi (char *op_end, sh_opcode_info *opcode)
        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,
@@ -2151,11 +2426,31 @@ assemble_ppi (char *op_end, sh_opcode_info *opcode)
                     | (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);
+         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)
@@ -2170,13 +2465,34 @@ assemble_ppi (char *op_end, sh_opcode_info *opcode)
          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)
            {
-             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
+                      && (SH_MERGE_ARCH_SET_VALID (valid_arch, arch_sh4al_dsp_up)))
+               {
+                 valid_arch = SH_MERGE_ARCH_SET (valid_arch, arch_sh4al_dsp_up);
+                 field_b -= 0x8cf0;
+               }
+             else
                as_bad (_("insn cannot be combined with pmuls"));
-             field_b -= 0x8100;
              switch (field_b & 0xf)
                {
                case A_X0_NUM:
@@ -2192,7 +2508,7 @@ assemble_ppi (char *op_end, sh_opcode_info *opcode)
                  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 ).
@@ -2276,6 +2592,7 @@ md_assemble (char *str)
   sh_operand_info operand[3];
   sh_opcode_info *opcode;
   unsigned int size = 0;
+  char *initial_str = str;
 
 #ifdef HAVE_SH64
   if (sh64_isa_mode == sh64_isa_shmedia)
@@ -2302,7 +2619,46 @@ md_assemble (char *str)
 
   if (opcode == NULL)
     {
-      as_bad (_("unknown opcode"));
+      /* The opcode is not in the hash table.
+        This means we definately have an assembly failure,
+        but the instruction may be valid in another CPU variant.
+        In this case emit something better than 'unknown opcode'.
+        Search the full table in sh-opc.h to check. */
+
+      char *name = initial_str;
+      int name_length = 0;
+      const sh_opcode_info *op;
+      int found = 0;
+
+      /* identify opcode in string */
+      while (isspace (*name))
+       {
+         name++;
+       }
+      while (!isspace (name[name_length]))
+       {
+         name_length++;
+       }
+
+      /* search for opcode in full list */
+      for (op = sh_table; op->name; op++)
+       {
+         if (strncasecmp (op->name, name, name_length) == 0
+             && op->name[name_length] == '\0')
+           {
+             found = 1;
+             break;
+           }
+       }
+
+      if ( found )
+       {
+         as_bad (_("opcode not valid for this cpu variant"));
+       }
+      else
+       {
+         as_bad (_("unknown opcode"));
+       }
       return;
     }
 
@@ -2327,8 +2683,8 @@ md_assemble (char *str)
        {
          /* Since we skip get_specific here, we have to check & update
             valid_arch now.  */
-         if (valid_arch & opcode->arch)
-           valid_arch &= opcode->arch;
+         if (SH_MERGE_ARCH_SET_VALID (valid_arch, opcode->arch))
+           valid_arch = SH_MERGE_ARCH_SET (valid_arch, opcode->arch);
          else
            as_bad (_("Delayed branches not available on SH1"));
          parse_exp (op_end + 1, &operand[0]);
@@ -2532,6 +2888,7 @@ struct option md_longopts[] =
 #define OPTION_SMALL (OPTION_LITTLE + 1)
 #define OPTION_DSP (OPTION_SMALL + 1)
 #define OPTION_ISA                    (OPTION_DSP + 1)
+#define OPTION_RENESAS (OPTION_ISA + 1)
 
   {"relax", no_argument, NULL, OPTION_RELAX},
   {"big", no_argument, NULL, OPTION_BIG},
@@ -2539,8 +2896,10 @@ struct option md_longopts[] =
   {"small", no_argument, NULL, OPTION_SMALL},
   {"dsp", no_argument, NULL, OPTION_DSP},
   {"isa",                    required_argument, NULL, OPTION_ISA},
+  {"renesas", no_argument, NULL, OPTION_RENESAS},
+
 #ifdef HAVE_SH64
-#define OPTION_ABI                    (OPTION_ISA + 1)
+#define OPTION_ABI                    (OPTION_RENESAS + 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)
@@ -2578,12 +2937,26 @@ md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
       break;
 
     case OPTION_DSP:
-      preset_target_arch = arch_sh1_up & ~arch_sh3e_up;
+      preset_target_arch = arch_sh1_up & ~(arch_sh_sp_fpu|arch_sh_dp_fpu);
+      break;
+
+    case OPTION_RENESAS:
+      dont_adjust_reloc_32 = 1;
       break;
 
     case OPTION_ISA:
       if (strcasecmp (arg, "sh4") == 0)
        preset_target_arch = arch_sh4;
+      else if (strcasecmp (arg, "sh4-nofpu") == 0)
+       preset_target_arch = arch_sh4_nofpu;
+      else if (strcasecmp (arg, "sh4-nommu-nofpu") == 0)
+       preset_target_arch = arch_sh4_nommu_nofpu;
+      else if (strcasecmp (arg, "sh4a") == 0)
+       preset_target_arch = arch_sh4a;
+      else if (strcasecmp (arg, "dsp") == 0)
+       preset_target_arch = arch_sh1_up & ~(arch_sh_sp_fpu|arch_sh_dp_fpu);
+      else if (strcasecmp (arg, "fp") == 0)
+       preset_target_arch = arch_sh1_up & ~arch_sh_has_dsp;
       else if (strcasecmp (arg, "any") == 0)
        preset_target_arch = arch_sh1_up;
 #ifdef HAVE_SH64
@@ -2603,7 +2976,35 @@ md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
        }
 #endif /* HAVE_SH64 */
       else
-       as_bad ("Invalid argument to --isa option: %s", arg);
+       {
+         extern const bfd_arch_info_type bfd_sh_arch;
+         extern unsigned int sh_ef_archset_table[];
+         bfd_arch_info_type *bfd_arch = &bfd_sh_arch;
+         preset_target_arch = 0;
+         for (; bfd_arch; bfd_arch=bfd_arch->next)
+           {
+             int len = strlen(bfd_arch->printable_name);
+             
+             if (bfd_arch->mach == bfd_mach_sh5)
+               continue;
+             
+             if (strncasecmp (bfd_arch->printable_name, arg, len) != 0)
+               continue;
+
+             if (arg[len] == '\0')
+               preset_target_arch =
+                 sh_get_arch_from_bfd_mach (bfd_arch->mach);
+             else if (strcasecmp(&arg[len], "-up") == 0)
+               preset_target_arch =
+                 sh_get_arch_up_from_bfd_mach (bfd_arch->mach);
+             else
+               continue;
+             break;
+           }
+         
+         if (!preset_target_arch)
+           as_bad ("Invalid argument to --isa option: %s", arg);
+       }
       break;
 
 #ifdef HAVE_SH64
@@ -2658,14 +3059,31 @@ SH options:\n\
 -little                        generate little endian code\n\
 -big                   generate big endian code\n\
 -relax                 alter jump instructions for long displacements\n\
+-renesas               disable optimization with section symbol for\n\
+                       compatibility with Renesas assembler.\n\
 -small                 align sections to 4 byte boundaries, not 16\n\
--dsp                   enable sh-dsp insns, and disable sh2e/sh3e/sh4 insns.\n"));
+-dsp                   enable sh-dsp insns, and disable floating-point ISAs.\n\
+-isa=[any              use most appropriate isa\n\
+    | dsp               same as '-dsp'\n\
+    | fp"));
+  {
+    extern const bfd_arch_info_type bfd_sh_arch;
+    bfd_arch_info_type *bfd_arch = &bfd_sh_arch;
+    for (; bfd_arch; bfd_arch=bfd_arch->next)
+      if (bfd_arch->mach != bfd_mach_sh5)
+       {
+         fprintf (stream, "\n    | %s", bfd_arch->printable_name);
+         fprintf (stream, "\n    | %s-up", bfd_arch->printable_name);
+       }
+  }
+  fprintf (stream, "]\n");
 #ifdef HAVE_SH64
   fprintf (stream, _("\
--isa=[shmedia          set default instruction set for SH64\n\
-      | SHmedia\n\
-      | shcompact\n\
-      | SHcompact]\n\
+-isa=[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\
@@ -2674,7 +3092,7 @@ 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\
-                       to 32 bits only"));
+                       to 32 bits only\n"));
 #endif /* HAVE_SH64 */
 }
 \f
@@ -3195,6 +3613,7 @@ sh_fix_adjustable (fixS *fixP)
   if (fixP->fx_r_type == BFD_RELOC_32_PLT_PCREL
       || fixP->fx_r_type == BFD_RELOC_32_GOT_PCREL
       || fixP->fx_r_type == BFD_RELOC_SH_GOTPC
+      || ((fixP->fx_r_type == BFD_RELOC_32) && dont_adjust_reloc_32)
       || fixP->fx_r_type == BFD_RELOC_RVA)
     return 0;
 
@@ -3212,7 +3631,7 @@ sh_elf_final_processing (void)
   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.  */
@@ -3220,24 +3639,7 @@ sh_elf_final_processing (void)
     val = EF_SH5;
   else
 #endif /* HAVE_SH64 */
-  if (valid_arch & arch_sh1)
-    val = EF_SH1;
-  else if (valid_arch & arch_sh2)
-    val = EF_SH2;
-  else if (valid_arch & arch_sh2e)
-    val = EF_SH2E;
-  else if (valid_arch & arch_sh_dsp)
-    val = EF_SH_DSP;
-  else if (valid_arch & arch_sh3)
-    val = EF_SH3;
-  else if (valid_arch & arch_sh3_dsp)
-    val = EF_SH_DSP;
-  else if (valid_arch & arch_sh3e)
-    val = EF_SH3E;
-  else if (valid_arch & arch_sh4)
-    val = EF_SH4;
-  else
-    abort ();
+    val = sh_find_elf_flags (valid_arch);
 
   elf_elfheader (stdoutput)->e_flags &= ~EF_SH_MACH_MASK;
   elf_elfheader (stdoutput)->e_flags |= val;
@@ -3854,10 +4256,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
     rel->addend = 0;
 
   rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
-#ifdef OBJ_ELF
-  if (rel->howto->type == R_SH_IND12W)
-      rel->addend += fixp->fx_offset - 4;
-#endif
+
   if (rel->howto == NULL)
     {
       as_bad_where (fixp->fx_file, fixp->fx_line,
@@ -3867,6 +4266,10 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
       rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
       assert (rel->howto != NULL);
     }
+#ifdef OBJ_ELF
+  else if (rel->howto->type == R_SH_IND12W)
+    rel->addend += fixp->fx_offset - 4;
+#endif
 
   return rel;
 }
@@ -3962,4 +4365,53 @@ sh_parse_name (char const *name, expressionS *exprP, char *nextcharP)
   return 1;
 }
 #endif
+
+void
+sh_cfi_frame_initial_instructions (void)
+{
+  cfi_add_CFA_def_cfa (15, 0);
+}
+
+int
+sh_regname_to_dw2regnum (const char *regname)
+{
+  unsigned int regnum = -1;
+  unsigned int i;
+  const char *p;
+  char *q;
+  static struct { char *name; int dw2regnum; } regnames[] =
+    {
+      { "pr", 17 }, { "t", 18 }, { "gbr", 19 }, { "mach", 20 },
+      { "macl", 21 }, { "fpul", 23 }
+    };
+
+  for (i = 0; i < ARRAY_SIZE (regnames); ++i)
+    if (strcmp (regnames[i].name, regname) == 0)
+      return regnames[i].dw2regnum;
+
+  if (regname[0] == 'r')
+    {
+      p = regname + 1;
+      regnum = strtoul (p, &q, 10);
+      if (p == q || *q || regnum >= 16)
+       return -1;
+    }
+  else if (regname[0] == 'f' && regname[1] == 'r')
+    {
+      p = regname + 2;
+      regnum = strtoul (p, &q, 10);
+      if (p == q || *q || regnum >= 16)
+       return -1;
+      regnum += 25;
+    }
+  else if (regname[0] == 'x' && regname[1] == 'd')
+    {
+      p = regname + 2;
+      regnum = strtoul (p, &q, 10);
+      if (p == q || *q || regnum >= 8)
+       return -1;
+      regnum += 87;
+    }
+  return regnum;
+}
 #endif /* BFD_ASSEMBLER */
This page took 0.032613 seconds and 4 git commands to generate.