PR ld/11621
[deliverable/binutils-gdb.git] / gas / config / tc-sh.c
index 0abbe92e2116435a5c6f27b32c2b53c19dc0a2d2..a7cdd0ecceee3114257ad431c366275433a83243 100644 (file)
@@ -1,12 +1,13 @@
 /* tc-sh.c -- Assemble code for the Renesas / SuperH SH
    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005, 2006  Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
@@ -825,8 +826,97 @@ sh_elf_cons (register int nbytes)
   else
     demand_empty_rest_of_line ();
 }
-#endif /* OBJ_ELF */
 
+/* The regular frag_offset_fixed_p doesn't work for rs_align_test
+   frags.  */
+
+static bfd_boolean
+align_test_frag_offset_fixed_p (const fragS *frag1, const fragS *frag2,
+                               bfd_vma *offset)
+{
+  const fragS *frag;
+  bfd_vma off;
+
+  /* Start with offset initialised to difference between the two frags.
+     Prior to assigning frag addresses this will be zero.  */
+  off = frag1->fr_address - frag2->fr_address;
+  if (frag1 == frag2)
+    {
+      *offset = off;
+      return TRUE;
+    }
+
+  /* Maybe frag2 is after frag1.  */
+  frag = frag1;
+  while (frag->fr_type == rs_fill
+        || frag->fr_type == rs_align_test)
+    {
+      if (frag->fr_type == rs_fill)
+       off += frag->fr_fix + frag->fr_offset * frag->fr_var;
+      else
+       off += frag->fr_fix;
+      frag = frag->fr_next;
+      if (frag == NULL)
+       break;
+      if (frag == frag2)
+       {
+         *offset = off;
+         return TRUE;
+       }
+    }
+
+  /* Maybe frag1 is after frag2.  */
+  off = frag1->fr_address - frag2->fr_address;
+  frag = frag2;
+  while (frag->fr_type == rs_fill
+        || frag->fr_type == rs_align_test)
+    {
+      if (frag->fr_type == rs_fill)
+       off -= frag->fr_fix + frag->fr_offset * frag->fr_var;
+      else
+       off -= frag->fr_fix;
+      frag = frag->fr_next;
+      if (frag == NULL)
+       break;
+      if (frag == frag1)
+       {
+         *offset = off;
+         return TRUE;
+       }
+    }
+
+  return FALSE;
+}
+
+/* Optimize a difference of symbols which have rs_align_test frag if
+   possible.  */
+
+int
+sh_optimize_expr (expressionS *l, operatorT op, expressionS *r)
+{
+  bfd_vma frag_off;
+
+  if (op == O_subtract
+      && l->X_op == O_symbol
+      && r->X_op == O_symbol
+      && S_GET_SEGMENT (l->X_add_symbol) == S_GET_SEGMENT (r->X_add_symbol)
+      && (SEG_NORMAL (S_GET_SEGMENT (l->X_add_symbol))
+         || r->X_add_symbol == l->X_add_symbol)
+      && align_test_frag_offset_fixed_p (symbol_get_frag (l->X_add_symbol),
+                                        symbol_get_frag (r->X_add_symbol),
+                                        &frag_off))
+    {
+      l->X_add_number -= r->X_add_number;
+      l->X_add_number -= frag_off / OCTETS_PER_BYTE;
+      l->X_add_number += (S_GET_VALUE (l->X_add_symbol)
+                         - S_GET_VALUE (r->X_add_symbol));
+      l->X_op = O_constant;
+      l->X_add_symbol = 0;
+      return 1;
+    }
+  return 0;
+}
+#endif /* OBJ_ELF */
 \f
 /* This function is called once, at assembler startup time.  This should
    set up all the tables, etc that the MD part of the assembler needs.  */
@@ -1261,7 +1351,7 @@ static char *
 parse_exp (char *s, sh_operand_info *op)
 {
   char *save;
-  char *new;
+  char *new_pointer;
 
   save = input_line_pointer;
   input_line_pointer = s;
@@ -1274,9 +1364,9 @@ parse_exp (char *s, sh_operand_info *op)
           || sh_PIC_related_p (op->immediate.X_op_symbol))
     as_bad (_("misplaced PIC operand"));
 #endif
-  new = input_line_pointer;
+  new_pointer = input_line_pointer;
   input_line_pointer = save;
-  return new;
+  return new_pointer;
 }
 
 /* The many forms of operand:
@@ -1590,36 +1680,6 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
          sh_operand_info *user = operands + n;
          sh_arg_type arg = this_try->arg[n];
 
-         if (SH_MERGE_ARCH_SET_VALID (valid_arch, arch_sh2a_nofpu_up)
-             && (   arg == A_DISP_REG_M
-                 || arg == A_DISP_REG_N))
-           {
-             /* Check a few key IMM* fields for overflow.  */
-             int opf;
-             long val = user->immediate.X_add_number;
-
-             for (opf = 0; opf < 4; opf ++)
-               switch (this_try->nibbles[opf])
-                 {
-                 case IMM0_4:
-                 case IMM1_4:
-                   if (val < 0 || val > 15)
-                     goto fail;
-                   break;
-                 case IMM0_4BY2:
-                 case IMM1_4BY2:
-                   if (val < 0 || val > 15 * 2)
-                     goto fail;
-                   break;
-                 case IMM0_4BY4:
-                 case IMM1_4BY4:
-                   if (val < 0 || val > 15 * 4)
-                     goto fail;
-                   break;
-                 default:
-                   break;
-                 }
-           }
          switch (arg)
            {
            case A_DISP_PC:
@@ -2113,6 +2173,36 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
              printf (_("unhandled %d\n"), arg);
              goto fail;
            }
+         if (SH_MERGE_ARCH_SET_VALID (valid_arch, arch_sh2a_nofpu_up)
+             && (   arg == A_DISP_REG_M
+                 || arg == A_DISP_REG_N))
+           {
+             /* Check a few key IMM* fields for overflow.  */
+             int opf;
+             long val = user->immediate.X_add_number;
+
+             for (opf = 0; opf < 4; opf ++)
+               switch (this_try->nibbles[opf])
+                 {
+                 case IMM0_4:
+                 case IMM1_4:
+                   if (val < 0 || val > 15)
+                     goto fail;
+                   break;
+                 case IMM0_4BY2:
+                 case IMM1_4BY2:
+                   if (val < 0 || val > 15 * 2)
+                     goto fail;
+                   break;
+                 case IMM0_4BY4:
+                 case IMM1_4BY4:
+                   if (val < 0 || val > 15 * 4)
+                     goto fail;
+                   break;
+                 default:
+                   break;
+                 }
+           }
        }
       if ( !SH_MERGE_ARCH_SET_VALID (valid_arch, this_try->arch))
        goto fail;
@@ -2231,7 +2321,7 @@ insert_loop_bounds (char *output, sh_operand_info *operand)
 static unsigned int
 build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
 {
-  int index;
+  int indx;
   char nbuf[8];
   char *output;
   unsigned int size = 2;
@@ -2256,12 +2346,12 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
   else
     output = frag_more (2);
 
-  for (index = 0; index < max_index; index++)
+  for (indx = 0; indx < max_index; indx++)
     {
-      sh_nibble_type i = opcode->nibbles[index];
+      sh_nibble_type i = opcode->nibbles[indx];
       if (i < 16)
        {
-         nbuf[index] = i;
+         nbuf[indx] = i;
        }
       else
        {
@@ -2269,32 +2359,32 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
            {
            case REG_N:
            case REG_N_D:
-             nbuf[index] = reg_n;
+             nbuf[indx] = reg_n;
              break;
            case REG_M:
-             nbuf[index] = reg_m;
+             nbuf[indx] = reg_m;
              break;
            case SDT_REG_N:
              if (reg_n < 2 || reg_n > 5)
                as_bad (_("Invalid register: 'r%d'"), reg_n);
-             nbuf[index] = (reg_n & 3) | 4;
+             nbuf[indx] = (reg_n & 3) | 4;
              break;
            case REG_NM:
-             nbuf[index] = reg_n | (reg_m >> 2);
+             nbuf[indx] = reg_n | (reg_m >> 2);
              break;
            case REG_B:
-             nbuf[index] = reg_b | 0x08;
+             nbuf[indx] = reg_b | 0x08;
              break;
            case REG_N_B01:
-             nbuf[index] = reg_n | 0x01;
+             nbuf[indx] = reg_n | 0x01;
              break;
            case IMM0_3s:
-             nbuf[index] |= 0x08;
+             nbuf[indx] |= 0x08;
            case IMM0_3c:
              insert (output + low_byte, BFD_RELOC_SH_IMM3, 0, operand);
              break;
            case IMM0_3Us:
-             nbuf[index] |= 0x80;
+             nbuf[indx] |= 0x80;
            case IMM0_3Uc:
              insert (output + low_byte, BFD_RELOC_SH_IMM3U, 0, operand);
              break;
@@ -2376,7 +2466,7 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
              break;
            case REPEAT:
              output = insert_loop_bounds (output, operand);
-             nbuf[index] = opcode->nibbles[3];
+             nbuf[indx] = opcode->nibbles[3];
              operand += 2;
              break;
            default:
@@ -2865,6 +2955,9 @@ md_assemble (char *str)
            as_bad (_("Delayed branches not available on SH1"));
          parse_exp (op_end + 1, &operand[0]);
          build_relax (opcode, &operand[0]);
+
+         /* All branches are currently 16 bit.  */
+         size = 2;
        }
       else
        {
@@ -2953,61 +3046,11 @@ md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
 }
 
 /* Various routines to kill one day.  */
-/* Equal to MAX_PRECISION in atof-ieee.c.  */
-#define MAX_LITTLENUMS 6
-
-/* Turn a string in input_line_pointer into a floating point constant
-   of type TYPE, and store the appropriate bytes in *LITP.  The number
-   of LITTLENUMS emitted is stored in *SIZEP .  An error message is
-   returned, or NULL on OK.  */
 
 char *
 md_atof (int type, char *litP, int *sizeP)
 {
-  int prec;
-  LITTLENUM_TYPE words[4];
-  char *t;
-  int i;
-
-  switch (type)
-    {
-    case 'f':
-      prec = 2;
-      break;
-
-    case 'd':
-      prec = 4;
-      break;
-
-    default:
-      *sizeP = 0;
-      return _("bad call to md_atof");
-    }
-
-  t = atof_ieee (input_line_pointer, type, words);
-  if (t)
-    input_line_pointer = t;
-
-  *sizeP = prec * 2;
-
-  if (! target_big_endian)
-    {
-      for (i = prec - 1; i >= 0; i--)
-       {
-         md_number_to_chars (litP, (valueT) words[i], 2);
-         litP += 2;
-       }
-    }
-  else
-    {
-      for (i = 0; i < prec; i++)
-       {
-         md_number_to_chars (litP, (valueT) words[i], 2);
-         litP += 2;
-       }
-    }
-
-  return NULL;
+  return ieee_md_atof (type, litP, sizeP, target_big_endian);
 }
 
 /* Handle the .uses pseudo-op.  This pseudo-op is used just before a
@@ -3054,6 +3097,7 @@ enum options
   OPTION_NO_EXPAND,
   OPTION_PT32,
 #endif
+  OPTION_H_TICK_HEX,
   OPTION_DUMMY  /* Not used.  This is just here to make it easy to add and subtract options from this enum.  */
 };
 
@@ -3063,6 +3107,10 @@ struct option md_longopts[] =
   {"relax", no_argument, NULL, OPTION_RELAX},
   {"big", no_argument, NULL, OPTION_BIG},
   {"little", no_argument, NULL, OPTION_LITTLE},
+  /* The next two switches are here because the
+     generic parts of the linker testsuite uses them.  */
+  {"EB", no_argument, NULL, OPTION_BIG},
+  {"EL", no_argument, NULL, OPTION_LITTLE},
   {"small", no_argument, NULL, OPTION_SMALL},
   {"dsp", no_argument, NULL, OPTION_DSP},
   {"isa", required_argument, NULL, OPTION_ISA},
@@ -3076,6 +3124,7 @@ struct option md_longopts[] =
   {"no-expand",              no_argument, NULL, OPTION_NO_EXPAND},
   {"expand-pt32",            no_argument, NULL, OPTION_PT32},
 #endif /* HAVE_SH64 */
+  { "h-tick-hex", no_argument,       NULL, OPTION_H_TICK_HEX  },
 
   {NULL, no_argument, NULL, 0}
 };
@@ -3165,7 +3214,7 @@ md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
            }
          
          if (!preset_target_arch)
-           as_bad ("Invalid argument to --isa option: %s", arg);
+           as_bad (_("Invalid argument to --isa option: %s"), arg);
        }
       break;
 
@@ -3186,7 +3235,7 @@ md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
          sh64_abi = sh64_abi_64;
        }
       else
-       as_bad ("Invalid argument to --abi option: %s", arg);
+       as_bad (_("Invalid argument to --abi option: %s"), arg);
       break;
 
     case OPTION_NO_MIX:
@@ -3206,6 +3255,10 @@ md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
       break;
 #endif /* HAVE_SH64 */
 
+    case OPTION_H_TICK_HEX:
+      enable_h_tick_hex = 1;
+      break;
+
     default:
       return 0;
     }
@@ -3311,6 +3364,21 @@ sh_frob_section (bfd *abfd ATTRIBUTE_UNUSED, segT sec,
   if (seginfo == NULL)
     return;
 
+  for (fix = seginfo->fix_root; fix != NULL; fix = fix->fx_next)
+    {
+      symbolS *sym;
+
+      sym = fix->fx_addsy;
+      /* Check for a local_symbol.  */
+      if (sym && sym->bsym == NULL)
+       {
+         struct local_symbol *ls = (struct local_symbol *)sym;
+         /* See if it's been converted.  If so, canonicalize.  */
+         if (local_symbol_converted_p (ls))
+           fix->fx_addsy = local_symbol_get_real_symbol (ls);
+       }
+    }
+
   for (fix = seginfo->fix_root; fix != NULL; fix = fix->fx_next)
     {
       symbolS *sym;
@@ -3664,7 +3732,7 @@ sh_handle_align (fragS *frag)
   else if (frag->fr_type == rs_align_test)
     {
       if (bytes != 0)
-       as_warn_where (frag->fr_file, frag->fr_line, _("misaligned data"));
+       as_bad_where (frag->fr_file, frag->fr_line, _("misaligned data"));
     }
 
   if (sh_relax
@@ -3778,6 +3846,28 @@ sh_elf_final_processing (void)
 }
 #endif
 
+/* Apply fixup FIXP to SIZE-byte field BUF given that VAL is its
+   assembly-time value.  If we're generating a reloc for FIXP,
+   see whether the addend should be stored in-place or whether
+   it should be in an ELF r_addend field.  */
+
+static void
+apply_full_field_fix (fixS *fixP, char *buf, bfd_vma val, int size)
+{
+  reloc_howto_type *howto;
+
+  if (fixP->fx_addsy != NULL || fixP->fx_pcrel)
+    {
+      howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
+      if (howto && !howto->partial_inplace)
+       {
+         fixP->fx_addnumber = val;
+         return;
+       }
+    }
+  md_number_to_chars (buf, val, size);
+}
+
 /* Apply a fixup to the object file.  */
 
 void
@@ -3935,6 +4025,23 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       break;
 
     case BFD_RELOC_SH_PCRELIMM8BY4:
+      /* If we are dealing with a known destination ... */
+      if ((fixP->fx_addsy == NULL || S_IS_DEFINED (fixP->fx_addsy))
+         && (fixP->fx_subsy == NULL || S_IS_DEFINED (fixP->fx_addsy)))
+      {
+       /* Don't silently move the destination due to misalignment.
+          The absolute address is the fragment base plus the offset into
+          the fragment plus the pc relative offset to the label.  */
+       if ((fixP->fx_frag->fr_address + fixP->fx_where + val) & 3)
+         as_bad_where (fixP->fx_file, fixP->fx_line,
+                       _("offset to unaligned destination"));
+
+       /* The displacement cannot be zero or backward even if aligned.
+          Allow -2 because val has already been adjusted somewhere.  */
+       if (val < -2)
+         as_bad_where (fixP->fx_file, fixP->fx_line, _("negative offset"));
+      }
+
       /* The lower two bits of the PC are cleared before the
          displacement is added in.  We can assume that the destination
          is on a 4 byte boundary.  If this instruction is also on a 4
@@ -3978,11 +4085,11 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 
     case BFD_RELOC_32:
     case BFD_RELOC_32_PCREL:
-      md_number_to_chars (buf, val, 4);
+      apply_full_field_fix (fixP, buf, val, 4);
       break;
 
     case BFD_RELOC_16:
-      md_number_to_chars (buf, val, 2);
+      apply_full_field_fix (fixP, buf, val, 2);
       break;
 
     case BFD_RELOC_SH_USES:
@@ -4014,8 +4121,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       val = fixP->fx_offset;
       if (fixP->fx_subsy)
        val -= S_GET_VALUE (fixP->fx_subsy);
-      fixP->fx_addnumber = val;
-      md_number_to_chars (buf, val, 4);
+      apply_full_field_fix (fixP, buf, val, 4);
       break;
 
     case BFD_RELOC_SH_GOTPC:
@@ -4036,7 +4142,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
          was used to store the correction, but since the expression is
          not pcrel, I felt it would be confusing to do it this way.  */
       * valP -= 1;
-      md_number_to_chars (buf, val, 4);
+      apply_full_field_fix (fixP, buf, val, 4);
       break;
 
     case BFD_RELOC_SH_TLS_GD_32:
@@ -4047,7 +4153,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     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);
+      apply_full_field_fix (fixP, buf, 0, 4);
       break;
 
     case BFD_RELOC_SH_TLS_LDO_32:
@@ -4055,7 +4161,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       S_SET_THREAD_LOCAL (fixP->fx_addsy);
       /* Fallthrough */
     case BFD_RELOC_32_GOTOFF:
-      md_number_to_chars (buf, val, 4);
+      apply_full_field_fix (fixP, buf, val, 4);
       break;
 #endif
 
@@ -4078,8 +4184,16 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
        val = ((val >> shift)
               | ((long) -1 & ~ ((long) -1 >> shift)));
     }
+
+  /* Extend sign for 64-bit host.  */
+  val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
   if (max != 0 && (val < min || val > max))
     as_bad_where (fixP->fx_file, fixP->fx_line, _("offset out of range"));
+  else if (max != 0)
+    /* Stop the generic code from trying to overlow check the value as well.
+       It may not have the correct value anyway, as we do not store val back
+       into *valP.  */
+    fixP->fx_no_overflow = 1;
 
   if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
     fixP->fx_done = 1;
@@ -4253,12 +4367,8 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
   else if (shmedia_init_reloc (rel, fixp))
     ;
 #endif
-  else if (fixp->fx_pcrel)
-    rel->addend = fixp->fx_addnumber;
-  else if (r_type == BFD_RELOC_32 || r_type == BFD_RELOC_32_GOTOFF)
-    rel->addend = fixp->fx_addnumber;
   else
-    rel->addend = 0;
+    rel->addend = fixp->fx_addnumber;
 
   rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
 
@@ -4269,7 +4379,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
                    bfd_get_reloc_code_name (r_type));
       /* Set howto to a garbage value so that we can keep going.  */
       rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
-      assert (rel->howto != NULL);
+      gas_assert (rel->howto != NULL);
     }
 #ifdef OBJ_ELF
   else if (rel->howto->type == R_SH_IND12W)
This page took 0.030683 seconds and 4 git commands to generate.