Update year range in copyright notice of binutils files
[deliverable/binutils-gdb.git] / gas / config / tc-riscv.c
index 6bbaa4b101051a33f96eb966a966bb5f57578d24..f60bea15c89dd7adae9a00bce3f73ed387d0daa3 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-riscv.c -- RISC-V assembler
-   Copyright (C) 2011-2017 Free Software Foundation, Inc.
+   Copyright (C) 2011-2018 Free Software Foundation, Inc.
 
    Contributed by Andrew Waterman (andrew@sifive.com).
    Based on MIPS target.
@@ -120,6 +120,18 @@ riscv_subset_supports (const char *feature)
   return FALSE;
 }
 
+static void
+riscv_clear_subsets (void)
+{
+  while (riscv_subsets != NULL)
+    {
+      struct riscv_subset *next = riscv_subsets->next;
+      free ((void *) riscv_subsets->name);
+      free (riscv_subsets);
+      riscv_subsets = next;
+    }
+}
+
 static void
 riscv_add_subset (const char *subset)
 {
@@ -135,10 +147,12 @@ riscv_add_subset (const char *subset)
 static void
 riscv_set_arch (const char *s)
 {
-  const char *all_subsets = "imafdc";
-  const char *extension = NULL;
+  const char *all_subsets = "imafdqc";
+  char *extension = NULL;
   const char *p = s;
 
+  riscv_clear_subsets();
+
   if (strncmp (p, "rv32", 4) == 0)
     {
       xlen = 32;
@@ -159,7 +173,7 @@ riscv_set_arch (const char *s)
 
       case 'g':
        p++;
-       for ( ; *all_subsets != 'c'; all_subsets++)
+       for ( ; *all_subsets != 'q'; all_subsets++)
          {
            const char subset[] = {*all_subsets, '\0'};
            riscv_add_subset (subset);
@@ -174,7 +188,8 @@ riscv_set_arch (const char *s)
     {
       if (*p == 'x')
        {
-         char *subset = xstrdup (p), *q = subset;
+         char *subset = xstrdup (p);
+         char *q = subset;
 
          while (*++q != '\0' && *q != '_')
            ;
@@ -186,7 +201,6 @@ riscv_set_arch (const char *s)
          extension = subset;
          riscv_add_subset (subset);
          p += strlen (subset);
-         free (subset);
        }
       else if (*p == '_')
        p++;
@@ -197,15 +211,11 @@ riscv_set_arch (const char *s)
          all_subsets++;
          p++;
        }
-      else if (*p == 'q')
-       {
-         const char subset[] = {*p, 0};
-         riscv_add_subset (subset);
-         p++;
-       }
       else
        as_fatal ("-march=%s: unsupported ISA subset `%c'", s, *p);
     }
+
+  free (extension);
 }
 
 /* Handle of the OPCODE hash table.  */
@@ -506,6 +516,7 @@ validate_riscv_insn (const struct riscv_opcode *opc)
          case 'c': break; /* RS1, constrained to equal sp */
          case 'i': used_bits |= ENCODE_RVC_SIMM3(-1U); break;
          case 'j': used_bits |= ENCODE_RVC_IMM (-1U); break;
+         case 'o': used_bits |= ENCODE_RVC_IMM (-1U); break;
          case 'k': used_bits |= ENCODE_RVC_LW_IMM (-1U); break;
          case 'l': used_bits |= ENCODE_RVC_LD_IMM (-1U); break;
          case 'm': used_bits |= ENCODE_RVC_LWSP_IMM (-1U); break;
@@ -632,6 +643,7 @@ md_begin (void)
   hash_reg_names (RCLASS_FPR, riscv_fpr_names_abi, NFPR);
 
 #define DECLARE_CSR(name, num) hash_reg_name (RCLASS_CSR, #name, num);
+#define DECLARE_CSR_ALIAS(name, num) DECLARE_CSR(name, num);
 #include "opcode/riscv-opc.h"
 #undef DECLARE_CSR
 
@@ -704,6 +716,21 @@ append_insn (struct riscv_cl_insn *ip, expressionS *address_expr,
 
   add_fixed_insn (ip);
   install_insn (ip);
+
+  /* We need to start a new frag after any instruction that can be
+     optimized away or compressed by the linker during relaxation, to prevent
+     the assembler from computing static offsets across such an instruction.
+     This is necessary to get correct EH info.  */
+  if (reloc_type == BFD_RELOC_RISCV_CALL
+      || reloc_type == BFD_RELOC_RISCV_CALL_PLT
+      || reloc_type == BFD_RELOC_RISCV_HI20
+      || reloc_type == BFD_RELOC_RISCV_PCREL_HI20
+      || reloc_type == BFD_RELOC_RISCV_TPREL_HI20
+      || reloc_type == BFD_RELOC_RISCV_TPREL_ADD)
+    {
+      frag_wane (frag_now);
+      frag_new (0);
+    }
 }
 
 /* Build an instruction created by a macro expansion.  This is passed
@@ -1158,6 +1185,25 @@ my_getSmallExpression (expressionS *ep, bfd_reloc_code_real_type *reloc,
   return reloc_index;
 }
 
+/* Detect and handle implicitly zero load-store offsets.  For example,
+   "lw t0, (t1)" is shorthand for "lw t0, 0(t1)".  Return TRUE iff such
+   an implicit offset was detected.  */
+
+static bfd_boolean
+riscv_handle_implicit_zero_offset (expressionS *expr, const char *s)
+{
+  /* Check whether there is only a single bracketed expression left.
+     If so, it must be the base register and the constant must be zero.  */
+  if (*s == '(' && strchr (s + 1, '(') == 0)
+    {
+      expr->X_op = O_constant;
+      expr->X_add_number = 0;
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
 /* This routine assembles an instruction into its binary format.  As a
    side effect, it sets the global variable imm_reloc to the type of
    relocation to do if one of the operands is an address expression.  */
@@ -1298,6 +1344,8 @@ rvc_imm_done:
                  ip->insn_opcode |= ENCODE_RVC_IMM (imm_expr->X_add_number);
                  goto rvc_imm_done;
                case 'k':
+                 if (riscv_handle_implicit_zero_offset (imm_expr, s))
+                   continue;
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
                      || !VALID_RVC_LW_IMM (imm_expr->X_add_number))
@@ -1305,6 +1353,8 @@ rvc_imm_done:
                  ip->insn_opcode |= ENCODE_RVC_LW_IMM (imm_expr->X_add_number);
                  goto rvc_imm_done;
                case 'l':
+                 if (riscv_handle_implicit_zero_offset (imm_expr, s))
+                   continue;
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
                      || !VALID_RVC_LD_IMM (imm_expr->X_add_number))
@@ -1312,6 +1362,8 @@ rvc_imm_done:
                  ip->insn_opcode |= ENCODE_RVC_LD_IMM (imm_expr->X_add_number);
                  goto rvc_imm_done;
                case 'm':
+                 if (riscv_handle_implicit_zero_offset (imm_expr, s))
+                   continue;
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
                      || !VALID_RVC_LWSP_IMM (imm_expr->X_add_number))
@@ -1320,6 +1372,8 @@ rvc_imm_done:
                    ENCODE_RVC_LWSP_IMM (imm_expr->X_add_number);
                  goto rvc_imm_done;
                case 'n':
+                 if (riscv_handle_implicit_zero_offset (imm_expr, s))
+                   continue;
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
                      || !VALID_RVC_LDSP_IMM (imm_expr->X_add_number))
@@ -1327,6 +1381,16 @@ rvc_imm_done:
                  ip->insn_opcode |=
                    ENCODE_RVC_LDSP_IMM (imm_expr->X_add_number);
                  goto rvc_imm_done;
+               case 'o':
+                 if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
+                     || imm_expr->X_op != O_constant
+                     /* C.addiw, c.li, and c.andi allow zero immediate.
+                        C.addi allows zero immediate as hint.  Otherwise this
+                        is same as 'j'.  */
+                     || !VALID_RVC_IMM (imm_expr->X_add_number))
+                   break;
+                 ip->insn_opcode |= ENCODE_RVC_IMM (imm_expr->X_add_number);
+                 goto rvc_imm_done;
                case 'K':
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
@@ -1346,6 +1410,8 @@ rvc_imm_done:
                    ENCODE_RVC_ADDI16SP_IMM (imm_expr->X_add_number);
                  goto rvc_imm_done;
                case 'M':
+                 if (riscv_handle_implicit_zero_offset (imm_expr, s))
+                   continue;
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
                      || !VALID_RVC_SWSP_IMM (imm_expr->X_add_number))
@@ -1354,6 +1420,8 @@ rvc_imm_done:
                    ENCODE_RVC_SWSP_IMM (imm_expr->X_add_number);
                  goto rvc_imm_done;
                case 'N':
+                 if (riscv_handle_implicit_zero_offset (imm_expr, s))
+                   continue;
                  if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
                      || imm_expr->X_op != O_constant
                      || !VALID_RVC_SDSP_IMM (imm_expr->X_add_number))
@@ -1423,8 +1491,8 @@ rvc_lui:
              my_getExpression (imm_expr, s);
              check_absolute_expr (ip, imm_expr);
              if ((unsigned long) imm_expr->X_add_number > 31)
-               as_warn (_("Improper shift amount (%lu)"),
-                        (unsigned long) imm_expr->X_add_number);
+               as_bad (_("Improper shift amount (%lu)"),
+                       (unsigned long) imm_expr->X_add_number);
              INSERT_OPERAND (SHAMTW, *ip, imm_expr->X_add_number);
              imm_expr->X_op = O_absent;
              s = expr_end;
@@ -1434,8 +1502,8 @@ rvc_lui:
              my_getExpression (imm_expr, s);
              check_absolute_expr (ip, imm_expr);
              if ((unsigned long) imm_expr->X_add_number >= xlen)
-               as_warn (_("Improper shift amount (%lu)"),
-                        (unsigned long) imm_expr->X_add_number);
+               as_bad (_("Improper shift amount (%lu)"),
+                       (unsigned long) imm_expr->X_add_number);
              INSERT_OPERAND (SHAMT, *ip, imm_expr->X_add_number);
              imm_expr->X_op = O_absent;
              s = expr_end;
@@ -1445,8 +1513,8 @@ rvc_lui:
              my_getExpression (imm_expr, s);
              check_absolute_expr (ip, imm_expr);
              if ((unsigned long) imm_expr->X_add_number > 31)
-               as_warn (_("Improper CSRxI immediate (%lu)"),
-                        (unsigned long) imm_expr->X_add_number);
+               as_bad (_("Improper CSRxI immediate (%lu)"),
+                       (unsigned long) imm_expr->X_add_number);
              INSERT_OPERAND (RS1, *ip, imm_expr->X_add_number);
              imm_expr->X_op = O_absent;
              s = expr_end;
@@ -1460,8 +1528,8 @@ rvc_lui:
                  my_getExpression (imm_expr, s);
                  check_absolute_expr (ip, imm_expr);
                  if ((unsigned long) imm_expr->X_add_number > 0xfff)
-                   as_warn (_("Improper CSR address (%lu)"),
-                            (unsigned long) imm_expr->X_add_number);
+                   as_bad (_("Improper CSR address (%lu)"),
+                           (unsigned long) imm_expr->X_add_number);
                  INSERT_OPERAND (CSR, *ip, imm_expr->X_add_number);
                  imm_expr->X_op = O_absent;
                  s = expr_end;
@@ -1584,12 +1652,7 @@ rvc_lui:
              p = percent_op_rtype;
              *imm_reloc = BFD_RELOC_UNUSED;
 load_store:
-             /* Check whether there is only a single bracketed expression
-                left.  If so, it must be the base register and the
-                constant must be zero.  */
-             imm_expr->X_op = O_constant;
-             imm_expr->X_add_number = 0;
-             if (*s == '(' && strchr (s + 1, '(') == 0)
+             if (riscv_handle_implicit_zero_offset (imm_expr, s))
                continue;
 alu_op:
              /* If this value won't fit into a 16 bit offset, then go
@@ -1800,6 +1863,7 @@ riscv_after_parse_args (void)
     riscv_set_arch (xlen == 64 ? "rv64g" : "rv32g");
 
   /* Add the RVC extension, regardless of -march, to support .option rvc.  */
+  riscv_set_rvc (FALSE);
   if (riscv_subset_supports ("c"))
     riscv_set_rvc (TRUE);
   else
@@ -1847,6 +1911,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
   unsigned int subtype;
   bfd_byte *buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where);
   bfd_boolean relaxable = FALSE;
+  offsetT loc;
+  segT sub_segment;
 
   /* Remember value for tc_gen_reloc.  */
   fixP->fx_addnumber = *valP;
@@ -1864,7 +1930,6 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       break;
 
     case BFD_RELOC_RISCV_GOT_HI20:
-    case BFD_RELOC_RISCV_PCREL_HI20:
     case BFD_RELOC_RISCV_ADD8:
     case BFD_RELOC_RISCV_ADD16:
     case BFD_RELOC_RISCV_ADD32:
@@ -1895,8 +1960,25 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
                      _("TLS relocation against a constant"));
       break;
 
-    case BFD_RELOC_64:
     case BFD_RELOC_32:
+      /* Use pc-relative relocation for FDE initial location.
+        The symbol address in .eh_frame may be adjusted in
+        _bfd_elf_discard_section_eh_frame, and the content of
+        .eh_frame will be adjusted in _bfd_elf_write_section_eh_frame.
+        Therefore, we cannot insert a relocation whose addend symbol is
+        in .eh_frame. Othrewise, the value may be adjusted twice.*/
+      if (fixP->fx_addsy && fixP->fx_subsy
+         && (sub_segment = S_GET_SEGMENT (fixP->fx_subsy))
+         && strcmp (sub_segment->name, ".eh_frame") == 0
+         && S_GET_VALUE (fixP->fx_subsy)
+            == fixP->fx_frag->fr_address + fixP->fx_where)
+       {
+         fixP->fx_r_type = BFD_RELOC_RISCV_32_PCREL;
+         fixP->fx_subsy = NULL;
+         break;
+       }
+      /* Fall through.  */
+    case BFD_RELOC_64:
     case BFD_RELOC_16:
     case BFD_RELOC_8:
     case BFD_RELOC_RISCV_CFA:
@@ -1932,30 +2014,31 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 
            case BFD_RELOC_RISCV_CFA:
              /* Load the byte to get the subtype.  */
-             subtype = bfd_get_8 (NULL, &fixP->fx_frag->fr_literal[fixP->fx_where]);
+             subtype = bfd_get_8 (NULL, &((fragS *) (fixP->fx_frag->fr_opcode))->fr_literal[fixP->fx_where]);
+             loc = fixP->fx_frag->fr_fix - (subtype & 7);
              switch (subtype)
                {
                case DW_CFA_advance_loc1:
-                 fixP->fx_where++;
-                 fixP->fx_next->fx_where++;
+                 fixP->fx_where = loc + 1;
+                 fixP->fx_next->fx_where = loc + 1;
                  fixP->fx_r_type = BFD_RELOC_RISCV_SET8;
                  fixP->fx_next->fx_r_type = BFD_RELOC_RISCV_SUB8;
                  break;
 
                case DW_CFA_advance_loc2:
                  fixP->fx_size = 2;
-                 fixP->fx_where++;
                  fixP->fx_next->fx_size = 2;
-                 fixP->fx_next->fx_where++;
+                 fixP->fx_where = loc + 1;
+                 fixP->fx_next->fx_where = loc + 1;
                  fixP->fx_r_type = BFD_RELOC_RISCV_SET16;
                  fixP->fx_next->fx_r_type = BFD_RELOC_RISCV_SUB16;
                  break;
 
                case DW_CFA_advance_loc4:
                  fixP->fx_size = 4;
-                 fixP->fx_where++;
                  fixP->fx_next->fx_size = 4;
-                 fixP->fx_next->fx_where++;
+                 fixP->fx_where = loc;
+                 fixP->fx_next->fx_where = loc;
                  fixP->fx_r_type = BFD_RELOC_RISCV_SET32;
                  fixP->fx_next->fx_r_type = BFD_RELOC_RISCV_SUB32;
                  break;
@@ -1964,6 +2047,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
                  if (subtype < 0x80 && (subtype & 0x40))
                    {
                      /* DW_CFA_advance_loc */
+                     fixP->fx_frag = (fragS *) fixP->fx_frag->fr_opcode;
+                     fixP->fx_next->fx_frag = fixP->fx_frag;
                      fixP->fx_r_type = BFD_RELOC_RISCV_SET6;
                      fixP->fx_next->fx_r_type = BFD_RELOC_RISCV_SUB6;
                    }
@@ -2037,8 +2122,12 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       relaxable = TRUE;
       break;
 
+    case BFD_RELOC_RISCV_PCREL_HI20:
     case BFD_RELOC_RISCV_PCREL_LO12_S:
     case BFD_RELOC_RISCV_PCREL_LO12_I:
+      relaxable = riscv_opts.relax;
+      break;
+
     case BFD_RELOC_RISCV_ALIGN:
       break;
 
@@ -2073,13 +2162,12 @@ riscv_pre_output_hook (void)
   for (s = stdoutput->sections; s; s = s->next)
     for (frch = seg_info (s)->frchainP; frch; frch = frch->frch_next)
       {
-       const fragS *frag;
+       fragS *frag;
 
        for (frag = frch->frch_root; frag; frag = frag->fr_next)
          {
            if (frag->fr_type == rs_cfa)
              {
-               fragS *loc4_frag;
                expressionS exp;
 
                symbolS *add_symbol = frag->fr_symbol->sy_value.X_add_symbol;
@@ -2090,8 +2178,7 @@ riscv_pre_output_hook (void)
                exp.X_add_number = 0;
                exp.X_op_symbol = op_symbol;
 
-               loc4_frag = (fragS *) frag->fr_opcode;
-               fix_new_exp (loc4_frag, (int) frag->fr_offset, 1, &exp, 0,
+               fix_new_exp (frag, (int) frag->fr_offset, 1, &exp, 0,
                             BFD_RELOC_RISCV_CFA);
              }
          }
@@ -2235,30 +2322,29 @@ bfd_boolean
 riscv_frag_align_code (int n)
 {
   bfd_vma bytes = (bfd_vma) 1 << n;
-  bfd_vma min_text_alignment_order = riscv_opts.rvc ? 1 : 2;
-  bfd_vma min_text_alignment = (bfd_vma) 1 << min_text_alignment_order;
+  bfd_vma insn_alignment = riscv_opts.rvc ? 2 : 4;
+  bfd_vma worst_case_bytes = bytes - insn_alignment;
+  char *nops;
+  expressionS ex;
+
+  /* If we are moving to a smaller alignment than the instruction size, then no
+     alignment is required. */
+  if (bytes <= insn_alignment)
+    return TRUE;
 
-  /* First, get back to minimal alignment.  */
-  frag_align_code (min_text_alignment_order, 0);
+  nops = frag_more (worst_case_bytes);
 
   /* When not relaxing, riscv_handle_align handles code alignment.  */
   if (!riscv_opts.relax)
     return FALSE;
 
-  if (bytes > min_text_alignment)
-    {
-      bfd_vma worst_case_bytes = bytes - min_text_alignment;
-      char *nops = frag_more (worst_case_bytes);
-      expressionS ex;
-
-      ex.X_op = O_constant;
-      ex.X_add_number = worst_case_bytes;
+  ex.X_op = O_constant;
+  ex.X_add_number = worst_case_bytes;
 
-      riscv_make_nops (nops, worst_case_bytes);
+  riscv_make_nops (nops, worst_case_bytes);
 
-      fix_new_exp (frag_now, nops - frag_now->fr_literal, 0,
-                  &ex, FALSE, BFD_RELOC_RISCV_ALIGN);
-    }
+  fix_new_exp (frag_now, nops - frag_now->fr_literal, 0,
+              &ex, FALSE, BFD_RELOC_RISCV_ALIGN);
 
   return TRUE;
 }
@@ -2465,15 +2551,10 @@ md_show_usage (FILE *stream)
 {
   fprintf (stream, _("\
 RISC-V options:\n\
-  -m32           assemble RV32 code\n\
-  -m64           assemble RV64 code (default)\n\
   -fpic          generate position-independent code\n\
   -fno-pic       don't generate position-independent code (default)\n\
-  -msoft-float   don't use F registers for floating-point values\n\
-  -mhard-float   use F registers for floating-point values (default)\n\
-  -mno-rvc       disable the C extension for compressed instructions (default)\n\
-  -mrvc          enable the C extension for compressed instructions\n\
-  -march=ISA     set the RISC-V architecture, RV64IMAFD by default\n\
+  -march=ISA     set the RISC-V architecture\n\
+  -mabi=ABI      set the RISC-V ABI\n\
 "));
 }
 
This page took 0.031079 seconds and 4 git commands to generate.