* config/tc-ia64.c (ia64_handle_align): Remove bogus be_nop.
[deliverable/binutils-gdb.git] / gas / config / tc-ia64.c
index 7a8d5f52146c9034dddc9dff3046ef7b331dc963..647724bed6ca6d05e7f32b3dd17a4230ae7f5cbe 100644 (file)
@@ -24,7 +24,6 @@
 
   - optional operands
   - directives:
-       .alias
        .eb
        .estate
        .lb
@@ -165,6 +164,11 @@ static void ia64_float_to_chars_littleendian
 static void (*ia64_float_to_chars)
   PARAMS ((char *, LITTLENUM_TYPE *, int));
 
+static struct hash_control *alias_hash;
+static struct hash_control *alias_name_hash;
+static struct hash_control *secalias_hash;
+static struct hash_control *secalias_name_hash;
+
 /* Characters which always start a comment.  */
 const char comment_chars[] = "";
 
@@ -534,9 +538,13 @@ pseudo_func[] =
     { "pause", PSEUDO_FUNC_CONST, { 0x0 } },
 
     /* unwind-related constants:  */
-    { "svr4",  PSEUDO_FUNC_CONST, { 0 } },
-    { "hpux",  PSEUDO_FUNC_CONST, { 1 } },
-    { "nt",    PSEUDO_FUNC_CONST, { 2 } },
+    { "svr4",  PSEUDO_FUNC_CONST,      { ELFOSABI_NONE } },
+    { "hpux",  PSEUDO_FUNC_CONST,      { ELFOSABI_HPUX } },
+    { "nt",    PSEUDO_FUNC_CONST,      { 2 } },                /* conflicts w/ELFOSABI_NETBSD */
+    { "linux", PSEUDO_FUNC_CONST,      { ELFOSABI_LINUX } },
+    { "freebsd", PSEUDO_FUNC_CONST,    { ELFOSABI_FREEBSD } },
+    { "openvms", PSEUDO_FUNC_CONST,    { ELFOSABI_OPENVMS } },
+    { "nsk",   PSEUDO_FUNC_CONST,      { ELFOSABI_NSK } },
 
     /* unwind-related registers:  */
     { "priunat",PSEUDO_FUNC_REG, { REG_PRIUNAT } }
@@ -968,9 +976,11 @@ ia64_elf_section_letter (letter, ptr_msg)
 {
   if (letter == 's')
     return SHF_IA_64_SHORT;
+  else if (letter == 'o')
+    return SHF_LINK_ORDER;
 
-  *ptr_msg = _("Bad .section directive: want a,s,w,x,M,S,G,T in string");
-  return 0;
+  *ptr_msg = _("Bad .section directive: want a,o,s,w,x,M,S,G,T in string");
+  return -1;
 }
 
 /* Map SHF_IA_64_SHORT to SEC_SMALL_DATA.  */
@@ -1004,6 +1014,9 @@ ia64_elf_section_type (str, len)
   if (STREQ (ELF_STRING_ia64_unwind_once))
     return SHT_IA_64_UNWIND;
 
+  if (STREQ ("unwind"))
+    return SHT_IA_64_UNWIND;
+
   if (STREQ ("init_array"))
     return SHT_INIT_ARRAY;
 
@@ -4378,13 +4391,6 @@ dot_psr (dummy)
   demand_empty_rest_of_line ();
 }
 
-static void
-dot_alias (dummy)
-     int dummy ATTRIBUTE_UNUSED;
-{
-  as_bad (".alias not implemented yet");
-}
-
 static void
 dot_ln (dummy)
      int dummy ATTRIBUTE_UNUSED;
@@ -4872,8 +4878,6 @@ const pseudo_typeS md_pseudo_table[] =
     { "body", dot_body, 0 },
     { "prologue", dot_prologue, 0 },
     { "endp", dot_endp, 0 },
-    { "file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0 },
-    { "loc", dwarf2_directive_loc, 0 },
 
     { "fframe", dot_fframe, 0 },
     { "vframe", dot_vframe, 0 },
@@ -4930,6 +4934,7 @@ const pseudo_typeS md_pseudo_table[] =
     { "msb", dot_byteorder, 1 },
     { "psr", dot_psr, 0 },
     { "alias", dot_alias, 0 },
+    { "secalias", dot_alias, 1 },
     { "ln", dot_ln, 0 },               /* source line info (for debugging) */
 
     { "xdata1", dot_xdata, 1 },
@@ -6573,6 +6578,11 @@ md_begin ()
   target_big_endian = -1;
   dot_byteorder (TARGET_BYTES_BIG_ENDIAN);
 
+  alias_hash = hash_new ();
+  alias_name_hash = hash_new ();
+  secalias_hash = hash_new ();
+  secalias_name_hash = hash_new ();
+
   pseudo_func[FUNC_DTP_MODULE].u.sym =
     symbol_new (".<dtpmod>", undefined_section, FUNC_DTP_MODULE,
                &zero_address_frag);
@@ -8716,6 +8726,77 @@ clear_qp_branch_flag (mask)
     }
 }
 
+/* MASK contains 2 and only 2 PRs which are mutually exclusive.  Remove
+   any mutexes which contain one of the PRs and create new ones when
+   needed.  */
+
+static int
+update_qp_mutex (valueT mask)
+{
+  int i;
+  int add = 0;
+
+  i = 0;
+  while (i < qp_mutexeslen)
+    {
+      if ((qp_mutexes[i].prmask & mask) != 0)
+       {
+         /* If it destroys and creates the same mutex, do nothing.  */
+         if (qp_mutexes[i].prmask == mask
+             && qp_mutexes[i].path == md.path)
+           {
+             i++;
+             add = -1;
+           }
+         else
+           {
+             int keep = 0;
+
+             if (md.debug_dv)
+               {
+                 fprintf (stderr, "  Clearing mutex relation");
+                 print_prmask (qp_mutexes[i].prmask);
+                 fprintf (stderr, "\n");
+               }
+             
+             /* Deal with the old mutex with more than 3+ PRs only if
+                the new mutex on the same execution path with it.
+
+                FIXME: The 3+ mutex support is incomplete.
+                dot_pred_rel () may be a better place to fix it.  */
+             if (qp_mutexes[i].path == md.path)
+               {
+                 /* If it is a proper subset of the mutex, create a
+                    new mutex.  */
+                 if (add == 0
+                     && (qp_mutexes[i].prmask & mask) == mask)
+                   add = 1;
+                 
+                 qp_mutexes[i].prmask &= ~mask;
+                 if (qp_mutexes[i].prmask & (qp_mutexes[i].prmask - 1))
+                   {
+                     /* Modify the mutex if there are more than one
+                        PR left.  */
+                     keep = 1;
+                     i++;
+                   }
+               }
+             
+             if (keep == 0)
+               /* Remove the mutex.  */
+               qp_mutexes[i] = qp_mutexes[--qp_mutexeslen];
+           }
+       }
+      else
+       ++i;
+    }
+
+  if (add == 1)
+    add_qp_mutex (mask);
+
+  return add;
+}
+
 /* Remove any mutexes which contain any of the PRs indicated in the mask.
 
    Any changes to a PR clears the mutex relations which include that PR.  */
@@ -8930,7 +9011,7 @@ note_register_values (idesc)
       else if (idesc->operands[i] == IA64_OPND_PR_ROT)
        {
          if (idesc->operands[1] & ((valueT) 1 << 43))
-           qp_changemask = ~(valueT) 0xFFFFFFFFFFF | idesc->operands[1];
+           qp_changemask = -((valueT) 1 << 44) | idesc->operands[1];
          else
            qp_changemask = idesc->operands[1];
          qp_changemask &= ~(valueT) 0xFFFF;
@@ -8980,11 +9061,11 @@ note_register_values (idesc)
     {
       int p1 = CURR_SLOT.opnd[0].X_add_number - REG_P;
       int p2 = CURR_SLOT.opnd[1].X_add_number - REG_P;
-      valueT p1mask = (valueT) 1 << p1;
-      valueT p2mask = (valueT) 1 << p2;
+      valueT p1mask = (p1 != 0) ? (valueT) 1 << p1 : 0;
+      valueT p2mask = (p2 != 0) ? (valueT) 1 << p2 : 0;
 
-      /* If one of the PRs is PR0, we can't really do anything.  */
-      if (p1 == 0 || p2 == 0)
+      /* If both PRs are PR0, we can't really do anything.  */
+      if (p1 == 0 && p2 == 0)
        {
          if (md.debug_dv)
            fprintf (stderr, "  Ignoring PRs due to inclusion of p0\n");
@@ -8994,7 +9075,6 @@ note_register_values (idesc)
       else if (has_suffix_p (idesc->name, ".or.andcm")
               || has_suffix_p (idesc->name, ".and.orcm"))
        {
-         add_qp_mutex (p1mask | p2mask);
          clear_qp_implies (p2mask, p1mask);
        }
       else if (has_suffix_p (idesc->name, ".andcm")
@@ -9010,26 +9090,29 @@ note_register_values (idesc)
        }
       else
        {
+         int added = 0;
+
          clear_qp_implies (p1mask | p2mask, p1mask | p2mask);
-         if (has_suffix_p (idesc->name, ".unc"))
+
+         /* If one of the PRs is PR0, we call clear_qp_mutex.  */
+         if (p1 == 0 || p2 == 0)
+           clear_qp_mutex (p1mask | p2mask);
+         else
+           added = update_qp_mutex (p1mask | p2mask);
+
+         if (CURR_SLOT.qp_regno == 0
+             || has_suffix_p (idesc->name, ".unc"))
            {
-             add_qp_mutex (p1mask | p2mask);
+             if (added == 0 && p1 && p2)
+               add_qp_mutex (p1mask | p2mask);
              if (CURR_SLOT.qp_regno != 0)
                {
-                 add_qp_imply (CURR_SLOT.opnd[0].X_add_number - REG_P,
-                               CURR_SLOT.qp_regno);
-                 add_qp_imply (CURR_SLOT.opnd[1].X_add_number - REG_P,
-                               CURR_SLOT.qp_regno);
+                 if (p1)
+                   add_qp_imply (p1, CURR_SLOT.qp_regno);
+                 if (p2)
+                   add_qp_imply (p2, CURR_SLOT.qp_regno);
                }
            }
-         else if (CURR_SLOT.qp_regno == 0)
-           {
-             add_qp_mutex (p1mask | p2mask);
-           }
-         else
-           {
-             clear_qp_mutex (p1mask | p2mask);
-           }
        }
     }
   /* Look for mov imm insns into GRs.  */
@@ -10661,9 +10744,6 @@ ia64_handle_align (fragp)
      fragS *fragp;
 {
   /* Use mfi bundle of nops with no stop bits.  */
-  static const unsigned char be_nop[]
-    = { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
-       0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c};
   static const unsigned char le_nop[]
     = { 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00};
@@ -10688,7 +10768,8 @@ ia64_handle_align (fragp)
       fragp->fr_fix += fix;
     }
 
-  memcpy (p, (target_big_endian ? be_nop : le_nop), 16);
+  /* Instruction bundles are always little-endian.  */
+  memcpy (p, le_nop, 16);
   fragp->fr_var = 16;
 }
 
@@ -10732,3 +10813,169 @@ ia64_check_label (symbolS *label)
       input_line_pointer++;
     }
 }
+
+/* Used to remember where .alias and .secalias directives are seen. We
+   will rename symbol and section names when we are about to output
+   the relocatable file.  */
+struct alias
+{
+  char *file;          /* The file where the directive is seen.  */
+  unsigned int line;   /* The line number the directive is at.  */
+  const char *name;    /* The orignale name of the symbol.  */
+};
+
+/* Called for .alias and .secalias directives. If SECTION is 1, it is
+   .secalias. Otherwise, it is .alias.  */
+static void
+dot_alias (int section)
+{
+  char *name, *alias;
+  char delim;
+  char *end_name;
+  int len;
+  const char *error_string;
+  struct alias *h;
+  const char *a;
+  struct hash_control *ahash, *nhash;
+  const char *kind;
+
+  name = input_line_pointer;
+  delim = get_symbol_end ();
+  end_name = input_line_pointer;
+  *end_name = delim;
+
+  if (name == end_name)
+    {
+      as_bad (_("expected symbol name"));
+      discard_rest_of_line ();
+      return;
+    }
+
+  SKIP_WHITESPACE ();
+
+  if (*input_line_pointer != ',')
+    {
+      *end_name = 0;
+      as_bad (_("expected comma after \"%s\""), name);
+      *end_name = delim;
+      ignore_rest_of_line ();
+      return;
+    }
+
+  input_line_pointer++;
+  *end_name = 0;
+
+  /* We call demand_copy_C_string to check if alias string is valid.
+     There should be a closing `"' and no `\0' in the string.  */
+  alias = demand_copy_C_string (&len);
+  if (alias == NULL)
+    {
+      ignore_rest_of_line ();
+      return;
+    }
+
+  /* Make a copy of name string.  */
+  len = strlen (name) + 1;
+  obstack_grow (&notes, name, len);
+  name = obstack_finish (&notes);
+
+  if (section)
+    {
+      kind = "section";
+      ahash = secalias_hash;
+      nhash = secalias_name_hash;
+    }
+  else
+    {
+      kind = "symbol";
+      ahash = alias_hash;
+      nhash = alias_name_hash;
+    }
+
+  /* Check if alias has been used before.  */
+  h = (struct alias *) hash_find (ahash, alias);
+  if (h)
+    {
+      if (strcmp (h->name, name))
+       as_bad (_("`%s' is already the alias of %s `%s'"),
+               alias, kind, h->name);
+      goto out;
+    }
+
+  /* Check if name already has an alias.  */
+  a = (const char *) hash_find (nhash, name);
+  if (a)
+    {
+      if (strcmp (a, alias))
+       as_bad (_("%s `%s' already has an alias `%s'"), kind, name, a);
+      goto out;
+    }
+
+  h = (struct alias *) xmalloc (sizeof (struct alias));
+  as_where (&h->file, &h->line);
+  h->name = name;
+  
+  error_string = hash_jam (ahash, alias, (PTR) h);
+  if (error_string)
+    {
+      as_fatal (_("inserting \"%s\" into %s alias hash table failed: %s"),
+               alias, kind, error_string);
+      goto out;
+    }
+
+  error_string = hash_jam (nhash, name, (PTR) alias);
+  if (error_string)
+    {
+      as_fatal (_("inserting \"%s\" into %s name hash table failed: %s"),
+               alias, kind, error_string);
+out:
+      obstack_free (&notes, name);
+      obstack_free (&notes, alias);
+    }
+
+  demand_empty_rest_of_line ();
+}
+
+/* It renames the original symbol name to its alias.  */
+static void
+do_alias (const char *alias, PTR value)
+{
+  struct alias *h = (struct alias *) value;
+  symbolS *sym = symbol_find (h->name);
+
+  if (sym == NULL)
+    as_warn_where (h->file, h->line,
+                  _("symbol `%s' aliased to `%s' is not used"),
+                  h->name, alias);
+    else
+      S_SET_NAME (sym, (char *) alias);
+}
+
+/* Called from write_object_file.  */
+void
+ia64_adjust_symtab (void)
+{
+  hash_traverse (alias_hash, do_alias);
+}
+
+/* It renames the original section name to its alias.  */
+static void
+do_secalias (const char *alias, PTR value)
+{
+  struct alias *h = (struct alias *) value;
+  segT sec = bfd_get_section_by_name (stdoutput, h->name);
+
+  if (sec == NULL)
+    as_warn_where (h->file, h->line,
+                  _("section `%s' aliased to `%s' is not used"),
+                  h->name, alias);
+  else
+    sec->name = alias;
+}
+
+/* Called from write_object_file.  */
+void
+ia64_frob_file (void)
+{
+  hash_traverse (secalias_hash, do_secalias);
+}
This page took 0.029185 seconds and 4 git commands to generate.