gas TC_PARSE_CONS_EXPRESSION communication with TC_CONS_FIX_NEW
[deliverable/binutils-gdb.git] / gas / config / tc-sh.c
index acf62aef21d643947ecf64ef2cf22934a130a23f..a0cd212641efa8cf7d18d95dee28aec557d87f8c 100644 (file)
@@ -1,12 +1,11 @@
 /* tc-sh.c -- Assemble code for the Renesas / SuperH SH
-   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005  Free Software Foundation, Inc.
+   Copyright (C) 1993-2014 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,
@@ -21,9 +20,7 @@
 
 /* Written By Steve Chamberlain <sac@cygnus.com>  */
 
-#include <stdio.h>
 #include "as.h"
-#include "bfd.h"
 #include "subsegs.h"
 #define DEFINE_TABLE
 #include "opcodes/sh-opc.h"
@@ -146,6 +143,11 @@ static unsigned int preset_target_arch;
    accommodate the insns seen so far.  */
 static unsigned int valid_arch;
 
+#ifdef OBJ_ELF
+/* Whether --fdpic was given.  */
+static int sh_fdpic;
+#endif
+
 const char EXP_CHARS[] = "eE";
 
 /* Chars that mean this number is a floating point constant.  */
@@ -613,7 +615,6 @@ sh_check_fixup (expressionS *main_exp, bfd_reloc_code_real_type *r_type_p)
 
   if (exp->X_op == O_PIC_reloc)
     {
-#ifdef HAVE_SH64
       switch (*r_type_p)
        {
        case BFD_RELOC_NONE:
@@ -621,6 +622,31 @@ sh_check_fixup (expressionS *main_exp, bfd_reloc_code_real_type *r_type_p)
          *r_type_p = exp->X_md;
          break;
 
+       case BFD_RELOC_SH_DISP20:
+         switch (exp->X_md)
+           {
+           case BFD_RELOC_32_GOT_PCREL:
+             *r_type_p = BFD_RELOC_SH_GOT20;
+             break;
+
+           case BFD_RELOC_32_GOTOFF:
+             *r_type_p = BFD_RELOC_SH_GOTOFF20;
+             break;
+
+           case BFD_RELOC_SH_GOTFUNCDESC:
+             *r_type_p = BFD_RELOC_SH_GOTFUNCDESC20;
+             break;
+
+           case BFD_RELOC_SH_GOTOFFFUNCDESC:
+             *r_type_p = BFD_RELOC_SH_GOTOFFFUNCDESC20;
+             break;
+
+           default:
+             abort ();
+           }
+         break;
+
+#ifdef HAVE_SH64
        case BFD_RELOC_SH_IMM_LOW16:
          switch (exp->X_md)
            {
@@ -716,13 +742,11 @@ sh_check_fixup (expressionS *main_exp, bfd_reloc_code_real_type *r_type_p)
              abort ();
            }
          break;
+#endif
 
        default:
          abort ();
        }
-#else
-      *r_type_p = exp->X_md;
-#endif
       if (exp == main_exp)
        exp->X_op = O_symbol;
       else
@@ -741,9 +765,10 @@ sh_check_fixup (expressionS *main_exp, bfd_reloc_code_real_type *r_type_p)
 /* Add expression EXP of SIZE bytes to offset OFF of fragment FRAG.  */
 
 void
-sh_cons_fix_new (fragS *frag, int off, int size, expressionS *exp)
+sh_cons_fix_new (fragS *frag, int off, int size, expressionS *exp,
+                bfd_reloc_code_real_type r_type)
 {
-  bfd_reloc_code_real_type r_type = BFD_RELOC_UNUSED;
+  r_type = BFD_RELOC_UNUSED;
 
   if (sh_check_fixup (exp, &r_type))
     as_bad (_("Invalid PIC expression."));
@@ -763,11 +788,9 @@ sh_cons_fix_new (fragS *frag, int off, int size, expressionS *exp)
        r_type = BFD_RELOC_32;
        break;
 
-#ifdef HAVE_SH64
       case 8:
        r_type = BFD_RELOC_64;
        break;
-#endif
 
       default:
        goto error;
@@ -827,8 +850,98 @@ sh_elf_cons (register int nbytes)
   else
     demand_empty_rest_of_line ();
 }
-#endif /* OBJ_ELF */
 
+/* The regular frag_offset_fixed_p doesn't work for rs_align_test
+   frags.  */
+
+static 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))
+    {
+      offsetT symval_diff = S_GET_VALUE (l->X_add_symbol)
+                           - S_GET_VALUE (r->X_add_symbol);
+      subtract_from_result (l, r->X_add_number, r->X_extrabit);
+      subtract_from_result (l, frag_off / OCTETS_PER_BYTE, 0);
+      add_to_result (l, symval_diff, symval_diff < 0);
+      l->X_op = O_constant;
+      l->X_add_symbol = 0;
+      return 1;
+    }
+  return 0;
+}
+#endif /* OBJ_ELF */
 \f
 /* This function is called once, at assembler startup time.  This should
    set up all the tables, etc that the MD part of the assembler needs.  */
@@ -1263,22 +1376,16 @@ static char *
 parse_exp (char *s, sh_operand_info *op)
 {
   char *save;
-  char *new;
+  char *new_pointer;
 
   save = input_line_pointer;
   input_line_pointer = s;
   expression (&op->immediate);
   if (op->immediate.X_op == O_absent)
     as_bad (_("missing operand"));
-#ifdef OBJ_ELF
-  else if (op->immediate.X_op == O_PIC_reloc
-          || sh_PIC_related_p (op->immediate.X_add_symbol)
-          || sh_PIC_related_p (op->immediate.X_op_symbol))
-    as_bad (_("misplaced PIC operand"));
-#endif
-  new = input_line_pointer;
+  new_pointer = input_line_pointer;
   input_line_pointer = save;
-  return new;
+  return new_pointer;
 }
 
 /* The many forms of operand:
@@ -1592,36 +1699,6 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands)
          sh_operand_info *user = operands + n;
          sh_arg_type arg = this_try->arg[n];
 
-         if (SH_MERGE_ARCH_SET_VALID (valid_arch, arch_sh2a_nofpu_up)
-             && (   arg == A_DISP_REG_M
-                 || arg == A_DISP_REG_N))
-           {
-             /* Check a few key IMM* fields for overflow.  */
-             int opf;
-             long val = user->immediate.X_add_number;
-
-             for (opf = 0; opf < 4; opf ++)
-               switch (this_try->nibbles[opf])
-                 {
-                 case IMM0_4:
-                 case IMM1_4:
-                   if (val < 0 || val > 15)
-                     goto fail;
-                   break;
-                 case IMM0_4BY2:
-                 case IMM1_4BY2:
-                   if (val < 0 || val > 15 * 2)
-                     goto fail;
-                   break;
-                 case IMM0_4BY4:
-                 case IMM1_4BY4:
-                   if (val < 0 || val > 15 * 4)
-                     goto fail;
-                   break;
-                 default:
-                   break;
-                 }
-           }
          switch (arg)
            {
            case A_DISP_PC:
@@ -2115,6 +2192,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;
@@ -2233,12 +2340,16 @@ insert_loop_bounds (char *output, sh_operand_info *operand)
 static unsigned int
 build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
 {
-  int index;
+  int indx;
   char nbuf[8];
   char *output;
   unsigned int size = 2;
   int low_byte = target_big_endian ? 1 : 0;
   int max_index = 4;
+  bfd_reloc_code_real_type r_type;
+#ifdef OBJ_ELF
+  int unhandled_pic = 0;
+#endif
 
   nbuf[0] = 0;
   nbuf[1] = 0;
@@ -2249,6 +2360,16 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
   nbuf[6] = 0;
   nbuf[7] = 0;
 
+#ifdef OBJ_ELF
+  for (indx = 0; indx < 3; indx++)
+    if (opcode->arg[indx] == A_IMM
+       && operand[indx].type == A_IMM
+       && (operand[indx].immediate.X_op == O_PIC_reloc
+           || sh_PIC_related_p (operand[indx].immediate.X_add_symbol)
+           || sh_PIC_related_p (operand[indx].immediate.X_op_symbol)))
+      unhandled_pic = 1;
+#endif
+
   if (SH_MERGE_ARCH_SET (opcode->arch, arch_op32))
     {
       output = frag_more (4);
@@ -2258,12 +2379,12 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
   else
     output = frag_more (2);
 
-  for (index = 0; index < max_index; index++)
+  for (indx = 0; indx < max_index; indx++)
     {
-      sh_nibble_type i = opcode->nibbles[index];
+      sh_nibble_type i = opcode->nibbles[indx];
       if (i < 16)
        {
-         nbuf[index] = i;
+         nbuf[indx] = i;
        }
       else
        {
@@ -2271,32 +2392,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;
@@ -2327,7 +2448,13 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
            case IMM0_20_4:
              break;
            case IMM0_20:
-             insert4 (output, BFD_RELOC_SH_DISP20, 0, operand);
+             r_type = BFD_RELOC_SH_DISP20;
+#ifdef OBJ_ELF
+             if (sh_check_fixup (&operand->immediate, &r_type))
+               as_bad (_("Invalid PIC expression."));
+             unhandled_pic = 0;
+#endif
+             insert4 (output, r_type, 0, operand);
              break;
            case IMM0_20BY8:
              insert4 (output, BFD_RELOC_SH_DISP20BY8, 0, operand);
@@ -2378,7 +2505,7 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
              break;
            case REPEAT:
              output = insert_loop_bounds (output, operand);
-             nbuf[index] = opcode->nibbles[3];
+             nbuf[indx] = opcode->nibbles[3];
              operand += 2;
              break;
            default:
@@ -2386,6 +2513,10 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
            }
        }
     }
+#ifdef OBJ_ELF
+  if (unhandled_pic)
+    as_bad (_("misplaced PIC operand"));
+#endif
   if (!target_big_endian)
     {
       output[1] = (nbuf[0] << 4) | (nbuf[1]);
@@ -2422,7 +2553,7 @@ find_cooked_opcode (char **str_p)
   unsigned char *op_start;
   unsigned char *op_end;
   char name[20];
-  int nlen = 0;
+  unsigned int nlen = 0;
 
   /* Drop leading whitespace.  */
   while (*str == ' ')
@@ -2434,7 +2565,7 @@ find_cooked_opcode (char **str_p)
      assemble_ppi, so the opcode might be terminated by an '@'.  */
   for (op_start = op_end = (unsigned char *) str;
        *op_end
-       && nlen < 20
+       && nlen < sizeof (name) - 1
        && !is_end_of_line[*op_end] && *op_end != ' ' && *op_end != '@';
        op_end++)
     {
@@ -2798,7 +2929,7 @@ md_assemble (char *str)
   if (opcode == NULL)
     {
       /* The opcode is not in the hash table.
-        This means we definately have an assembly failure,
+        This means we definitely have an assembly failure,
         but the instruction may be valid in another CPU variant.
         In this case emit something better than 'unknown opcode'.
         Search the full table in sh-opc.h to check. */
@@ -2867,6 +2998,9 @@ md_assemble (char *str)
            as_bad (_("Delayed branches not available on SH1"));
          parse_exp (op_end + 1, &operand[0]);
          build_relax (opcode, &operand[0]);
+
+         /* All branches are currently 16 bit.  */
+         size = 2;
        }
       else
        {
@@ -2955,61 +3089,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
@@ -3055,6 +3139,10 @@ enum options
   OPTION_SHCOMPACT_CONST_CRANGE,
   OPTION_NO_EXPAND,
   OPTION_PT32,
+#endif
+  OPTION_H_TICK_HEX,
+#ifdef OBJ_ELF
+  OPTION_FDPIC,
 #endif
   OPTION_DUMMY  /* Not used.  This is just here to make it easy to add and subtract options from this enum.  */
 };
@@ -3065,6 +3153,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},
@@ -3078,6 +3170,11 @@ 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  },
+
+#ifdef OBJ_ELF
+  {"fdpic", no_argument, NULL, OPTION_FDPIC},
+#endif
 
   {NULL, no_argument, NULL, 0}
 };
@@ -3167,7 +3264,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;
 
@@ -3188,7 +3285,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:
@@ -3208,6 +3305,16 @@ md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
       break;
 #endif /* HAVE_SH64 */
 
+    case OPTION_H_TICK_HEX:
+      enable_h_tick_hex = 1;
+      break;
+
+#ifdef OBJ_ELF
+    case OPTION_FDPIC:
+      sh_fdpic = TRUE;
+      break;
+#endif /* OBJ_ELF */
+
     default:
       return 0;
     }
@@ -3260,6 +3367,10 @@ SH options:\n\
 --expand-pt32          with -abi=64, expand PT, PTA and PTB instructions\n\
                        to 32 bits only\n"));
 #endif /* HAVE_SH64 */
+#ifdef OBJ_ELF
+  fprintf (stream, _("\
+--fdpic                        generate an FDPIC object file\n"));
+#endif /* OBJ_ELF */
 }
 \f
 /* This struct is used to pass arguments to sh_count_relocs through
@@ -3313,6 +3424,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;
@@ -3597,7 +3723,6 @@ void
 sh_cons_align (int nbytes)
 {
   int nalign;
-  char *p;
 
   if (sh_no_align_cons)
     {
@@ -3623,8 +3748,8 @@ sh_cons_align (int nbytes)
       return;
     }
 
-  p = frag_var (rs_align_test, 1, 1, (relax_substateT) 0,
-               (symbolS *) NULL, (offsetT) nalign, (char *) NULL);
+  frag_var (rs_align_test, 1, 1, (relax_substateT) 0,
+           (symbolS *) NULL, (offsetT) nalign, (char *) NULL);
 
   record_alignment (now_seg, nalign);
 }
@@ -3666,7 +3791,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
@@ -3738,7 +3863,13 @@ sh_fix_adjustable (fixS *fixP)
 {
   if (fixP->fx_r_type == BFD_RELOC_32_PLT_PCREL
       || fixP->fx_r_type == BFD_RELOC_32_GOT_PCREL
+      || fixP->fx_r_type == BFD_RELOC_SH_GOT20
       || fixP->fx_r_type == BFD_RELOC_SH_GOTPC
+      || fixP->fx_r_type == BFD_RELOC_SH_GOTFUNCDESC
+      || fixP->fx_r_type == BFD_RELOC_SH_GOTFUNCDESC20
+      || fixP->fx_r_type == BFD_RELOC_SH_GOTOFFFUNCDESC
+      || fixP->fx_r_type == BFD_RELOC_SH_GOTOFFFUNCDESC20
+      || fixP->fx_r_type == BFD_RELOC_SH_FUNCDESC
       || ((fixP->fx_r_type == BFD_RELOC_32) && dont_adjust_reloc_32)
       || fixP->fx_r_type == BFD_RELOC_RVA)
     return 0;
@@ -3777,9 +3908,47 @@ sh_elf_final_processing (void)
 
   elf_elfheader (stdoutput)->e_flags &= ~EF_SH_MACH_MASK;
   elf_elfheader (stdoutput)->e_flags |= val;
+
+  if (sh_fdpic)
+    elf_elfheader (stdoutput)->e_flags |= EF_SH_FDPIC;
 }
 #endif
 
+#ifdef TE_UCLINUX
+/* Return the target format for uClinux.  */
+
+const char *
+sh_uclinux_target_format (void)
+{
+  if (sh_fdpic)
+    return (!target_big_endian ? "elf32-sh-fdpic" : "elf32-shbig-fdpic");
+  else
+    return (!target_big_endian ? "elf32-shl" : "elf32-sh");
+}
+#endif
+
+/* Apply fixup FIXP to SIZE-byte field BUF given that VAL is its
+   assembly-time value.  If we're generating a reloc for FIXP,
+   see whether the addend should be stored in-place or whether
+   it should be in an ELF r_addend field.  */
+
+static void
+apply_full_field_fix (fixS *fixP, char *buf, bfd_vma val, int size)
+{
+  reloc_howto_type *howto;
+
+  if (fixP->fx_addsy != NULL || fixP->fx_pcrel)
+    {
+      howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
+      if (howto && !howto->partial_inplace)
+       {
+         fixP->fx_addnumber = val;
+         return;
+       }
+    }
+  md_number_to_chars (buf, val, size);
+}
+
 /* Apply a fixup to the object file.  */
 
 void
@@ -3797,6 +3966,11 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
      the other symbol.  We have to adjust the relocation type here.  */
   if (fixP->fx_pcrel)
     {
+#ifndef HAVE_SH64
+      /* Safeguard; this must not occur for non-sh64 configurations.  */
+      gas_assert (fixP->fx_r_type != BFD_RELOC_64);
+#endif
+
       switch (fixP->fx_r_type)
        {
        default:
@@ -3937,6 +4111,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,13 +4169,19 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       buf[highbyte] |= (val >> 8) & 0xf;
       break;
 
+#ifndef HAVE_SH64
+    case BFD_RELOC_64:
+      apply_full_field_fix (fixP, buf, *valP, 8);
+      break;
+#endif
+
     case BFD_RELOC_32:
     case BFD_RELOC_32_PCREL:
-      md_number_to_chars (buf, val, 4);
+      apply_full_field_fix (fixP, buf, val, 4);
       break;
 
     case BFD_RELOC_16:
-      md_number_to_chars (buf, val, 2);
+      apply_full_field_fix (fixP, buf, val, 2);
       break;
 
     case BFD_RELOC_SH_USES:
@@ -4016,8 +4213,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       val = fixP->fx_offset;
       if (fixP->fx_subsy)
        val -= S_GET_VALUE (fixP->fx_subsy);
-      fixP->fx_addnumber = val;
-      md_number_to_chars (buf, val, 4);
+      apply_full_field_fix (fixP, buf, val, 4);
       break;
 
     case BFD_RELOC_SH_GOTPC:
@@ -4038,7 +4234,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
          was used to store the correction, but since the expression is
          not pcrel, I felt it would be confusing to do it this way.  */
       * valP -= 1;
-      md_number_to_chars (buf, val, 4);
+      apply_full_field_fix (fixP, buf, val, 4);
       break;
 
     case BFD_RELOC_SH_TLS_GD_32:
@@ -4047,9 +4243,15 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       S_SET_THREAD_LOCAL (fixP->fx_addsy);
       /* Fallthrough */
     case BFD_RELOC_32_GOT_PCREL:
+    case BFD_RELOC_SH_GOT20:
     case BFD_RELOC_SH_GOTPLT32:
+    case BFD_RELOC_SH_GOTFUNCDESC:
+    case BFD_RELOC_SH_GOTFUNCDESC20:
+    case BFD_RELOC_SH_GOTOFFFUNCDESC:
+    case BFD_RELOC_SH_GOTOFFFUNCDESC20:
+    case BFD_RELOC_SH_FUNCDESC:
       * valP = 0; /* Fully resolved at runtime.  No addend.  */
-      md_number_to_chars (buf, 0, 4);
+      apply_full_field_fix (fixP, buf, 0, 4);
       break;
 
     case BFD_RELOC_SH_TLS_LDO_32:
@@ -4057,7 +4259,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       S_SET_THREAD_LOCAL (fixP->fx_addsy);
       /* Fallthrough */
     case BFD_RELOC_32_GOTOFF:
-      md_number_to_chars (buf, val, 4);
+    case BFD_RELOC_SH_GOTOFF20:
+      apply_full_field_fix (fixP, buf, val, 4);
       break;
 #endif
 
@@ -4080,8 +4283,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;
@@ -4255,12 +4466,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);
 
@@ -4271,7 +4478,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)
@@ -4360,6 +4567,14 @@ sh_parse_name (char const *name,
     reloc_type = BFD_RELOC_SH_TLS_LE_32;
   else if ((next_end = sh_end_of_match (next + 1, "DTPOFF")))
     reloc_type = BFD_RELOC_SH_TLS_LDO_32;
+  else if ((next_end = sh_end_of_match (next + 1, "PCREL")))
+    reloc_type = BFD_RELOC_32_PCREL;
+  else if ((next_end = sh_end_of_match (next + 1, "GOTFUNCDESC")))
+    reloc_type = BFD_RELOC_SH_GOTFUNCDESC;
+  else if ((next_end = sh_end_of_match (next + 1, "GOTOFFFUNCDESC")))
+    reloc_type = BFD_RELOC_SH_GOTOFFFUNCDESC;
+  else if ((next_end = sh_end_of_match (next + 1, "FUNCDESC")))
+    reloc_type = BFD_RELOC_SH_FUNCDESC;
   else
     goto no_suffix;
 
@@ -4382,7 +4597,7 @@ sh_cfi_frame_initial_instructions (void)
 }
 
 int
-sh_regname_to_dw2regnum (const char *regname)
+sh_regname_to_dw2regnum (char *regname)
 {
   unsigned int regnum = -1;
   unsigned int i;
This page took 0.044727 seconds and 4 git commands to generate.