2003-08-01 Jason Eckhardt <jle@rice.edu>
[deliverable/binutils-gdb.git] / gas / config / tc-sh.c
index 5afaad89683d47705c5fbd3a461f2b1eb010508e..d147df6df5b20bd315b5c72fbbaf3d603bce7d44 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.
@@ -71,6 +71,7 @@ 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 bfd_boolean sh_local_pcrel PARAMS ((fixS *fix));
 
 #ifdef OBJ_ELF
 static void sh_elf_cons PARAMS ((int));
@@ -135,10 +136,6 @@ const pseudo_typeS md_pseudo_table[] =
   {"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 },
 
@@ -162,9 +159,9 @@ int sh_relax;               /* set if -relax seen */
 
 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
    accomodate the insns seen so far.  */
@@ -433,7 +430,7 @@ const relax_typeS md_relax_table[C (END, 0)] = {
   { SH64PCREL16_F, SH64PCREL16_M, SH64PCREL16_LENGTH, C (SH64PCREL16PT_64, SH64PCREL32) },
   /* C (SH64PCREL16PT_64, SH64PCREL32) */
   { SH64PCREL32_F,
-    SH64PCREL32_M, 
+    SH64PCREL32_M,
     SH64PCREL32_LENGTH,
     C (SH64PCREL16PT_64, SH64PCREL48) },
   /* C (SH64PCREL16PT_64, SH64PCREL48) */
@@ -554,12 +551,12 @@ sh_check_fixup (main_exp, r_type_p)
      plus/minus a symbol.  However, gas' parser gives us:
 
        O_subtract (O_add (f@PLT, .), .LPCS#+2)
-       
+
      so we attempt to transform this into:
 
         O_subtract (f@PLT, O_subtract (.LPCS#+2, .))
 
-     which we can handle simply below.  */     
+     which we can handle simply below.  */
   if (exp->X_op == O_subtract)
     {
       if (sh_PIC_related_p (exp->X_op_symbol))
@@ -620,7 +617,7 @@ sh_check_fixup (main_exp, r_type_p)
            case BFD_RELOC_UNUSED:
              *r_type_p = BFD_RELOC_SH_GOTPC;
              break;
-             
+
            default:
              abort ();
            }
@@ -654,15 +651,15 @@ sh_check_fixup (main_exp, r_type_p)
            case BFD_RELOC_32_GOTOFF:
              *r_type_p = BFD_RELOC_SH_GOTOFF_LOW16;
              break;
-             
+
            case BFD_RELOC_SH_GOTPLT32:
              *r_type_p = BFD_RELOC_SH_GOTPLT_LOW16;
              break;
-             
+
            case BFD_RELOC_32_GOT_PCREL:
              *r_type_p = BFD_RELOC_SH_GOT_LOW16;
              break;
-             
+
            case BFD_RELOC_32_PLT_PCREL:
              *r_type_p = BFD_RELOC_SH_PLT_LOW16;
              break;
@@ -678,15 +675,15 @@ sh_check_fixup (main_exp, r_type_p)
            case BFD_RELOC_32_GOTOFF:
              *r_type_p = BFD_RELOC_SH_GOTOFF_MEDLOW16;
              break;
-             
+
            case BFD_RELOC_SH_GOTPLT32:
              *r_type_p = BFD_RELOC_SH_GOTPLT_MEDLOW16;
              break;
-             
+
            case BFD_RELOC_32_GOT_PCREL:
              *r_type_p = BFD_RELOC_SH_GOT_MEDLOW16;
              break;
-             
+
            case BFD_RELOC_32_PLT_PCREL:
              *r_type_p = BFD_RELOC_SH_PLT_MEDLOW16;
              break;
@@ -702,15 +699,15 @@ sh_check_fixup (main_exp, r_type_p)
            case BFD_RELOC_32_GOTOFF:
              *r_type_p = BFD_RELOC_SH_GOTOFF_MEDHI16;
              break;
-             
+
            case BFD_RELOC_SH_GOTPLT32:
              *r_type_p = BFD_RELOC_SH_GOTPLT_MEDHI16;
              break;
-             
+
            case BFD_RELOC_32_GOT_PCREL:
              *r_type_p = BFD_RELOC_SH_GOT_MEDHI16;
              break;
-             
+
            case BFD_RELOC_32_PLT_PCREL:
              *r_type_p = BFD_RELOC_SH_PLT_MEDHI16;
              break;
@@ -726,15 +723,15 @@ sh_check_fixup (main_exp, r_type_p)
            case BFD_RELOC_32_GOTOFF:
              *r_type_p = BFD_RELOC_SH_GOTOFF_HI16;
              break;
-             
+
            case BFD_RELOC_SH_GOTPLT32:
              *r_type_p = BFD_RELOC_SH_GOTPLT_HI16;
              break;
-             
+
            case BFD_RELOC_32_GOT_PCREL:
              *r_type_p = BFD_RELOC_SH_GOT_HI16;
              break;
-             
+
            case BFD_RELOC_32_PLT_PCREL:
              *r_type_p = BFD_RELOC_SH_PLT_HI16;
              break;
@@ -808,7 +805,7 @@ sh_cons_fix_new (frag, off, size, exp)
       as_bad (_("unsupported BFD relocation size %u"), size);
       r_type = BFD_RELOC_UNUSED;
     }
-    
+
   fix_new_exp (frag, off, size, exp, 0, r_type);
 }
 
@@ -825,7 +822,7 @@ sh_elf_cons (nbytes)
 #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 ();
@@ -862,11 +859,12 @@ sh_elf_cons (nbytes)
 void
 md_begin ()
 {
-  sh_opcode_info *opcode;
+  const sh_opcode_info *opcode;
   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
@@ -878,19 +876,13 @@ md_begin ()
   /* 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);
        }
-      else
-       {
-         /* Make all the opcodes with the same name point to the same
-            string.  */
-         opcode->name = prev_name;
-       }
     }
 }
 
@@ -1383,10 +1375,33 @@ parse_at (src, op)
                }
              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 adressing 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
                {
@@ -1550,7 +1565,7 @@ get_specific (opcode, operands)
   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.  */
@@ -2099,15 +2114,16 @@ assemble_ppi (op_end, opcode)
   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];
 
+      /* 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);
       opcode = get_specific (opcode, operand);
@@ -2235,6 +2251,15 @@ assemble_ppi (op_end, opcode)
                default:
                  as_bad (_("bad padd / psub 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;
@@ -2320,13 +2345,13 @@ md_assemble (str)
     {
       /* 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);
        }
 
-      seen_insn = true;
+      seen_insn = TRUE;
     }
 #endif /* HAVE_SH64 */
 
@@ -2358,6 +2383,12 @@ md_assemble (str)
       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]);
        }
@@ -2453,14 +2484,14 @@ md_undefined_symbol (name)
 
 void
 tc_crawl_symbol_chain (headers)
-     object_headers *headers;
+     object_headers *headers ATTRIBUTE_UNUSED;
 {
   printf (_("call to tc_crawl_symbol_chain \n"));
 }
 
 void
 tc_headers_hook (headers)
-     object_headers *headers;
+     object_headers *headers ATTRIBUTE_UNUSED;
 {
   printf (_("call to tc_headers_hook \n"));
 }
@@ -2557,7 +2588,7 @@ s_uses (ignore)
   demand_empty_rest_of_line ();
 }
 \f
-CONST char *md_shortopts = "";
+const char *md_shortopts = "";
 struct option md_longopts[] =
 {
 #define OPTION_RELAX  (OPTION_MD_BASE)
@@ -2565,20 +2596,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_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},
+  {"isa",                    required_argument, NULL, OPTION_ISA},
 #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)
-  {"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},
@@ -2614,12 +2645,16 @@ md_parse_option (c, arg)
       break;
 
     case OPTION_DSP:
-      sh_dsp = 1;
+      preset_target_arch = arch_sh1_up & ~arch_sh3e_up;
       break;
 
-#ifdef HAVE_SH64
     case OPTION_ISA:
-      if (strcasecmp (arg, "shmedia") == 0)
+      if (strcasecmp (arg, "sh4") == 0)
+       preset_target_arch = arch_sh4;
+      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"));
@@ -2633,10 +2668,12 @@ md_parse_option (c, arg)
            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;
 
+#ifdef HAVE_SH64
     case OPTION_ABI:
       if (strcmp (arg, "32") == 0)
        {
@@ -2657,19 +2694,19 @@ md_parse_option (c, arg)
       break;
 
     case OPTION_NO_MIX:
-      sh64_mix = false;
+      sh64_mix = FALSE;
       break;
 
     case OPTION_SHCOMPACT_CONST_CRANGE:
-      sh64_shcompact_const_crange = true;
+      sh64_shcompact_const_crange = TRUE;
       break;
 
     case OPTION_NO_EXPAND:
-      sh64_expand = false;
+      sh64_expand = FALSE;
       break;
 
     case OPTION_PT32:
-      sh64_pt32 = true;
+      sh64_pt32 = TRUE;
       break;
 #endif /* HAVE_SH64 */
 
@@ -2690,7 +2727,7 @@ 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\
--dsp                   enable sh-dsp insns, and disable sh3e / sh4 insns.\n"));
+-dsp                   enable sh-dsp insns, and disable sh2e/sh3e/sh4 insns.\n"));
 #ifdef HAVE_SH64
   fprintf (stream, _("\
 -isa=[shmedia          set default instruction set for SH64\n\
@@ -2903,7 +2940,7 @@ md_convert_frag (headers, seg, fragP)
 #ifdef BFD_ASSEMBLER
      bfd *headers ATTRIBUTE_UNUSED;
 #else
-     object_headers *headers;
+     object_headers *headers ATTRIBUTE_UNUSED;
 #endif
      segT seg;
      fragS *fragP;
@@ -3034,7 +3071,7 @@ md_convert_frag (headers, seg, fragP)
 
     default:
 #ifdef HAVE_SH64
-      shmedia_md_convert_frag (headers, seg, fragP, true);
+      shmedia_md_convert_frag (headers, seg, fragP, TRUE);
 #else
       abort ();
 #endif
@@ -3178,30 +3215,21 @@ sh_handle_align (frag)
             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 (fix)
+     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
@@ -3211,11 +3239,20 @@ int
 sh_force_relocation (fix)
      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)
@@ -3234,24 +3271,13 @@ sh_force_relocation (fix)
 }
 
 #ifdef OBJ_ELF
-boolean
+bfd_boolean
 sh_fix_adjustable (fixP)
    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;
 
@@ -3281,6 +3307,8 @@ sh_elf_final_processing ()
     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)
@@ -3310,7 +3338,7 @@ md_apply_fix3 (fixP, valP, seg)
   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
   int lowbyte = target_big_endian ? 1 : 0;
   int highbyte = target_big_endian ? 0 : 1;
-  long val = * (long *) valP;
+  long val = (long) *valP;
   long max, min;
   int shift;
 
@@ -3362,7 +3390,10 @@ md_apply_fix3 (fixP, valP, seg)
     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)
@@ -3497,9 +3528,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;
-      val = fixP->fx_addnumber;
+      val = fixP->fx_offset;
       if (fixP->fx_subsy)
        val -= S_GET_VALUE (fixP->fx_subsy);
+      fixP->fx_addnumber = val;
       md_number_to_chars (buf, val, 4);
       break;
 
@@ -3524,12 +3556,21 @@ md_apply_fix3 (fixP, valP, seg)
       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_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;
@@ -3659,15 +3700,24 @@ md_number_to_chars (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 (fixP)
+     fixS *fixP;
+{
+  return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address + 2;
+}
+
 long
 md_pcrel_from_section (fixP, sec)
      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,
@@ -3677,7 +3727,7 @@ md_pcrel_from_section (fixP, sec)
       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
@@ -3860,18 +3910,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;
 
-  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))
     {
-      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)
@@ -3910,7 +3954,11 @@ tc_gen_reloc (section, fixp)
     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"),
@@ -3935,7 +3983,7 @@ sh_end_of_match (cont, what)
     return cont + len;
 
   return NULL;
-}  
+}
 
 int
 sh_parse_name (name, exprP, nextcharP)
@@ -3982,7 +4030,7 @@ sh_parse_name (name, exprP, nextcharP)
     }
 
   exprP->X_add_symbol = symbol_find_or_make (name);
-  
+
   if (*nextcharP != '@')
     goto no_suffix;
   else if ((next_end = sh_end_of_match (next + 1, "GOTOFF")))
@@ -3993,6 +4041,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;
+  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;
 
This page took 0.0331 seconds and 4 git commands to generate.