tc-xgate.c: Replace R_XGATE_PCREL_X with BFD_RELOC_XGATE_PCREL_X
[deliverable/binutils-gdb.git] / gas / config / tc-ft32.c
index 505d12667fa4da50617ea3542bf444cb96e64199..9ef548edc00ba3515cc5633577172456ebbe47b6 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-ft32.c -- Assemble code for ft32
-   Copyright (C) 2008-2016 Free Software Foundation, Inc.
+   Copyright (C) 2008-2020 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -26,6 +26,9 @@
 
 extern const ft32_opc_info_t ft32_opc_info[128];
 
+/* See md_parse_option() for meanings of these options.  */
+static char norelax;                   /* True if -norelax switch seen.  */
+
 const char comment_chars[]        = "#";
 const char line_separator_chars[] = ";";
 const char line_comment_chars[]   = "#";
@@ -58,6 +61,8 @@ md_begin (void)
     hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
 
   bfd_set_arch_mach (stdoutput, TARGET_ARCH, 0);
+  if (!norelax)
+    linkrelax = 1;
 }
 
 /* Parse an expression and then restore the input line pointer.  */
@@ -78,10 +83,13 @@ static int
 parse_condition (char **ptr)
 {
   char *s = *ptr;
-  static const struct {
+  static const struct
+  {
     const char *name;
     int bits;
-  } ccs[] = {
+  }
+  ccs[] =
+  {
     { "gt,"   , (2 << FT32_FLD_CR_BIT) | (5 << FT32_FLD_CB_BIT) | (1 << FT32_FLD_CV_BIT)},
     { "gte,"  , (2 << FT32_FLD_CR_BIT) | (4 << FT32_FLD_CB_BIT) | (1 << FT32_FLD_CV_BIT)},
     { "lt,"   , (2 << FT32_FLD_CR_BIT) | (4 << FT32_FLD_CB_BIT) | (0 << FT32_FLD_CV_BIT)},
@@ -191,18 +199,17 @@ md_assemble (char *str)
 {
   char *op_start;
   char *op_end;
-
   ft32_opc_info_t *opcode;
   char *output;
   int idx = 0;
   char pend;
-
   int nlen = 0;
-
   unsigned int b;
   int f;
-
   expressionS arg;
+  bfd_boolean fixed = FALSE;
+  unsigned int sc;
+  bfd_boolean can_sc;
 
   /* Drop leading whitespace.  */
   while (*str == ' ')
@@ -211,7 +218,10 @@ md_assemble (char *str)
   /* Find the op code end.  */
   op_start = str;
   for (op_end = str;
-       *op_end && !is_end_of_line[*op_end & 0xff] && *op_end != ' ' && *op_end != '.';
+       *op_end
+       && !is_end_of_line[*op_end & 0xff]
+       && *op_end != ' '
+       && *op_end != '.';
        op_end++)
     nlen++;
 
@@ -236,6 +246,7 @@ md_assemble (char *str)
   if (opcode->dw)
     {
       int dw;
+
       if (*op_end == '.')
         {
           switch (op_end[1])
@@ -270,104 +281,115 @@ md_assemble (char *str)
   while (f)
     {
       int lobit = f & -f;
+
       if (f & lobit)
         {
           switch (lobit)
-          {
-          case  FT32_FLD_CBCRCV:
-            b |= parse_condition( &op_end);
-            break;
-          case  FT32_FLD_CB:
-            b |= parse_decimal (&op_end) << FT32_FLD_CB_BIT;
-            break;
-          case  FT32_FLD_R_D:
-            b |= parse_register_operand (&op_end) << FT32_FLD_R_D_BIT;
-            break;
-          case  FT32_FLD_CR:
-            b |= (parse_register_operand (&op_end) - 28) << FT32_FLD_CR_BIT;
-            break;
-          case  FT32_FLD_CV:
-            b |= parse_decimal (&op_end) << FT32_FLD_CV_BIT;
-            break;
-          case  FT32_FLD_R_1:
-            b |= parse_register_operand (&op_end) << FT32_FLD_R_1_BIT;
-            break;
-          case  FT32_FLD_RIMM:
-            if (*op_end == '$')
-              {
-                b |= parse_register_operand (&op_end) << FT32_FLD_RIMM_BIT;
-              }
-            else
-              {
-                b |= 0x400 << FT32_FLD_RIMM_BIT;
-                op_end = parse_exp_save_ilp (op_end, &arg);
-                fix_new_exp (frag_now,
-                             (output - frag_now->fr_literal),
-                             2,
-                             &arg,
-                             0,
-                             BFD_RELOC_FT32_10);
-              }
-            break;
-          case  FT32_FLD_R_2:
-            b |= parse_register_operand (&op_end) << FT32_FLD_R_2_BIT;
-            break;
-          case  FT32_FLD_K20:
-            op_end = parse_exp_save_ilp (op_end, &arg);
-            fix_new_exp (frag_now,
-                         (output - frag_now->fr_literal),
-                         3,
-                         &arg,
-                         0,
-                         BFD_RELOC_FT32_20);
-            break;
-          case  FT32_FLD_PA:
-            op_end = parse_exp_save_ilp (op_end, &arg);
-            fix_new_exp (frag_now,
-                         (output - frag_now->fr_literal),
-                         3,
-                         &arg,
-                         0,
-                         BFD_RELOC_FT32_18);
-            break;
-          case  FT32_FLD_AA:
-            op_end = parse_exp_save_ilp (op_end, &arg);
-            fix_new_exp (frag_now,
-                         (output - frag_now->fr_literal),
-                         3,
-                         &arg,
-                         0,
-                         BFD_RELOC_FT32_17);
-            break;
-          case  FT32_FLD_K16:
-            op_end = parse_exp_save_ilp (op_end, &arg);
-            fix_new_exp (frag_now,
-                         (output - frag_now->fr_literal),
-                         2,
-                         &arg,
-                         0,
-                         BFD_RELOC_16);
-            break;
-          case  FT32_FLD_K8:
-            op_end = parse_exp_save_ilp (op_end, &arg);
-            fix_new_exp (frag_now,
-                         (output - frag_now->fr_literal),
-                         1,
-                         &arg,
-                         0,
-                         BFD_RELOC_8);
-            break;
-          case  FT32_FLD_R_D_POST:
-            b |= parse_register_operand (&op_end) << FT32_FLD_R_D_BIT;
-            break;
-          case  FT32_FLD_R_1_POST:
-            b |= parse_register_operand (&op_end) << FT32_FLD_R_1_BIT;
-            break;
-          default:
-            as_bad (_("internal error in argument parsing"));
-            break;
-          }
+           {
+           case  FT32_FLD_CBCRCV:
+             b |= parse_condition( &op_end);
+             break;
+           case  FT32_FLD_CB:
+             b |= parse_decimal (&op_end) << FT32_FLD_CB_BIT;
+             break;
+           case  FT32_FLD_R_D:
+             b |= parse_register_operand (&op_end) << FT32_FLD_R_D_BIT;
+             break;
+           case  FT32_FLD_CR:
+             b |= (parse_register_operand (&op_end) - 28) << FT32_FLD_CR_BIT;
+             break;
+           case  FT32_FLD_CV:
+             b |= parse_decimal (&op_end) << FT32_FLD_CV_BIT;
+             break;
+           case  FT32_FLD_R_1:
+             b |= parse_register_operand (&op_end) << FT32_FLD_R_1_BIT;
+             break;
+           case  FT32_FLD_RIMM:
+             if (*op_end == '$')
+               {
+                 b |= parse_register_operand (&op_end) << FT32_FLD_RIMM_BIT;
+               }
+             else
+               {
+                 b |= 0x400 << FT32_FLD_RIMM_BIT;
+                 op_end = parse_exp_save_ilp (op_end, &arg);
+                 fixed = TRUE;
+                 fix_new_exp (frag_now,
+                              (output - frag_now->fr_literal),
+                              2,
+                              &arg,
+                              0,
+                              BFD_RELOC_FT32_10);
+               }
+             break;
+           case  FT32_FLD_R_2:
+             b |= parse_register_operand (&op_end) << FT32_FLD_R_2_BIT;
+             break;
+           case  FT32_FLD_K20:
+             op_end = parse_exp_save_ilp (op_end, &arg);
+             fixed = TRUE;
+             fix_new_exp (frag_now,
+                          (output - frag_now->fr_literal),
+                          3,
+                          &arg,
+                          0,
+                          BFD_RELOC_FT32_20);
+             break;
+           case  FT32_FLD_PA:
+             op_end = parse_exp_save_ilp (op_end, &arg);
+             fixed = TRUE;
+             fix_new_exp (frag_now,
+                          (output - frag_now->fr_literal),
+                          3,
+                          &arg,
+                          0,
+                          BFD_RELOC_FT32_18);
+             break;
+           case  FT32_FLD_AA:
+             op_end = parse_exp_save_ilp (op_end, &arg);
+             fixed = TRUE;
+             fix_new_exp (frag_now,
+                          (output - frag_now->fr_literal),
+                          3,
+                          &arg,
+                          0,
+                          BFD_RELOC_FT32_17);
+             break;
+           case  FT32_FLD_K16:
+             op_end = parse_exp_save_ilp (op_end, &arg);
+             fixed = TRUE;
+             fix_new_exp (frag_now,
+                          (output - frag_now->fr_literal),
+                          2,
+                          &arg,
+                          0,
+                          BFD_RELOC_16);
+             break;
+           case  FT32_FLD_K15:
+             op_end = parse_exp_save_ilp (op_end, &arg);
+             if (arg.X_add_number & 0x80)
+               arg.X_add_number ^= 0x7f00;
+             fixed = TRUE;
+             fix_new_exp (frag_now,
+                          (output - frag_now->fr_literal),
+                          2,
+                          &arg,
+                          0,
+                          BFD_RELOC_FT32_15);
+             break;
+           case  FT32_FLD_R_D_POST:
+             b |= parse_register_operand (&op_end) << FT32_FLD_R_D_BIT;
+             break;
+           case  FT32_FLD_R_1_POST:
+             b |= parse_register_operand (&op_end) << FT32_FLD_R_1_BIT;
+             break;
+           default:
+             as_bad (_("internal error in argument parsing"));
+             break;
+           }
+
           f &= ~lobit;
+
           if (f)
             {
               while (ISSPACE (*op_end))
@@ -385,14 +407,33 @@ md_assemble (char *str)
             }
         }
     }
+
   if (*op_end != 0)
     as_warn (_("extra stuff on line ignored"));
 
+  can_sc = ft32_shortcode (b, &sc);
+
+  if (!fixed && can_sc)
+    {
+      arg.X_op = O_constant;
+      arg.X_add_number = 0;
+      arg.X_add_symbol = NULL;
+      arg.X_op_symbol = NULL;
+      fix_new_exp (frag_now,
+                   (output - frag_now->fr_literal),
+                   2,
+                   &arg,
+                   0,
+                   BFD_RELOC_FT32_RELAX);
+    }
+
   output[idx++] = 0xff & (b >> 0);
   output[idx++] = 0xff & (b >> 8);
   output[idx++] = 0xff & (b >> 16);
   output[idx++] = 0xff & (b >> 24);
 
+  dwarf2_emit_insn (4);
+
   while (ISSPACE (*op_end))
     op_end++;
 
@@ -450,6 +491,9 @@ const char *md_shortopts = "";
 
 struct option md_longopts[] =
 {
+#define OPTION_NORELAX (OPTION_MD_BASE)
+  {"norelax", no_argument, NULL, OPTION_NORELAX},
+  {"no-relax", no_argument, NULL, OPTION_NORELAX},
   {NULL, no_argument, NULL, 0}
 };
 size_t md_longopts_size = sizeof (md_longopts);
@@ -459,12 +503,26 @@ size_t md_longopts_size = sizeof (md_longopts);
 int
 md_parse_option (int c ATTRIBUTE_UNUSED, const char *arg ATTRIBUTE_UNUSED)
 {
-  return 0;
+  switch (c)
+    {
+    case OPTION_NORELAX:
+      norelax = 1;
+      break;
+
+    default:
+      return 0;
+    }
+
+  return 1;
 }
 
 void
 md_show_usage (FILE *stream ATTRIBUTE_UNUSED)
 {
+  fprintf (stream, _("FT32 options:\n"));
+  fprintf (stream, _("\n\
+-no-relax              don't relax relocations\n\
+                       \n"));
 }
 
 /* Convert from target byte order to host byte order.  */
@@ -483,6 +541,7 @@ md_chars_to_number (char * buf, int n)
 
   return result;
 }
+
 /* Apply a fixup to the object file.  */
 
 void
@@ -493,8 +552,43 @@ md_apply_fix (fixS *fixP ATTRIBUTE_UNUSED,
   long val = *valP;
   long newval;
 
+  if (linkrelax && fixP->fx_subsy)
+    {
+      /* For a subtraction relocation expression, generate one
+         of the DIFF relocs, with the value being the difference.
+         Note that a sym1 - sym2 expression is adjusted into a
+         section_start_sym + sym4_offset_from_section_start - sym1
+         expression. fixP->fx_addsy holds the section start symbol,
+         fixP->fx_offset holds sym2's offset, and fixP->fx_subsy
+         holds sym1. Calculate the current difference and write value,
+         but leave fx_offset as is - during relaxation,
+         fx_offset - value gives sym1's value.  */
+
+       switch (fixP->fx_r_type)
+         {
+           case BFD_RELOC_32:
+             fixP->fx_r_type = BFD_RELOC_FT32_DIFF32;
+             break;
+           default:
+             as_bad_where (fixP->fx_file, fixP->fx_line,
+                           _("expression too complex"));
+             break;
+         }
+
+      val = S_GET_VALUE (fixP->fx_addsy) +
+          fixP->fx_offset - S_GET_VALUE (fixP->fx_subsy);
+      *valP = val;
+
+      fixP->fx_subsy = NULL;
+  }
+
+  /* We don't actually support subtracting a symbol.  */
+  if (fixP->fx_subsy != (symbolS *) NULL)
+    as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
+
   switch (fixP->fx_r_type)
     {
+    case BFD_RELOC_FT32_DIFF32:
     case BFD_RELOC_32:
       buf[3] = val >> 24;
       buf[2] = val >> 16;
@@ -527,6 +621,14 @@ md_apply_fix (fixS *fixP ATTRIBUTE_UNUSED,
       md_number_to_chars (buf, newval, 3);
       break;
 
+    case BFD_RELOC_FT32_15:
+      if (!val)
+       break;
+      newval = md_chars_to_number (buf, 2);
+      newval |= val & ((1 << 15) - 1);
+      md_number_to_chars (buf, newval, 2);
+      break;
+
     case BFD_RELOC_FT32_17:
       if (!val)
        break;
@@ -543,13 +645,15 @@ md_apply_fix (fixS *fixP ATTRIBUTE_UNUSED,
       md_number_to_chars (buf, newval, 4);
       break;
 
+    case BFD_RELOC_FT32_RELAX:
+      break;
+
     default:
       abort ();
     }
 
   if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
     fixP->fx_done = 1;
-  // printf("fx_addsy=%p fixP->fx_pcrel=%d fx_done=%d\n", fixP->fx_addsy, fixP->fx_pcrel, fixP->fx_done);
 }
 
 void
@@ -559,6 +663,7 @@ md_number_to_chars (char *ptr, valueT use, int nbytes)
 }
 
 /* Generate a machine-dependent relocation.  */
+
 arelent *
 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
 {
@@ -572,14 +677,18 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
     case BFD_RELOC_8:
     case BFD_RELOC_FT32_10:
     case BFD_RELOC_FT32_20:
+    case BFD_RELOC_FT32_15:
     case BFD_RELOC_FT32_17:
     case BFD_RELOC_FT32_18:
+    case BFD_RELOC_FT32_RELAX:
+    case BFD_RELOC_FT32_DIFF32:
       code = fixP->fx_r_type;
       break;
     default:
       as_bad_where (fixP->fx_file, fixP->fx_line,
-                   _("Semantics error.  This type of operand can not be relocated, it must be an assembly-time constant"));
-      return 0;
+                   _("Semantics error.  This type of operand can not be "
+                      "relocated, it must be an assembly-time constant"));
+      return NULL;
     }
 
   relP = XNEW (arelent);
@@ -604,3 +713,80 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
 
   return relP;
 }
+
+/* TC_FORCE_RELOCATION hook */
+
+static bfd_boolean
+relaxable_section (asection *sec)
+{
+  return ((sec->flags & SEC_DEBUGGING) == 0
+          && (sec->flags & SEC_CODE) != 0
+          && (sec->flags & SEC_ALLOC) != 0);
+}
+
+/* Does whatever the xtensa port does.  */
+
+int
+ft32_validate_fix_sub (fixS *fix)
+{
+  segT add_symbol_segment, sub_symbol_segment;
+
+  /* The difference of two symbols should be resolved by the assembler when
+     linkrelax is not set.  If the linker may relax the section containing
+     the symbols, then an Xtensa DIFF relocation must be generated so that
+     the linker knows to adjust the difference value.  */
+  if (!linkrelax || fix->fx_addsy == NULL)
+    return 0;
+
+  /* Make sure both symbols are in the same segment, and that segment is
+     "normal" and relaxable.  If the segment is not "normal", then the
+     fix is not valid.  If the segment is not "relaxable", then the fix
+     should have been handled earlier.  */
+  add_symbol_segment = S_GET_SEGMENT (fix->fx_addsy);
+  if (! SEG_NORMAL (add_symbol_segment) ||
+      ! relaxable_section (add_symbol_segment))
+    return 0;
+
+  sub_symbol_segment = S_GET_SEGMENT (fix->fx_subsy);
+  return (sub_symbol_segment == add_symbol_segment);
+}
+
+/* TC_FORCE_RELOCATION hook */
+
+/* If linkrelax is turned on, and the symbol to relocate
+   against is in a relaxable segment, don't compute the value -
+   generate a relocation instead.  */
+
+int
+ft32_force_relocation (fixS *fix)
+{
+  if (linkrelax && fix->fx_addsy
+      && relaxable_section (S_GET_SEGMENT (fix->fx_addsy)))
+    {
+      return 1;
+    }
+
+  return generic_force_reloc (fix);
+}
+
+bfd_boolean
+ft32_allow_local_subtract (expressionS * left,
+                          expressionS * right,
+                          segT section)
+{
+  /* If we are not in relaxation mode, subtraction is OK.  */
+  if (!linkrelax)
+    return TRUE;
+
+  /* If the symbols are not in a code section then they are OK.  */
+  if ((section->flags & SEC_CODE) == 0)
+    return TRUE;
+
+  if (left->X_add_symbol == right->X_add_symbol)
+    return TRUE;
+
+  /* We have to assume that there may be instructions between the
+     two symbols and that relaxation may increase the distance between
+     them.  */
+  return FALSE;
+}
This page took 0.029251 seconds and 4 git commands to generate.