Allow symbols in MEMORY region specification
[deliverable/binutils-gdb.git] / gas / config / tc-aarch64.c
index 7483f30fc1a68d7cc717e65c55c9f3a9017a8c93..b495331b941e73e68b7470c45f2778c0778348a2 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-aarch64.c -- Assemble for the AArch64 ISA
 
-   Copyright (C) 2009-2014 Free Software Foundation, Inc.
+   Copyright (C) 2009-2015 Free Software Foundation, Inc.
    Contributed by ARM Ltd.
 
    This file is part of GAS.
@@ -1917,6 +1917,7 @@ s_tlsdesccall (int ignored ATTRIBUTE_UNUSED)
 
 static void s_aarch64_arch (int);
 static void s_aarch64_cpu (int);
+static void s_aarch64_arch_extension (int);
 
 /* This table describes all the machine specific pseudo-ops the assembler
    has to support.  The fields are:
@@ -1934,6 +1935,7 @@ const pseudo_typeS md_pseudo_table[] = {
   {"pool", s_ltorg, 0},
   {"cpu", s_aarch64_cpu, 0},
   {"arch", s_aarch64_arch, 0},
+  {"arch_extension", s_aarch64_arch_extension, 0},
   {"inst", s_aarch64_inst, 0},
 #ifdef OBJ_ELF
   {"tlsdesccall", s_tlsdesccall, 0},
@@ -5488,6 +5490,47 @@ programmer_friendly_fixup (aarch64_instruction *instr)
   return TRUE;
 }
 
+/* Check for loads and stores that will cause unpredictable behavior.  */
+
+static void
+warn_unpredictable_ldst (aarch64_instruction *instr, char *str)
+{
+  aarch64_inst *base = &instr->base;
+  const aarch64_opcode *opcode = base->opcode;
+  const aarch64_opnd_info *opnds = base->operands;
+  switch (opcode->iclass)
+    {
+    case ldst_pos:
+    case ldst_imm9:
+    case ldst_unscaled:
+    case ldst_unpriv:
+      /* Loading/storing the base register is unpredictable if writeback.  */
+      if ((aarch64_get_operand_class (opnds[0].type)
+          == AARCH64_OPND_CLASS_INT_REG)
+         && opnds[0].reg.regno == opnds[1].addr.base_regno
+         && opnds[1].addr.writeback)
+       as_warn (_("unpredictable transfer with writeback -- `%s'"), str);
+      break;
+    case ldstpair_off:
+    case ldstnapair_offs:
+    case ldstpair_indexed:
+      /* Loading/storing the base register is unpredictable if writeback.  */
+      if ((aarch64_get_operand_class (opnds[0].type)
+          == AARCH64_OPND_CLASS_INT_REG)
+         && (opnds[0].reg.regno == opnds[2].addr.base_regno
+           || opnds[1].reg.regno == opnds[2].addr.base_regno)
+         && opnds[2].addr.writeback)
+           as_warn (_("unpredictable transfer with writeback -- `%s'"), str);
+      /* Load operations must load different registers.  */
+      if ((opcode->opcode & (1 << 22))
+         && opnds[0].reg.regno == opnds[1].reg.regno)
+           as_warn (_("unpredictable load of register pair -- `%s'"), str);
+      break;
+    default:
+      break;
+    }
+}
+
 /* A wrapper function to interface with libopcodes on encoding and
    record the error message if there is any.
 
@@ -5620,6 +5663,8 @@ md_assemble (char *str)
              return;
            }
 
+         warn_unpredictable_ldst (&inst, str);
+
          if (inst.reloc.type == BFD_RELOC_UNUSED
              || !inst.reloc.need_libopcodes_p)
            output_inst (NULL);
@@ -5825,7 +5870,24 @@ md_section_align (segT segment ATTRIBUTE_UNUSED, valueT size)
 }
 
 /* This is called from HANDLE_ALIGN in write.c.         Fill in the contents
-   of an rs_align_code fragment.  */
+   of an rs_align_code fragment.
+
+   Here we fill the frag with the appropriate info for padding the
+   output stream.  The resulting frag will consist of a fixed (fr_fix)
+   and of a repeating (fr_var) part.
+
+   The fixed content is always emitted before the repeating content and
+   these two parts are used as follows in constructing the output:
+   - the fixed part will be used to align to a valid instruction word
+     boundary, in case that we start at a misaligned address; as no
+     executable instruction can live at the misaligned location, we
+     simply fill with zeros;
+   - the variable part will be used to cover the remaining padding and
+     we fill using the AArch64 NOP instruction.
+
+   Note that the size of a RS_ALIGN_CODE fragment is always 7 to provide
+   enough storage space for up to 3 bytes for padding the back to a valid
+   instruction alignment and exactly 4 bytes to store the NOP pattern.  */
 
 void
 aarch64_handle_align (fragS * fragP)
@@ -5836,69 +5898,33 @@ aarch64_handle_align (fragS * fragP)
 
   int bytes, fix, noop_size;
   char *p;
-  const char *noop;
 
   if (fragP->fr_type != rs_align_code)
     return;
 
   bytes = fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix;
   p = fragP->fr_literal + fragP->fr_fix;
-  fix = 0;
-
-  if (bytes > MAX_MEM_FOR_RS_ALIGN_CODE)
-    bytes &= MAX_MEM_FOR_RS_ALIGN_CODE;
 
 #ifdef OBJ_ELF
   gas_assert (fragP->tc_frag_data.recorded);
 #endif
 
-  noop = aarch64_noop;
   noop_size = sizeof (aarch64_noop);
-  fragP->fr_var = noop_size;
 
-  if (bytes & (noop_size - 1))
+  fix = bytes & (noop_size - 1);
+  if (fix)
     {
-      fix = bytes & (noop_size - 1);
 #ifdef OBJ_ELF
       insert_data_mapping_symbol (MAP_INSN, fragP->fr_fix, fragP, fix);
 #endif
       memset (p, 0, fix);
       p += fix;
-      bytes -= fix;
-    }
-
-  while (bytes >= noop_size)
-    {
-      memcpy (p, noop, noop_size);
-      p += noop_size;
-      bytes -= noop_size;
-      fix += noop_size;
+      fragP->fr_fix += fix;
     }
 
-  fragP->fr_fix += fix;
-}
-
-/* Called from md_do_align.  Used to create an alignment
-   frag in a code section.  */
-
-void
-aarch64_frag_align_code (int n, int max)
-{
-  char *p;
-
-  /* We assume that there will never be a requirement
-     to support alignments greater than x bytes.  */
-  if (max > MAX_MEM_FOR_RS_ALIGN_CODE)
-    as_fatal (_
-             ("alignments greater than %d bytes not supported in .text sections"),
-             MAX_MEM_FOR_RS_ALIGN_CODE + 1);
-
-  p = frag_var (rs_align_code,
-               MAX_MEM_FOR_RS_ALIGN_CODE,
-               1,
-               (relax_substateT) max,
-               (symbolS *) NULL, (offsetT) n, (char *) NULL);
-  *p = 0;
+  if (noop_size)
+    memcpy (p, aarch64_noop, noop_size);
+  fragP->fr_var = noop_size;
 }
 
 /* Perform target specific initialisation of a frag.
@@ -7201,17 +7227,20 @@ struct aarch64_cpu_option_table
    recognized by GCC.  */
 static const struct aarch64_cpu_option_table aarch64_cpus[] = {
   {"all", AARCH64_ANY, NULL},
-  {"cortex-a53",       AARCH64_ARCH_V8, "Cortex-A53"},
-  {"cortex-a57",       AARCH64_ARCH_V8, "Cortex-A57"},
-  {"thunderx",         AARCH64_ARCH_V8, "Cavium ThunderX"},
+  {"cortex-a53", AARCH64_FEATURE(AARCH64_ARCH_V8,
+                                AARCH64_FEATURE_CRC), "Cortex-A53"},
+  {"cortex-a57", AARCH64_FEATURE(AARCH64_ARCH_V8,
+                                AARCH64_FEATURE_CRC), "Cortex-A57"},
+  {"thunderx", AARCH64_ARCH_V8, "Cavium ThunderX"},
+  /* The 'xgene-1' name is an older name for 'xgene1', which was used
+     in earlier releases and is superseded by 'xgene1' in all
+     tools.  */
   {"xgene-1", AARCH64_ARCH_V8, "APM X-Gene 1"},
+  {"xgene1", AARCH64_ARCH_V8, "APM X-Gene 1"},
+  {"xgene2", AARCH64_FEATURE(AARCH64_ARCH_V8,
+                            AARCH64_FEATURE_CRC), "APM X-Gene 2"},
   {"generic", AARCH64_ARCH_V8, NULL},
 
-  /* These two are example CPUs supported in GCC, once we have real
-     CPUs they will be removed.  */
-  {"example-1",        AARCH64_ARCH_V8, NULL},
-  {"example-2",        AARCH64_ARCH_V8, NULL},
-
   {NULL, AARCH64_ARCH_NONE, NULL}
 };
 
@@ -7254,7 +7283,8 @@ struct aarch64_long_option_table
 };
 
 static int
-aarch64_parse_features (char *str, const aarch64_feature_set **opt_p)
+aarch64_parse_features (char *str, const aarch64_feature_set **opt_p,
+                       bfd_boolean ext_only)
 {
   /* We insist on extensions being added before being removed.  We achieve
      this by using the ADDING_VALUE variable to indicate whether we are
@@ -7270,17 +7300,19 @@ aarch64_parse_features (char *str, const aarch64_feature_set **opt_p)
   while (str != NULL && *str != 0)
     {
       const struct aarch64_option_cpu_value_table *opt;
-      char *ext;
+      char *ext = NULL;
       int optlen;
 
-      if (*str != '+')
+      if (!ext_only)
        {
-         as_bad (_("invalid architectural extension"));
-         return 0;
-       }
+         if (*str != '+')
+           {
+             as_bad (_("invalid architectural extension"));
+             return 0;
+           }
 
-      str++;
-      ext = strchr (str, '+');
+         ext = strchr (++str, '+');
+       }
 
       if (ext != NULL)
        optlen = ext - str;
@@ -7360,7 +7392,7 @@ aarch64_parse_cpu (char *str)
       {
        mcpu_cpu_opt = &opt->value;
        if (ext != NULL)
-         return aarch64_parse_features (ext, &mcpu_cpu_opt);
+         return aarch64_parse_features (ext, &mcpu_cpu_opt, FALSE);
 
        return 1;
       }
@@ -7392,7 +7424,7 @@ aarch64_parse_arch (char *str)
       {
        march_cpu_opt = &opt->value;
        if (ext != NULL)
-         return aarch64_parse_features (ext, &march_cpu_opt);
+         return aarch64_parse_features (ext, &march_cpu_opt, FALSE);
 
        return 1;
       }
@@ -7575,7 +7607,7 @@ s_aarch64_cpu (int ignored ATTRIBUTE_UNUSED)
       {
        mcpu_cpu_opt = &opt->value;
        if (ext != NULL)
-         if (!aarch64_parse_features (ext, &mcpu_cpu_opt))
+         if (!aarch64_parse_features (ext, &mcpu_cpu_opt, FALSE))
            return;
 
        cpu_variant = *mcpu_cpu_opt;
@@ -7621,7 +7653,7 @@ s_aarch64_arch (int ignored ATTRIBUTE_UNUSED)
       {
        mcpu_cpu_opt = &opt->value;
        if (ext != NULL)
-         if (!aarch64_parse_features (ext, &mcpu_cpu_opt))
+         if (!aarch64_parse_features (ext, &mcpu_cpu_opt, FALSE))
            return;
 
        cpu_variant = *mcpu_cpu_opt;
@@ -7636,6 +7668,28 @@ s_aarch64_arch (int ignored ATTRIBUTE_UNUSED)
   ignore_rest_of_line ();
 }
 
+/* Parse a .arch_extension directive.  */
+
+static void
+s_aarch64_arch_extension (int ignored ATTRIBUTE_UNUSED)
+{
+  char saved_char;
+  char *ext = input_line_pointer;;
+
+  while (*input_line_pointer && !ISSPACE (*input_line_pointer))
+    input_line_pointer++;
+  saved_char = *input_line_pointer;
+  *input_line_pointer = 0;
+
+  if (!aarch64_parse_features (ext, &mcpu_cpu_opt, TRUE))
+    return;
+
+  cpu_variant = *mcpu_cpu_opt;
+
+  *input_line_pointer = saved_char;
+  demand_empty_rest_of_line ();
+}
+
 /* Copy symbol information.  */
 
 void
This page took 0.026754 seconds and 4 git commands to generate.