aarch64: make the type of reg_entry::type aarch64_reg_type
[deliverable/binutils-gdb.git] / gas / config / obj-elf.c
index 2f93990e721df9b014b714e5de0975273cfff186..8af563fbd24e6d1c6c1b99175d77248eace9745a 100644 (file)
@@ -1,13 +1,11 @@
 /* ELF object file format
 /* ELF object file format
-   Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005, 2006, 2007
-   Free Software Foundation, Inc.
+   Copyright (C) 1992-2016 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
 
    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,
+   published by 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, but
    or (at your option) any later version.
 
    GAS is distributed in the hope that it will be useful, but
 #include "elf/mep.h"
 #endif
 
 #include "elf/mep.h"
 #endif
 
+#ifdef TC_NIOS2
+#include "elf/nios2.h"
+#endif
+
 static void obj_elf_line (int);
 static void obj_elf_size (int);
 static void obj_elf_type (int);
 static void obj_elf_line (int);
 static void obj_elf_size (int);
 static void obj_elf_type (int);
@@ -72,6 +74,7 @@ static void obj_elf_visibility (int);
 static void obj_elf_symver (int);
 static void obj_elf_subsection (int);
 static void obj_elf_popsection (int);
 static void obj_elf_symver (int);
 static void obj_elf_subsection (int);
 static void obj_elf_popsection (int);
+static void obj_elf_gnu_attribute (int);
 static void obj_elf_tls_common (int);
 static void obj_elf_lcomm (int);
 static void obj_elf_struct (int);
 static void obj_elf_tls_common (int);
 static void obj_elf_lcomm (int);
 static void obj_elf_struct (int);
@@ -113,6 +116,9 @@ static const pseudo_typeS elf_pseudo_table[] =
   {"vtable_inherit", (void (*) (int)) &obj_elf_vtable_inherit, 0},
   {"vtable_entry", (void (*) (int)) &obj_elf_vtable_entry, 0},
 
   {"vtable_inherit", (void (*) (int)) &obj_elf_vtable_inherit, 0},
   {"vtable_entry", (void (*) (int)) &obj_elf_vtable_entry, 0},
 
+  /* A GNU extension for object attributes.  */
+  {"gnu_attribute", obj_elf_gnu_attribute, 0},
+
   /* These are used for dwarf.  */
   {"2byte", cons, 2},
   {"4byte", cons, 4},
   /* These are used for dwarf.  */
   {"2byte", cons, 2},
   {"4byte", cons, 4},
@@ -260,19 +266,33 @@ elf_file_symbol (const char *s, int appfile)
       || (symbol_rootP->bsym->flags & BSF_FILE) == 0)
     {
       symbolS *sym;
       || (symbol_rootP->bsym->flags & BSF_FILE) == 0)
     {
       symbolS *sym;
+      size_t name_length;
 
       sym = symbol_new (s, absolute_section, 0, NULL);
       symbol_set_frag (sym, &zero_address_frag);
 
       sym = symbol_new (s, absolute_section, 0, NULL);
       symbol_set_frag (sym, &zero_address_frag);
+
+      name_length = strlen (s);
+      if (name_length > strlen (S_GET_NAME (sym)))
+       {
+         obstack_grow (&notes, s, name_length + 1);
+         S_SET_NAME (sym, (const char *) obstack_finish (&notes));
+       }
+      else
+       strcpy ((char *) S_GET_NAME (sym), s);
+
       symbol_get_bfdsym (sym)->flags |= BSF_FILE;
 
       symbol_get_bfdsym (sym)->flags |= BSF_FILE;
 
-      if (symbol_rootP != sym)
+      if (symbol_rootP != sym
+         && (symbol_rootP->bsym == NULL
+             || !(symbol_rootP->bsym->flags & BSF_FILE)))
        {
          symbol_remove (sym, &symbol_rootP, &symbol_lastP);
          symbol_insert (sym, symbol_rootP, &symbol_rootP, &symbol_lastP);
        {
          symbol_remove (sym, &symbol_rootP, &symbol_lastP);
          symbol_insert (sym, symbol_rootP, &symbol_rootP, &symbol_lastP);
+       }
+
 #ifdef DEBUG
 #ifdef DEBUG
-         verify_symbol_chain (symbol_rootP, symbol_lastP);
+      verify_symbol_chain (symbol_rootP, symbol_lastP);
 #endif
 #endif
-       }
     }
 
 #ifdef NEED_ECOFF_DEBUG
     }
 
 #ifdef NEED_ECOFF_DEBUG
@@ -382,20 +402,34 @@ obj_elf_lcomm (int ignore ATTRIBUTE_UNUSED)
     symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT;
 }
 
     symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT;
 }
 
+static symbolS *
+get_sym_from_input_line_and_check (void)
+{
+  char *name;
+  char c;
+  symbolS *sym;
+
+  c = get_symbol_name (& name);
+  sym = symbol_find_or_make (name);
+  *input_line_pointer = c;
+  SKIP_WHITESPACE_AFTER_NAME ();
+
+  /* There is no symbol name if input_line_pointer has not moved.  */
+  if (name == input_line_pointer)
+    as_bad (_("Missing symbol name in directive"));
+  return sym;
+}
+
 static void
 obj_elf_local (int ignore ATTRIBUTE_UNUSED)
 {
 static void
 obj_elf_local (int ignore ATTRIBUTE_UNUSED)
 {
-  char *name;
   int c;
   symbolS *symbolP;
 
   do
     {
   int c;
   symbolS *symbolP;
 
   do
     {
-      name = input_line_pointer;
-      c = get_symbol_end ();
-      symbolP = symbol_find_or_make (name);
-      *input_line_pointer = c;
-      SKIP_WHITESPACE ();
+      symbolP = get_sym_from_input_line_and_check ();
+      c = *input_line_pointer;
       S_CLEAR_EXTERNAL (symbolP);
       symbol_get_obj (symbolP)->local = 1;
       if (c == ',')
       S_CLEAR_EXTERNAL (symbolP);
       symbol_get_obj (symbolP)->local = 1;
       if (c == ',')
@@ -413,19 +447,14 @@ obj_elf_local (int ignore ATTRIBUTE_UNUSED)
 static void
 obj_elf_weak (int ignore ATTRIBUTE_UNUSED)
 {
 static void
 obj_elf_weak (int ignore ATTRIBUTE_UNUSED)
 {
-  char *name;
   int c;
   symbolS *symbolP;
 
   do
     {
   int c;
   symbolS *symbolP;
 
   do
     {
-      name = input_line_pointer;
-      c = get_symbol_end ();
-      symbolP = symbol_find_or_make (name);
-      *input_line_pointer = c;
-      SKIP_WHITESPACE ();
+      symbolP = get_sym_from_input_line_and_check ();
+      c = *input_line_pointer;
       S_SET_WEAK (symbolP);
       S_SET_WEAK (symbolP);
-      symbol_get_obj (symbolP)->local = 1;
       if (c == ',')
        {
          input_line_pointer++;
       if (c == ',')
        {
          input_line_pointer++;
@@ -441,7 +470,6 @@ obj_elf_weak (int ignore ATTRIBUTE_UNUSED)
 static void
 obj_elf_visibility (int visibility)
 {
 static void
 obj_elf_visibility (int visibility)
 {
-  char *name;
   int c;
   symbolS *symbolP;
   asymbol *bfdsym;
   int c;
   symbolS *symbolP;
   asymbol *bfdsym;
@@ -449,21 +477,17 @@ obj_elf_visibility (int visibility)
 
   do
     {
 
   do
     {
-      name = input_line_pointer;
-      c = get_symbol_end ();
-      symbolP = symbol_find_or_make (name);
-      *input_line_pointer = c;
-
-      SKIP_WHITESPACE ();
+      symbolP = get_sym_from_input_line_and_check ();
 
       bfdsym = symbol_get_bfdsym (symbolP);
       elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym);
 
 
       bfdsym = symbol_get_bfdsym (symbolP);
       elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym);
 
-      assert (elfsym);
+      gas_assert (elfsym);
 
       elfsym->internal_elf_sym.st_other &= ~3;
       elfsym->internal_elf_sym.st_other |= visibility;
 
 
       elfsym->internal_elf_sym.st_other &= ~3;
       elfsym->internal_elf_sym.st_other |= visibility;
 
+      c = *input_line_pointer;
       if (c == ',')
        {
          input_line_pointer ++;
       if (c == ',')
        {
          input_line_pointer ++;
@@ -494,9 +518,9 @@ static struct section_stack *section_stack;
 static bfd_boolean
 get_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
 {
 static bfd_boolean
 get_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
 {
-  const char *gname = inf;
+  const char *gname = (const char *) inf;
   const char *group_name = elf_group_name (sec);
   const char *group_name = elf_group_name (sec);
-  
+
   return (group_name == gname
          || (group_name != NULL
              && gname != NULL
   return (group_name == gname
          || (group_name != NULL
              && gname != NULL
@@ -523,8 +547,8 @@ get_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
 
 void
 obj_elf_change_section (const char *name,
 
 void
 obj_elf_change_section (const char *name,
-                       int type,
-                       int attr,
+                       unsigned int type,
+                       bfd_vma attr,
                        int entsize,
                        const char *group_name,
                        int linkonce,
                        int entsize,
                        const char *group_name,
                        int linkonce,
@@ -544,7 +568,7 @@ obj_elf_change_section (const char *name,
   if (push)
     {
       struct section_stack *elt;
   if (push)
     {
       struct section_stack *elt;
-      elt = xmalloc (sizeof (struct section_stack));
+      elt = XNEW (struct section_stack);
       elt->next = section_stack;
       elt->seg = now_seg;
       elt->prev_seg = previous_section;
       elt->next = section_stack;
       elt->seg = now_seg;
       elt->prev_seg = previous_section;
@@ -577,13 +601,13 @@ obj_elf_change_section (const char *name,
       else if (type != ssect->type)
        {
          if (old_sec == NULL
       else if (type != ssect->type)
        {
          if (old_sec == NULL
-             /* FIXME: gcc, as of 2002-10-22, will emit
+             /* Some older versions of gcc will emit
 
                 .section .init_array,"aw",@progbits
 
                 for __attribute__ ((section (".init_array"))).
                 "@progbits" is incorrect.  Also for x86-64 large bss
 
                 .section .init_array,"aw",@progbits
 
                 for __attribute__ ((section (".init_array"))).
                 "@progbits" is incorrect.  Also for x86-64 large bss
-                sections, gcc, as of 2005-07-06, will emit
+                sections, some older versions of gcc will emit
 
                 .section .lbss,"aw",@progbits
 
 
                 .section .lbss,"aw",@progbits
 
@@ -597,7 +621,9 @@ obj_elf_change_section (const char *name,
              && ssect->type != SHT_PREINIT_ARRAY)
            {
              /* We allow to specify any type for a .note section.  */
              && ssect->type != SHT_PREINIT_ARRAY)
            {
              /* We allow to specify any type for a .note section.  */
-             if (ssect->type != SHT_NOTE)
+             if (ssect->type != SHT_NOTE
+                 /* Processor and application defined types are allowed too.  */
+                 && type < SHT_LOPROC)
                as_warn (_("setting incorrect section type for %s"),
                         name);
            }
                as_warn (_("setting incorrect section type for %s"),
                         name);
            }
@@ -609,7 +635,8 @@ obj_elf_change_section (const char *name,
            }
        }
 
            }
        }
 
-      if (old_sec == NULL && (attr & ~ssect->attr) != 0)
+      if (old_sec == NULL && ((attr & ~(SHF_MASKOS | SHF_MASKPROC))
+                             & ~ssect->attr) != 0)
        {
          /* As a GNU extension, we permit a .note section to be
             allocatable.  If the linker sees an allocatable .note
        {
          /* As a GNU extension, we permit a .note section to be
             allocatable.  If the linker sees an allocatable .note
@@ -641,6 +668,14 @@ obj_elf_change_section (const char *name,
          /* A section on Alpha may have SHF_ALPHA_GPREL.  */
          else if ((attr & ~ssect->attr) == SHF_ALPHA_GPREL)
            override = TRUE;
          /* A section on Alpha may have SHF_ALPHA_GPREL.  */
          else if ((attr & ~ssect->attr) == SHF_ALPHA_GPREL)
            override = TRUE;
+#endif
+#ifdef TC_RX
+         else if (attr == (SHF_EXECINSTR | SHF_WRITE | SHF_ALLOC)
+                  && (ssect->type == SHT_INIT_ARRAY
+                      || ssect->type == SHT_FINI_ARRAY
+                      || ssect->type == SHT_PREINIT_ARRAY))
+           /* RX init/fini arrays can and should have the "awx" attributes set.  */
+           ;
 #endif
          else
            {
 #endif
          else
            {
@@ -650,6 +685,7 @@ obj_elf_change_section (const char *name,
              override = TRUE;
            }
        }
              override = TRUE;
            }
        }
+
       if (!override && old_sec == NULL)
        attr |= ssect->attr;
     }
       if (!override && old_sec == NULL)
        attr |= ssect->attr;
     }
@@ -662,6 +698,7 @@ obj_elf_change_section (const char *name,
           | ((attr & SHF_EXECINSTR) ? SEC_CODE : 0)
           | ((attr & SHF_MERGE) ? SEC_MERGE : 0)
           | ((attr & SHF_STRINGS) ? SEC_STRINGS : 0)
           | ((attr & SHF_EXECINSTR) ? SEC_CODE : 0)
           | ((attr & SHF_MERGE) ? SEC_MERGE : 0)
           | ((attr & SHF_STRINGS) ? SEC_STRINGS : 0)
+          | ((attr & SHF_EXCLUDE) ? SEC_EXCLUDE: 0)
           | ((attr & SHF_TLS) ? SEC_THREAD_LOCAL : 0));
 #ifdef md_elf_section_flags
   flags = md_elf_section_flags (flags, attr, type);
           | ((attr & SHF_TLS) ? SEC_THREAD_LOCAL : 0));
 #ifdef md_elf_section_flags
   flags = md_elf_section_flags (flags, attr, type);
@@ -674,6 +711,8 @@ obj_elf_change_section (const char *name,
     {
       symbolS *secsym;
 
     {
       symbolS *secsym;
 
+      if (type == SHT_NULL)
+       type = bfd_elf_get_default_section_type (flags);
       elf_section_type (sec) = type;
       elf_section_flags (sec) = attr;
 
       elf_section_type (sec) = type;
       elf_section_flags (sec) = attr;
 
@@ -710,6 +749,11 @@ obj_elf_change_section (const char *name,
                  | SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD
                  | SEC_THREAD_LOCAL)))
            as_warn (_("ignoring changed section attributes for %s"), name);
                  | SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD
                  | SEC_THREAD_LOCAL)))
            as_warn (_("ignoring changed section attributes for %s"), name);
+         else
+           /* FIXME: Maybe we should consider removing a previously set
+              processor or application specific attribute as suspicious ?  */
+           elf_section_flags (sec) = attr;
+
          if ((flags & SEC_MERGE) && old_sec->entsize != (unsigned) entsize)
            as_warn (_("ignoring changed section entity size for %s"), name);
        }
          if ((flags & SEC_MERGE) && old_sec->entsize != (unsigned) entsize)
            as_warn (_("ignoring changed section entity size for %s"), name);
        }
@@ -720,10 +764,11 @@ obj_elf_change_section (const char *name,
 #endif
 }
 
 #endif
 }
 
-static int
-obj_elf_parse_section_letters (char *str, size_t len)
+static bfd_vma
+obj_elf_parse_section_letters (char *str, size_t len, bfd_boolean *is_clone)
 {
 {
-  int attr = 0;
+  bfd_vma attr = 0;
+  *is_clone = FALSE;
 
   while (len > 0)
     {
 
   while (len > 0)
     {
@@ -732,6 +777,9 @@ obj_elf_parse_section_letters (char *str, size_t len)
        case 'a':
          attr |= SHF_ALLOC;
          break;
        case 'a':
          attr |= SHF_ALLOC;
          break;
+       case 'e':
+         attr |= SHF_EXCLUDE;
+         break;
        case 'w':
          attr |= SHF_WRITE;
          break;
        case 'w':
          attr |= SHF_WRITE;
          break;
@@ -750,6 +798,9 @@ obj_elf_parse_section_letters (char *str, size_t len)
        case 'T':
          attr |= SHF_TLS;
          break;
        case 'T':
          attr |= SHF_TLS;
          break;
+       case '?':
+         *is_clone = TRUE;
+         break;
        /* Compatibility.  */
        case 'm':
          if (*(str - 1) == 'a')
        /* Compatibility.  */
        case 'm':
          if (*(str - 1) == 'a')
@@ -764,14 +815,27 @@ obj_elf_parse_section_letters (char *str, size_t len)
            }
        default:
          {
            }
        default:
          {
-           char *bad_msg = _("unrecognized .section attribute: want a,w,x,M,S,G,T");
+           const char *bad_msg = _("unrecognized .section attribute:"
+                                   " want a,e,w,x,M,S,G,T or number");
 #ifdef md_elf_section_letter
 #ifdef md_elf_section_letter
-           int md_attr = md_elf_section_letter (*str, &bad_msg);
-           if (md_attr >= 0)
+           bfd_vma md_attr = md_elf_section_letter (*str, &bad_msg);
+           if (md_attr != (bfd_vma) -1)
              attr |= md_attr;
            else
 #endif
              attr |= md_attr;
            else
 #endif
-             as_fatal ("%s", bad_msg);
+             if (ISDIGIT (*str))
+               {
+                 char * end;
+
+                 attr |= strtoul (str, & end, 0);
+                 /* Update str and len, allowing for the fact that
+                    we will execute str++ and len-- below.  */
+                 end --;
+                 len -= (end - str);
+                 str = end;
+               }
+             else
+               as_fatal ("%s", bad_msg);
          }
          break;
        }
          }
          break;
        }
@@ -782,31 +846,7 @@ obj_elf_parse_section_letters (char *str, size_t len)
 }
 
 static int
 }
 
 static int
-obj_elf_section_word (char *str, size_t len)
-{
-  if (len == 5 && strncmp (str, "write", 5) == 0)
-    return SHF_WRITE;
-  if (len == 5 && strncmp (str, "alloc", 5) == 0)
-    return SHF_ALLOC;
-  if (len == 9 && strncmp (str, "execinstr", 9) == 0)
-    return SHF_EXECINSTR;
-  if (len == 3 && strncmp (str, "tls", 3) == 0)
-    return SHF_TLS;
-
-#ifdef md_elf_section_word
-  {
-    int md_attr = md_elf_section_word (str, len);
-    if (md_attr >= 0)
-      return md_attr;
-  }
-#endif
-
-  as_warn (_("unrecognized section attribute"));
-  return 0;
-}
-
-static int
-obj_elf_section_type (char *str, size_t len)
+obj_elf_section_type (char *str, size_t len, bfd_boolean warn)
 {
   if (len == 8 && strncmp (str, "progbits", 8) == 0)
     return SHT_PROGBITS;
 {
   if (len == 8 && strncmp (str, "progbits", 8) == 0)
     return SHT_PROGBITS;
@@ -829,12 +869,57 @@ obj_elf_section_type (char *str, size_t len)
   }
 #endif
 
   }
 #endif
 
-  as_warn (_("unrecognized section type"));
+  if (ISDIGIT (*str))
+    {
+      char * end;
+      int type = strtoul (str, & end, 0);
+
+      if (warn && (size_t) (end - str) != len)
+       as_warn (_("extraneous characters at end of numeric section type"));
+
+      return type;
+    }
+
+  if (warn)
+    as_warn (_("unrecognized section type"));
+  return 0;
+}
+
+static bfd_vma
+obj_elf_section_word (char *str, size_t len, int *type)
+{
+  int ret;
+
+  if (len == 5 && strncmp (str, "write", 5) == 0)
+    return SHF_WRITE;
+  if (len == 5 && strncmp (str, "alloc", 5) == 0)
+    return SHF_ALLOC;
+  if (len == 9 && strncmp (str, "execinstr", 9) == 0)
+    return SHF_EXECINSTR;
+  if (len == 7 && strncmp (str, "exclude", 7) == 0)
+    return SHF_EXCLUDE;
+  if (len == 3 && strncmp (str, "tls", 3) == 0)
+    return SHF_TLS;
+
+#ifdef md_elf_section_word
+  {
+    bfd_vma md_attr = md_elf_section_word (str, len);
+    if (md_attr > 0)
+      return md_attr;
+  }
+#endif
+
+  ret = obj_elf_section_type (str, len, FALSE);
+  if (ret != 0)
+    *type = ret;
+  else
+    as_warn (_("unrecognized section attribute"));
+
   return 0;
 }
 
 /* Get name of section.  */
   return 0;
 }
 
 /* Get name of section.  */
-static char *
+const char *
 obj_elf_section_name (void)
 {
   char *name;
 obj_elf_section_name (void)
 {
   char *name;
@@ -864,9 +949,28 @@ obj_elf_section_name (void)
          return NULL;
        }
 
          return NULL;
        }
 
-      name = xmalloc (end - input_line_pointer + 1);
-      memcpy (name, input_line_pointer, end - input_line_pointer);
-      name[end - input_line_pointer] = '\0';
+      name = xmemdup0 (input_line_pointer, end - input_line_pointer);
+
+      while (flag_sectname_subst)
+        {
+         char *subst = strchr (name, '%');
+         if (subst && subst[1] == 'S')
+           {
+             int oldlen = strlen (name);
+             int substlen = strlen (now_seg->name);
+             int newlen = oldlen - 2 + substlen;
+             char *newname = XNEWVEC (char, newlen + 1);
+             int headlen = subst - name;
+             memcpy (newname, name, headlen);
+             strcpy (newname + headlen, now_seg->name);
+             strcat (newname + headlen, subst + 2);
+             xfree (name);
+             name = newname;
+           }
+         else
+           break;
+       }
+
 #ifdef tc_canonicalize_section_name
       name = tc_canonicalize_section_name (name);
 #endif
 #ifdef tc_canonicalize_section_name
       name = tc_canonicalize_section_name (name);
 #endif
@@ -879,10 +983,13 @@ obj_elf_section_name (void)
 void
 obj_elf_section (int push)
 {
 void
 obj_elf_section (int push)
 {
-  char *name, *group_name, *beg;
-  int type, attr, dummy;
+  const char *name, *group_name;
+  char *beg;
+  int type, dummy;
+  bfd_vma attr;
   int entsize;
   int linkonce;
   int entsize;
   int linkonce;
+  subsegT new_subsection = -1;
 
 #ifndef TC_I370
   if (flag_mri)
 
 #ifndef TC_I370
   if (flag_mri)
@@ -921,15 +1028,33 @@ obj_elf_section (int push)
       ++input_line_pointer;
       SKIP_WHITESPACE ();
 
       ++input_line_pointer;
       SKIP_WHITESPACE ();
 
+      if (push && ISDIGIT (*input_line_pointer))
+       {
+         /* .pushsection has an optional subsection.  */
+         new_subsection = (subsegT) get_absolute_expression ();
+
+         SKIP_WHITESPACE ();
+
+         /* Stop if we don't see a comma.  */
+         if (*input_line_pointer != ',')
+           goto done;
+
+         /* Skip the comma.  */
+         ++input_line_pointer;
+         SKIP_WHITESPACE ();
+       }
+
       if (*input_line_pointer == '"')
        {
       if (*input_line_pointer == '"')
        {
+         bfd_boolean is_clone;
+
          beg = demand_copy_C_string (&dummy);
          if (beg == NULL)
            {
              ignore_rest_of_line ();
              return;
            }
          beg = demand_copy_C_string (&dummy);
          if (beg == NULL)
            {
              ignore_rest_of_line ();
              return;
            }
-         attr |= obj_elf_parse_section_letters (beg, strlen (beg));
+         attr |= obj_elf_parse_section_letters (beg, strlen (beg), &is_clone);
 
          SKIP_WHITESPACE ();
          if (*input_line_pointer == ',')
 
          SKIP_WHITESPACE ();
          if (*input_line_pointer == ',')
@@ -948,14 +1073,22 @@ obj_elf_section (int push)
                      ignore_rest_of_line ();
                      return;
                    }
                      ignore_rest_of_line ();
                      return;
                    }
-                 type = obj_elf_section_type (beg, strlen (beg));
+                 type = obj_elf_section_type (beg, strlen (beg), TRUE);
                }
              else if (c == '@' || c == '%')
                {
                }
              else if (c == '@' || c == '%')
                {
-                 beg = ++input_line_pointer;
-                 c = get_symbol_end ();
-                 *input_line_pointer = c;
-                 type = obj_elf_section_type (beg, input_line_pointer - beg);
+                 ++input_line_pointer;
+
+                 if (ISDIGIT (* input_line_pointer))
+                   {
+                     type = strtoul (input_line_pointer, & input_line_pointer, 0);
+                   }
+                 else
+                   {
+                     c = get_symbol_name (& beg);
+                     (void) restore_line_pointer (c);
+                     type = obj_elf_section_type (beg, input_line_pointer - beg, TRUE);
+                   }
                }
              else
                input_line_pointer = save;
                }
              else
                input_line_pointer = save;
@@ -981,16 +1114,26 @@ obj_elf_section (int push)
              attr &= ~SHF_MERGE;
            }
 
              attr &= ~SHF_MERGE;
            }
 
+         if ((attr & SHF_GROUP) != 0 && is_clone)
+           {
+             as_warn (_("? section flag ignored with G present"));
+             is_clone = FALSE;
+           }
          if ((attr & SHF_GROUP) != 0 && *input_line_pointer == ',')
            {
              ++input_line_pointer;
              group_name = obj_elf_section_name ();
              if (group_name == NULL)
                attr &= ~SHF_GROUP;
          if ((attr & SHF_GROUP) != 0 && *input_line_pointer == ',')
            {
              ++input_line_pointer;
              group_name = obj_elf_section_name ();
              if (group_name == NULL)
                attr &= ~SHF_GROUP;
-             else if (strncmp (input_line_pointer, ",comdat", 7) == 0)
+             else if (*input_line_pointer == ',')
                {
                {
-                 input_line_pointer += 7;
-                 linkonce = 1;
+                 ++input_line_pointer;
+                 SKIP_WHITESPACE ();
+                 if (strncmp (input_line_pointer, "comdat", 6) == 0)
+                   {
+                     input_line_pointer += 6;
+                     linkonce = 1;
+                   }
                }
              else if (strncmp (name, ".gnu.linkonce", 13) == 0)
                linkonce = 1;
                }
              else if (strncmp (name, ".gnu.linkonce", 13) == 0)
                linkonce = 1;
@@ -1000,6 +1143,16 @@ obj_elf_section (int push)
              as_warn (_("group name for SHF_GROUP not specified"));
              attr &= ~SHF_GROUP;
            }
              as_warn (_("group name for SHF_GROUP not specified"));
              attr &= ~SHF_GROUP;
            }
+
+         if (is_clone)
+           {
+             const char *now_group = elf_group_name (now_seg);
+             if (now_group != NULL)
+               {
+                 group_name = xstrdup (now_group);
+                 linkonce = (now_seg->flags & SEC_LINK_ONCE) != 0;
+               }
+           }
        }
       else
        {
        }
       else
        {
@@ -1014,11 +1167,11 @@ obj_elf_section (int push)
                  ignore_rest_of_line ();
                  return;
                }
                  ignore_rest_of_line ();
                  return;
                }
-             beg = ++input_line_pointer;
-             c = get_symbol_end ();
-             *input_line_pointer = c;
+             ++input_line_pointer;
+             c = get_symbol_name (& beg);
+             (void) restore_line_pointer (c);
 
 
-             attr |= obj_elf_section_word (beg, input_line_pointer - beg);
+             attr |= obj_elf_section_word (beg, input_line_pointer - beg, & type);
 
              SKIP_WHITESPACE ();
            }
 
              SKIP_WHITESPACE ();
            }
@@ -1027,9 +1180,13 @@ obj_elf_section (int push)
        }
     }
 
        }
     }
 
+done:
   demand_empty_rest_of_line ();
 
   obj_elf_change_section (name, type, attr, entsize, group_name, linkonce, push);
   demand_empty_rest_of_line ();
 
   obj_elf_change_section (name, type, attr, entsize, group_name, linkonce, push);
+
+  if (push && new_subsection != -1)
+    subseg_set (now_seg, new_subsection);
 }
 
 /* Change to the .data section.  */
 }
 
 /* Change to the .data section.  */
@@ -1089,7 +1246,7 @@ obj_elf_struct (int i)
 static void
 obj_elf_subsection (int ignore ATTRIBUTE_UNUSED)
 {
 static void
 obj_elf_subsection (int ignore ATTRIBUTE_UNUSED)
 {
-  register int temp;
+  int temp;
 
 #ifdef md_flush_pending_output
   md_flush_pending_output ();
 
 #ifdef md_flush_pending_output
   md_flush_pending_output ();
@@ -1193,14 +1350,8 @@ obj_elf_symver (int ignore ATTRIBUTE_UNUSED)
   char old_lexat;
   symbolS *sym;
 
   char old_lexat;
   symbolS *sym;
 
-  name = input_line_pointer;
-  c = get_symbol_end ();
+  sym = get_sym_from_input_line_and_check ();
 
 
-  sym = symbol_find_or_make (name);
-
-  *input_line_pointer = c;
-
-  SKIP_WHITESPACE ();
   if (*input_line_pointer != ',')
     {
       as_bad (_("expected comma after name in .symver"));
   if (*input_line_pointer != ',')
     {
       as_bad (_("expected comma after name in .symver"));
@@ -1210,19 +1361,18 @@ obj_elf_symver (int ignore ATTRIBUTE_UNUSED)
 
   ++input_line_pointer;
   SKIP_WHITESPACE ();
 
   ++input_line_pointer;
   SKIP_WHITESPACE ();
-  name = input_line_pointer;
 
   /* Temporarily include '@' in symbol names.  */
   old_lexat = lex_type[(unsigned char) '@'];
   lex_type[(unsigned char) '@'] |= LEX_NAME;
 
   /* Temporarily include '@' in symbol names.  */
   old_lexat = lex_type[(unsigned char) '@'];
   lex_type[(unsigned char) '@'] |= LEX_NAME;
-  c = get_symbol_end ();
+  c = get_symbol_name (& name);
   lex_type[(unsigned char) '@'] = old_lexat;
 
   if (symbol_get_obj (sym)->versioned_name == NULL)
     {
       symbol_get_obj (sym)->versioned_name = xstrdup (name);
 
   lex_type[(unsigned char) '@'] = old_lexat;
 
   if (symbol_get_obj (sym)->versioned_name == NULL)
     {
       symbol_get_obj (sym)->versioned_name = xstrdup (name);
 
-      *input_line_pointer = c;
+      (void) restore_line_pointer (c);
 
       if (strchr (symbol_get_obj (sym)->versioned_name,
                  ELF_VER_CHR) == NULL)
 
       if (strchr (symbol_get_obj (sym)->versioned_name,
                  ELF_VER_CHR) == NULL)
@@ -1245,7 +1395,7 @@ obj_elf_symver (int ignore ATTRIBUTE_UNUSED)
          return;
        }
 
          return;
        }
 
-      *input_line_pointer = c;
+      (void) restore_line_pointer (c);
     }
 
   demand_empty_rest_of_line ();
     }
 
   demand_empty_rest_of_line ();
@@ -1265,8 +1415,7 @@ obj_elf_vtable_inherit (int ignore ATTRIBUTE_UNUSED)
   if (*input_line_pointer == '#')
     ++input_line_pointer;
 
   if (*input_line_pointer == '#')
     ++input_line_pointer;
 
-  cname = input_line_pointer;
-  c = get_symbol_end ();
+  c = get_symbol_name (& cname);
   csym = symbol_find (cname);
 
   /* GCFIXME: should check that we don't have two .vtable_inherits for
   csym = symbol_find (cname);
 
   /* GCFIXME: should check that we don't have two .vtable_inherits for
@@ -1275,17 +1424,17 @@ obj_elf_vtable_inherit (int ignore ATTRIBUTE_UNUSED)
 
   if (csym == NULL || symbol_get_frag (csym) == NULL)
     {
 
   if (csym == NULL || symbol_get_frag (csym) == NULL)
     {
-      as_bad ("expected `%s' to have already been set for .vtable_inherit",
+      as_bad (_("expected `%s' to have already been set for .vtable_inherit"),
              cname);
       bad = 1;
     }
 
   *input_line_pointer = c;
 
              cname);
       bad = 1;
     }
 
   *input_line_pointer = c;
 
-  SKIP_WHITESPACE ();
+  SKIP_WHITESPACE_AFTER_NAME ();
   if (*input_line_pointer != ',')
     {
   if (*input_line_pointer != ',')
     {
-      as_bad ("expected comma after name in .vtable_inherit");
+      as_bad (_("expected comma after name in .vtable_inherit"));
       ignore_rest_of_line ();
       return NULL;
     }
       ignore_rest_of_line ();
       return NULL;
     }
@@ -1305,10 +1454,9 @@ obj_elf_vtable_inherit (int ignore ATTRIBUTE_UNUSED)
     }
   else
     {
     }
   else
     {
-      pname = input_line_pointer;
-      c = get_symbol_end ();
+      c = get_symbol_name (& pname);
       psym = symbol_find_or_make (pname);
       psym = symbol_find_or_make (pname);
-      *input_line_pointer = c;
+      restore_line_pointer (c);
     }
 
   demand_empty_rest_of_line ();
     }
 
   demand_empty_rest_of_line ();
@@ -1316,7 +1464,7 @@ obj_elf_vtable_inherit (int ignore ATTRIBUTE_UNUSED)
   if (bad)
     return NULL;
 
   if (bad)
     return NULL;
 
-  assert (symbol_get_value_expression (csym)->X_op == O_constant);
+  gas_assert (symbol_get_value_expression (csym)->X_op == O_constant);
   return fix_new (symbol_get_frag (csym),
                  symbol_get_value_expression (csym)->X_add_number,
                  0, psym, 0, 0, BFD_RELOC_VTABLE_INHERIT);
   return fix_new (symbol_get_frag (csym),
                  symbol_get_value_expression (csym)->X_add_number,
                  0, psym, 0, 0, BFD_RELOC_VTABLE_INHERIT);
@@ -1329,23 +1477,16 @@ obj_elf_vtable_inherit (int ignore ATTRIBUTE_UNUSED)
 struct fix *
 obj_elf_vtable_entry (int ignore ATTRIBUTE_UNUSED)
 {
 struct fix *
 obj_elf_vtable_entry (int ignore ATTRIBUTE_UNUSED)
 {
-  char *name;
   symbolS *sym;
   offsetT offset;
   symbolS *sym;
   offsetT offset;
-  char c;
 
   if (*input_line_pointer == '#')
     ++input_line_pointer;
 
 
   if (*input_line_pointer == '#')
     ++input_line_pointer;
 
-  name = input_line_pointer;
-  c = get_symbol_end ();
-  sym = symbol_find_or_make (name);
-  *input_line_pointer = c;
-
-  SKIP_WHITESPACE ();
+  sym = get_sym_from_input_line_and_check ();
   if (*input_line_pointer != ',')
     {
   if (*input_line_pointer != ',')
     {
-      as_bad ("expected comma after name in .vtable_entry");
+      as_bad (_("expected comma after name in .vtable_entry"));
       ignore_rest_of_line ();
       return NULL;
     }
       ignore_rest_of_line ();
       return NULL;
     }
@@ -1362,6 +1503,195 @@ obj_elf_vtable_entry (int ignore ATTRIBUTE_UNUSED)
                  BFD_RELOC_VTABLE_ENTRY);
 }
 
                  BFD_RELOC_VTABLE_ENTRY);
 }
 
+#define skip_whitespace(str)  do { if (*(str) == ' ') ++(str); } while (0)
+
+static inline int
+skip_past_char (char ** str, char c)
+{
+  if (**str == c)
+    {
+      (*str)++;
+      return 0;
+    }
+  else
+    return -1;
+}
+#define skip_past_comma(str) skip_past_char (str, ',')
+
+/* A list of attributes that have been explicitly set by the assembly code.
+   VENDOR is the vendor id, BASE is the tag shifted right by the number
+   of bits in MASK, and bit N of MASK is set if tag BASE+N has been set.  */
+struct recorded_attribute_info {
+  struct recorded_attribute_info *next;
+  int vendor;
+  unsigned int base;
+  unsigned long mask;
+};
+static struct recorded_attribute_info *recorded_attributes;
+
+/* Record that we have seen an explicit specification of attribute TAG
+   for vendor VENDOR.  */
+
+static void
+record_attribute (int vendor, unsigned int tag)
+{
+  unsigned int base;
+  unsigned long mask;
+  struct recorded_attribute_info *rai;
+
+  base = tag / (8 * sizeof (rai->mask));
+  mask = 1UL << (tag % (8 * sizeof (rai->mask)));
+  for (rai = recorded_attributes; rai; rai = rai->next)
+    if (rai->vendor == vendor && rai->base == base)
+      {
+       rai->mask |= mask;
+       return;
+      }
+
+  rai = XNEW (struct recorded_attribute_info);
+  rai->next = recorded_attributes;
+  rai->vendor = vendor;
+  rai->base = base;
+  rai->mask = mask;
+  recorded_attributes = rai;
+}
+
+/* Return true if we have seen an explicit specification of attribute TAG
+   for vendor VENDOR.  */
+
+bfd_boolean
+obj_elf_seen_attribute (int vendor, unsigned int tag)
+{
+  unsigned int base;
+  unsigned long mask;
+  struct recorded_attribute_info *rai;
+
+  base = tag / (8 * sizeof (rai->mask));
+  mask = 1UL << (tag % (8 * sizeof (rai->mask)));
+  for (rai = recorded_attributes; rai; rai = rai->next)
+    if (rai->vendor == vendor && rai->base == base)
+      return (rai->mask & mask) != 0;
+  return FALSE;
+}
+
+/* Parse an attribute directive for VENDOR.
+   Returns the attribute number read, or zero on error.  */
+
+int
+obj_elf_vendor_attribute (int vendor)
+{
+  expressionS exp;
+  int type;
+  int tag;
+  unsigned int i = 0;
+  char *s = NULL;
+
+  /* Read the first number or name.  */
+  skip_whitespace (input_line_pointer);
+  s = input_line_pointer;
+  if (ISDIGIT (*input_line_pointer))
+    {
+      expression (& exp);
+      if (exp.X_op != O_constant)
+       goto bad;
+      tag = exp.X_add_number;
+    }
+  else
+    {
+      char *name;
+
+      /* A name may contain '_', but no other punctuation.  */
+      for (; ISALNUM (*input_line_pointer) || *input_line_pointer == '_';
+          ++input_line_pointer)
+       i++;
+      if (i == 0)
+       goto bad;
+
+      name = xstrndup (s, i);
+
+#ifndef CONVERT_SYMBOLIC_ATTRIBUTE
+#define CONVERT_SYMBOLIC_ATTRIBUTE(a) -1
+#endif
+
+      tag = CONVERT_SYMBOLIC_ATTRIBUTE (name);
+      if (tag == -1)
+       {
+         as_bad (_("Attribute name not recognised: %s"), name);
+         ignore_rest_of_line ();
+         free (name);
+         return 0;
+       }
+      free (name);
+    }
+
+  type = _bfd_elf_obj_attrs_arg_type (stdoutput, vendor, tag);
+
+  if (skip_past_comma (&input_line_pointer) == -1)
+    goto bad;
+  if (type & 1)
+    {
+      expression (& exp);
+      if (exp.X_op != O_constant)
+       {
+         as_bad (_("expected numeric constant"));
+         ignore_rest_of_line ();
+         return 0;
+       }
+      i = exp.X_add_number;
+    }
+  if ((type & 3) == 3
+      && skip_past_comma (&input_line_pointer) == -1)
+    {
+      as_bad (_("expected comma"));
+      ignore_rest_of_line ();
+      return 0;
+    }
+  if (type & 2)
+    {
+      int len;
+
+      skip_whitespace (input_line_pointer);
+      if (*input_line_pointer != '"')
+       goto bad_string;
+      s = demand_copy_C_string (&len);
+    }
+
+  record_attribute (vendor, tag);
+  switch (type & 3)
+    {
+    case 3:
+      bfd_elf_add_obj_attr_int_string (stdoutput, vendor, tag, i, s);
+      break;
+    case 2:
+      bfd_elf_add_obj_attr_string (stdoutput, vendor, tag, s);
+      break;
+    case 1:
+      bfd_elf_add_obj_attr_int (stdoutput, vendor, tag, i);
+      break;
+    default:
+      abort ();
+    }
+
+  demand_empty_rest_of_line ();
+  return tag;
+bad_string:
+  as_bad (_("bad string constant"));
+  ignore_rest_of_line ();
+  return 0;
+bad:
+  as_bad (_("expected <tag> , <value>"));
+  ignore_rest_of_line ();
+  return 0;
+}
+
+/* Parse a .gnu_attribute directive.  */
+
+static void
+obj_elf_gnu_attribute (int ignored ATTRIBUTE_UNUSED)
+{
+  obj_elf_vendor_attribute (OBJ_ATTR_GNU);
+}
+
 void
 elf_obj_read_begin_hook (void)
 {
 void
 elf_obj_read_begin_hook (void)
 {
@@ -1398,7 +1728,7 @@ elf_copy_symbol_attributes (symbolS *dest, symbolS *src)
   if (srcelf->size)
     {
       if (destelf->size == NULL)
   if (srcelf->size)
     {
       if (destelf->size == NULL)
-       destelf->size = xmalloc (sizeof (expressionS));
+       destelf->size = XNEW (expressionS);
       *destelf->size = *srcelf->size;
     }
   else
       *destelf->size = *srcelf->size;
     }
   else
@@ -1476,15 +1806,15 @@ obj_elf_version (int ignore ATTRIBUTE_UNUSED)
 static void
 obj_elf_size (int ignore ATTRIBUTE_UNUSED)
 {
 static void
 obj_elf_size (int ignore ATTRIBUTE_UNUSED)
 {
-  char *name = input_line_pointer;
-  char c = get_symbol_end ();
+  char *name;
+  char c = get_symbol_name (&name);
   char *p;
   expressionS exp;
   symbolS *sym;
 
   p = input_line_pointer;
   *p = c;
   char *p;
   expressionS exp;
   symbolS *sym;
 
   p = input_line_pointer;
   *p = c;
-  SKIP_WHITESPACE ();
+  SKIP_WHITESPACE_AFTER_NAME ();
   if (*input_line_pointer != ',')
     {
       *p = 0;
   if (*input_line_pointer != ',')
     {
       *p = 0;
@@ -1515,14 +1845,14 @@ obj_elf_size (int ignore ATTRIBUTE_UNUSED)
     }
   else
     {
     }
   else
     {
-      symbol_get_obj (sym)->size = xmalloc (sizeof (expressionS));
+      symbol_get_obj (sym)->size = XNEW (expressionS);
       *symbol_get_obj (sym)->size = exp;
     }
   demand_empty_rest_of_line ();
 }
 
 /* Handle the ELF .type pseudo-op.  This sets the type of a symbol.
       *symbol_get_obj (sym)->size = exp;
     }
   demand_empty_rest_of_line ();
 }
 
 /* Handle the ELF .type pseudo-op.  This sets the type of a symbol.
-   There are five syntaxes:
+   There are six syntaxes:
 
    The first (used on Solaris) is
        .type SYM,#function
 
    The first (used on Solaris) is
        .type SYM,#function
@@ -1534,25 +1864,45 @@ obj_elf_size (int ignore ATTRIBUTE_UNUSED)
        .type SYM,%function
    The fifth (used on SVR4/860) is
        .type SYM,"function"
        .type SYM,%function
    The fifth (used on SVR4/860) is
        .type SYM,"function"
+   The sixth (emitted by recent SunPRO under Solaris) is
+       .type SYM,[0-9]
+   where the integer is the STT_* value.
    */
 
    */
 
+static char *
+obj_elf_type_name (char *cp)
+{
+  char *p;
+
+  p = input_line_pointer;
+  if (*input_line_pointer >= '0'
+      && *input_line_pointer <= '9')
+    {
+      while (*input_line_pointer >= '0'
+            && *input_line_pointer <= '9')
+       ++input_line_pointer;
+      *cp = *input_line_pointer;
+      *input_line_pointer = '\0';
+    }
+  else
+    *cp = get_symbol_name (&p);
+
+  return p;
+}
+
 static void
 obj_elf_type (int ignore ATTRIBUTE_UNUSED)
 {
 static void
 obj_elf_type (int ignore ATTRIBUTE_UNUSED)
 {
-  char *name;
   char c;
   int type;
   char c;
   int type;
-  const char *typename;
+  const char *type_name;
   symbolS *sym;
   elf_symbol_type *elfsym;
 
   symbolS *sym;
   elf_symbol_type *elfsym;
 
-  name = input_line_pointer;
-  c = get_symbol_end ();
-  sym = symbol_find_or_make (name);
+  sym = get_sym_from_input_line_and_check ();
+  c = *input_line_pointer;
   elfsym = (elf_symbol_type *) symbol_get_bfdsym (sym);
   elfsym = (elf_symbol_type *) symbol_get_bfdsym (sym);
-  *input_line_pointer = c;
 
 
-  SKIP_WHITESPACE ();
   if (*input_line_pointer == ',')
     ++input_line_pointer;
 
   if (*input_line_pointer == ',')
     ++input_line_pointer;
 
@@ -1563,28 +1913,88 @@ obj_elf_type (int ignore ATTRIBUTE_UNUSED)
       || *input_line_pointer == '%')
     ++input_line_pointer;
 
       || *input_line_pointer == '%')
     ++input_line_pointer;
 
-  typename = input_line_pointer;
-  c = get_symbol_end ();
+  type_name = obj_elf_type_name (& c);
 
   type = 0;
 
   type = 0;
-  if (strcmp (typename, "function") == 0
-      || strcmp (typename, "STT_FUNC") == 0)
+  if (strcmp (type_name, "function") == 0
+      || strcmp (type_name, "2") == 0
+      || strcmp (type_name, "STT_FUNC") == 0)
     type = BSF_FUNCTION;
     type = BSF_FUNCTION;
-  else if (strcmp (typename, "object") == 0
-          || strcmp (typename, "STT_OBJECT") == 0)
+  else if (strcmp (type_name, "object") == 0
+          || strcmp (type_name, "1") == 0
+          || strcmp (type_name, "STT_OBJECT") == 0)
     type = BSF_OBJECT;
     type = BSF_OBJECT;
-  else if (strcmp (typename, "tls_object") == 0
-          || strcmp (typename, "STT_TLS") == 0)
+  else if (strcmp (type_name, "tls_object") == 0
+          || strcmp (type_name, "6") == 0
+          || strcmp (type_name, "STT_TLS") == 0)
     type = BSF_OBJECT | BSF_THREAD_LOCAL;
     type = BSF_OBJECT | BSF_THREAD_LOCAL;
-  else if (strcmp (typename, "notype") == 0
-          || strcmp (typename, "STT_NOTYPE") == 0)
+  else if (strcmp (type_name, "notype") == 0
+          || strcmp (type_name, "0") == 0
+          || strcmp (type_name, "STT_NOTYPE") == 0)
     ;
     ;
+  else if (strcmp (type_name, "common") == 0
+          || strcmp (type_name, "5") == 0
+          || strcmp (type_name, "STT_COMMON") == 0)
+    {
+      type = BSF_OBJECT;
+
+      if (! S_IS_COMMON (sym))
+       {
+         if (S_IS_VOLATILE (sym))
+           {
+             sym = symbol_clone (sym, 1);
+             S_SET_SEGMENT (sym, bfd_com_section_ptr);
+             S_SET_VALUE (sym, 0);
+             S_SET_EXTERNAL (sym);
+             symbol_set_frag (sym, &zero_address_frag);
+             S_CLEAR_VOLATILE (sym);
+           }
+         else if (S_IS_DEFINED (sym) || symbol_equated_p (sym))
+           as_bad (_("symbol '%s' is already defined"), S_GET_NAME (sym));
+         else
+           {
+             /* FIXME: Is it safe to just change the section ?  */
+             S_SET_SEGMENT (sym, bfd_com_section_ptr);
+             S_SET_VALUE (sym, 0);
+             S_SET_EXTERNAL (sym);
+           }
+       }
+    }
+  else if (strcmp (type_name, "gnu_indirect_function") == 0
+          || strcmp (type_name, "10") == 0
+          || strcmp (type_name, "STT_GNU_IFUNC") == 0)
+    {
+      const struct elf_backend_data *bed;
+
+      bed = get_elf_backend_data (stdoutput);
+      if (!(bed->elf_osabi == ELFOSABI_GNU
+           || bed->elf_osabi == ELFOSABI_FREEBSD
+           /* GNU is still using the default value 0.  */
+           || bed->elf_osabi == ELFOSABI_NONE))
+       as_bad (_("symbol type \"%s\" is supported only by GNU and FreeBSD targets"),
+               type_name);
+      type = BSF_FUNCTION | BSF_GNU_INDIRECT_FUNCTION;
+    }
+  else if (strcmp (type_name, "gnu_unique_object") == 0)
+    {
+      struct elf_backend_data *bed;
+
+      bed = (struct elf_backend_data *) get_elf_backend_data (stdoutput);
+      if (!(bed->elf_osabi == ELFOSABI_GNU
+           /* GNU is still using the default value 0.  */
+           || bed->elf_osabi == ELFOSABI_NONE))
+       as_bad (_("symbol type \"%s\" is supported only by GNU targets"),
+               type_name);
+      type = BSF_OBJECT | BSF_GNU_UNIQUE;
+      /* PR 10549: Always set OSABI field to GNU for objects containing unique symbols.  */
+      bed->elf_osabi = ELFOSABI_GNU;
+    }
 #ifdef md_elf_symbol_type
 #ifdef md_elf_symbol_type
-  else if ((type = md_elf_symbol_type (typename, sym, elfsym)) != -1)
+  else if ((type = md_elf_symbol_type (type_name, sym, elfsym)) != -1)
     ;
 #endif
   else
     ;
 #endif
   else
-    as_bad (_("unrecognized symbol type \"%s\""), typename);
+    as_bad (_("unrecognized symbol type \"%s\""), type_name);
 
   *input_line_pointer = c;
 
 
   *input_line_pointer = c;
 
@@ -1612,13 +2022,18 @@ obj_elf_ident (int ignore ATTRIBUTE_UNUSED)
       char *p;
       comment_section = subseg_new (".comment", 0);
       bfd_set_section_flags (stdoutput, comment_section,
       char *p;
       comment_section = subseg_new (".comment", 0);
       bfd_set_section_flags (stdoutput, comment_section,
-                            SEC_READONLY | SEC_HAS_CONTENTS);
+                            SEC_READONLY | SEC_HAS_CONTENTS
+                            | SEC_MERGE | SEC_STRINGS);
+      comment_section->entsize = 1;
+#ifdef md_elf_section_change_hook
+      md_elf_section_change_hook ();
+#endif
       p = frag_more (1);
       *p = 0;
     }
   else
     subseg_set (comment_section, 0);
       p = frag_more (1);
       *p = 0;
     }
   else
     subseg_set (comment_section, 0);
-  stringer (1);
+  stringer (8 + 1);
   subseg_set (old_section, old_subsection);
 }
 
   subseg_set (old_section, old_subsection);
 }
 
@@ -1629,7 +2044,7 @@ obj_elf_ident (int ignore ATTRIBUTE_UNUSED)
 void
 obj_elf_init_stab_section (segT seg)
 {
 void
 obj_elf_init_stab_section (segT seg)
 {
-  char *file;
+  const char *file;
   char *p;
   char *stabstr_name;
   unsigned int stroff;
   char *p;
   char *stabstr_name;
   unsigned int stroff;
@@ -1642,12 +2057,10 @@ obj_elf_init_stab_section (segT seg)
   p = frag_more (12);
   /* Zero it out.  */
   memset (p, 0, 12);
   p = frag_more (12);
   /* Zero it out.  */
   memset (p, 0, 12);
-  as_where (&file, NULL);
-  stabstr_name = xmalloc (strlen (segment_name (seg)) + 4);
-  strcpy (stabstr_name, segment_name (seg));
-  strcat (stabstr_name, "str");
+  file = as_where (NULL);
+  stabstr_name = concat (segment_name (seg), "str", (char *) NULL);
   stroff = get_stab_string_offset (file, stabstr_name);
   stroff = get_stab_string_offset (file, stabstr_name);
-  know (stroff == 1);
+  know (stroff == 1 || (stroff == 0 && file[0] == '\0'));
   md_number_to_chars (p, stroff, 4);
   seg_info (seg)->stabu.p = p;
 }
   md_number_to_chars (p, stroff, 4);
   seg_info (seg)->stabu.p = p;
 }
@@ -1669,9 +2082,7 @@ adjust_stab_sections (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
   if (!strcmp ("str", sec->name + strlen (sec->name) - 3))
     return;
 
   if (!strcmp ("str", sec->name + strlen (sec->name) - 3))
     return;
 
-  name = alloca (strlen (sec->name) + 4);
-  strcpy (name, sec->name);
-  strcat (name, "str");
+  name = concat (sec->name, "str", NULL);
   strsec = bfd_get_section_by_name (abfd, name);
   if (strsec)
     strsz = bfd_section_size (abfd, strsec);
   strsec = bfd_get_section_by_name (abfd, name);
   if (strsec)
     strsz = bfd_section_size (abfd, strsec);
@@ -1680,10 +2091,11 @@ adjust_stab_sections (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
   nsyms = bfd_section_size (abfd, sec) / 12 - 1;
 
   p = seg_info (sec)->stabu.p;
   nsyms = bfd_section_size (abfd, sec) / 12 - 1;
 
   p = seg_info (sec)->stabu.p;
-  assert (p != 0);
+  gas_assert (p != 0);
 
   bfd_h_put_16 (abfd, nsyms, p + 6);
   bfd_h_put_32 (abfd, strsz, p + 8);
 
   bfd_h_put_16 (abfd, nsyms, p + 6);
   bfd_h_put_32 (abfd, strsz, p + 8);
+  free (name);
 }
 
 #ifdef NEED_ECOFF_DEBUG
 }
 
 #ifdef NEED_ECOFF_DEBUG
@@ -1731,6 +2143,7 @@ void
 elf_frob_symbol (symbolS *symp, int *puntp)
 {
   struct elf_obj_sy *sy_obj;
 elf_frob_symbol (symbolS *symp, int *puntp)
 {
   struct elf_obj_sy *sy_obj;
+  expressionS *size;
 
 #ifdef NEED_ECOFF_DEBUG
   if (ECOFF_DEBUGGING)
 
 #ifdef NEED_ECOFF_DEBUG
   if (ECOFF_DEBUGGING)
@@ -1739,24 +2152,20 @@ elf_frob_symbol (symbolS *symp, int *puntp)
 
   sy_obj = symbol_get_obj (symp);
 
 
   sy_obj = symbol_get_obj (symp);
 
-  if (sy_obj->size != NULL)
+  size = sy_obj->size;
+  if (size != NULL)
     {
     {
-      switch (sy_obj->size->X_op)
+      if (resolve_expression (size)
+         && size->X_op == O_constant)
+       S_SET_SIZE (symp, size->X_add_number);
+      else
        {
        {
-       case O_subtract:
-         S_SET_SIZE (symp,
-                     (S_GET_VALUE (sy_obj->size->X_add_symbol)
-                      + sy_obj->size->X_add_number
-                      - S_GET_VALUE (sy_obj->size->X_op_symbol)));
-         break;
-       case O_constant:
-         S_SET_SIZE (symp,
-                     (S_GET_VALUE (sy_obj->size->X_add_symbol)
-                      + sy_obj->size->X_add_number));
-         break;
-       default:
-         as_bad (_(".size expression too complicated to fix up"));
-         break;
+         if (!flag_allow_nonconst_size)
+           as_bad (_(".size expression for %s "
+                     "does not evaluate to a constant"), S_GET_NAME (symp));
+         else
+           as_warn (_(".size expression for %s "
+                      "does not evaluate to a constant"), S_GET_NAME (symp));
        }
       free (sy_obj->size);
       sy_obj->size = NULL;
        }
       free (sy_obj->size);
       sy_obj->size = NULL;
@@ -1767,7 +2176,9 @@ elf_frob_symbol (symbolS *symp, int *puntp)
       char *p;
 
       p = strchr (sy_obj->versioned_name, ELF_VER_CHR);
       char *p;
 
       p = strchr (sy_obj->versioned_name, ELF_VER_CHR);
-      know (p != NULL);
+      if (p == NULL)
+       /* We will have already reported an error about a missing version.  */
+       *puntp = TRUE;
 
       /* This symbol was given a new name with the .symver directive.
 
 
       /* This symbol was given a new name with the .symver directive.
 
@@ -1780,14 +2191,15 @@ elf_frob_symbol (symbolS *symp, int *puntp)
         symbol.  However, it's not clear whether it is the best
         approach.  */
 
         symbol.  However, it's not clear whether it is the best
         approach.  */
 
-      if (! S_IS_DEFINED (symp))
+      else if (! S_IS_DEFINED (symp))
        {
          /* Verify that the name isn't using the @@ syntax--this is
             reserved for definitions of the default version to link
             against.  */
          if (p[1] == ELF_VER_CHR)
            {
        {
          /* Verify that the name isn't using the @@ syntax--this is
             reserved for definitions of the default version to link
             against.  */
          if (p[1] == ELF_VER_CHR)
            {
-             as_bad (_("invalid attempt to declare external version name as default in symbol `%s'"),
+             as_bad (_("invalid attempt to declare external version name"
+                       " as default in symbol `%s'"),
                      sy_obj->versioned_name);
              *puntp = TRUE;
            }
                      sy_obj->versioned_name);
              *puntp = TRUE;
            }
@@ -1875,6 +2287,7 @@ struct group_list
   asection **head;             /* Section lists.  */
   unsigned int *elt_count;     /* Number of sections in each list.  */
   unsigned int num_group;      /* Number of lists.  */
   asection **head;             /* Section lists.  */
   unsigned int *elt_count;     /* Number of sections in each list.  */
   unsigned int num_group;      /* Number of lists.  */
+  struct hash_control *indexes; /* Maps group name to index in head array.  */
 };
 
 /* Called via bfd_map_over_sections.  If SEC is a member of a group,
 };
 
 /* Called via bfd_map_over_sections.  If SEC is a member of a group,
@@ -1885,24 +2298,24 @@ struct group_list
 static void
 build_group_lists (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
 {
 static void
 build_group_lists (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
 {
-  struct group_list *list = inf;
+  struct group_list *list = (struct group_list *) inf;
   const char *group_name = elf_group_name (sec);
   unsigned int i;
   const char *group_name = elf_group_name (sec);
   unsigned int i;
+  unsigned int *elem_idx;
+  unsigned int *idx_ptr;
 
   if (group_name == NULL)
     return;
 
   /* If this group already has a list, add the section to the head of
      the list.  */
 
   if (group_name == NULL)
     return;
 
   /* If this group already has a list, add the section to the head of
      the list.  */
-  for (i = 0; i < list->num_group; i++)
+  elem_idx = (unsigned int *) hash_find (list->indexes, group_name);
+  if (elem_idx != NULL)
     {
     {
-      if (strcmp (group_name, elf_group_name (list->head[i])) == 0)
-       {
-         elf_next_in_group (sec) = list->head[i];
-         list->head[i] = sec;
-         list->elt_count[i] += 1;
-         return;
-       }
+      elf_next_in_group (sec) = list->head[*elem_idx];
+      list->head[*elem_idx] = sec;
+      list->elt_count[*elem_idx] += 1;
+      return;
     }
 
   /* New group.  Make the arrays bigger in chunks to minimize calls to
     }
 
   /* New group.  Make the arrays bigger in chunks to minimize calls to
@@ -1911,41 +2324,48 @@ build_group_lists (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf)
   if ((i & 127) == 0)
     {
       unsigned int newsize = i + 128;
   if ((i & 127) == 0)
     {
       unsigned int newsize = i + 128;
-      list->head = xrealloc (list->head, newsize * sizeof (*list->head));
-      list->elt_count = xrealloc (list->elt_count,
-                                 newsize * sizeof (*list->elt_count));
+      list->head = XRESIZEVEC (asection *, list->head, newsize);
+      list->elt_count = XRESIZEVEC (unsigned int, list->elt_count, newsize);
     }
   list->head[i] = sec;
   list->elt_count[i] = 1;
   list->num_group += 1;
     }
   list->head[i] = sec;
   list->elt_count[i] = 1;
   list->num_group += 1;
+
+  /* Add index to hash.  */
+  idx_ptr = XNEW (unsigned int);
+  *idx_ptr = i;
+  hash_insert (list->indexes, group_name, idx_ptr);
+}
+
+static void free_section_idx (const char *key ATTRIBUTE_UNUSED, void *val)
+{
+  free ((unsigned int *) val);
 }
 
 void
 }
 
 void
-elf_frob_file (void)
+elf_adjust_symtab (void)
 {
   struct group_list list;
   unsigned int i;
 
 {
   struct group_list list;
   unsigned int i;
 
-  bfd_map_over_sections (stdoutput, adjust_stab_sections, NULL);
-
   /* Go find section groups.  */
   list.num_group = 0;
   list.head = NULL;
   list.elt_count = NULL;
   /* Go find section groups.  */
   list.num_group = 0;
   list.head = NULL;
   list.elt_count = NULL;
+  list.indexes = hash_new ();
   bfd_map_over_sections (stdoutput, build_group_lists, &list);
 
   /* Make the SHT_GROUP sections that describe each section group.  We
      can't set up the section contents here yet, because elf section
      indices have yet to be calculated.  elf.c:set_group_contents does
      the rest of the work.  */
   bfd_map_over_sections (stdoutput, build_group_lists, &list);
 
   /* Make the SHT_GROUP sections that describe each section group.  We
      can't set up the section contents here yet, because elf section
      indices have yet to be calculated.  elf.c:set_group_contents does
      the rest of the work.  */
 for (i = 0; i < list.num_group; i++)
+ for (i = 0; i < list.num_group; i++)
     {
       const char *group_name = elf_group_name (list.head[i]);
       const char *sec_name;
       asection *s;
       flagword flags;
       struct symbol *sy;
     {
       const char *group_name = elf_group_name (list.head[i]);
       const char *sec_name;
       asection *s;
       flagword flags;
       struct symbol *sy;
-      int has_sym;
       bfd_size_type size;
 
       flags = SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_GROUP;
       bfd_size_type size;
 
       flags = SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_GROUP;
@@ -1961,17 +2381,7 @@ elf_frob_file (void)
              }
          }
 
              }
          }
 
-      sec_name = group_name;
-      sy = symbol_find_exact (group_name);
-      has_sym = 0;
-      if (sy != NULL
-         && (sy == symbol_lastP
-             || (sy->sy_next != NULL
-                 && sy->sy_next->sy_previous == sy)))
-       {
-         has_sym = 1;
-         sec_name = ".group";
-       }
+      sec_name = ".group";
       s = subseg_force_new (sec_name, 0);
       if (s == NULL
          || !bfd_set_section_flags (stdoutput, s, flags)
       s = subseg_force_new (sec_name, 0);
       if (s == NULL
          || !bfd_set_section_flags (stdoutput, s, flags)
@@ -1984,8 +2394,27 @@ elf_frob_file (void)
 
       /* Pass a pointer to the first section in this group.  */
       elf_next_in_group (s) = list.head[i];
 
       /* Pass a pointer to the first section in this group.  */
       elf_next_in_group (s) = list.head[i];
-      if (has_sym)
-       elf_group_id (s) = sy->bsym;
+      /* Make sure that the signature symbol for the group has the
+        name of the group.  */
+      sy = symbol_find_exact (group_name);
+      if (!sy
+         || (sy != symbol_lastP
+             && (sy->sy_next == NULL
+                 || sy->sy_next->sy_previous != sy)))
+       {
+         /* Create the symbol now.  */
+         sy = symbol_new (group_name, now_seg, (valueT) 0, frag_now);
+#ifdef TE_SOLARIS
+         /* Before Solaris 11 build 154, Sun ld rejects local group
+            signature symbols, so make them weak hidden instead.  */
+         symbol_get_bfdsym (sy)->flags |= BSF_WEAK;
+         S_SET_OTHER (sy, STV_HIDDEN);
+#else
+         symbol_get_obj (sy)->local = 1;
+#endif
+         symbol_table_insert (sy);
+       }
+      elf_group_id (s) = symbol_get_bfdsym (sy);
 
       size = 4 * (list.elt_count[i] + 1);
       bfd_set_section_size (stdoutput, s, size);
 
       size = 4 * (list.elt_count[i] + 1);
       bfd_set_section_size (stdoutput, s, size);
@@ -1994,6 +2423,16 @@ elf_frob_file (void)
       frag_wane (frag_now);
     }
 
       frag_wane (frag_now);
     }
 
+  /* Cleanup hash.  */
+  hash_traverse (list.indexes, free_section_idx);
+  hash_die (list.indexes);
+}
+
+void
+elf_frob_file (void)
+{
+  bfd_map_over_sections (stdoutput, adjust_stab_sections, NULL);
+
 #ifdef elf_tc_final_processing
   elf_tc_final_processing ();
 #endif
 #ifdef elf_tc_final_processing
   elf_tc_final_processing ();
 #endif
@@ -2021,8 +2460,7 @@ elf_frob_file_before_adjust (void)
 
                p = strchr (symbol_get_obj (symp)->versioned_name,
                            ELF_VER_CHR);
 
                p = strchr (symbol_get_obj (symp)->versioned_name,
                            ELF_VER_CHR);
-               know (p != NULL);
-               if (p[1] == ELF_VER_CHR && p[2] == ELF_VER_CHR)
+               if (p != NULL && p[1] == ELF_VER_CHR && p[2] == ELF_VER_CHR)
                  {
                    size_t l = strlen (&p[3]) + 1;
                    memmove (&p[1], &p[3], l);
                  {
                    size_t l = strlen (&p[3]) + 1;
                    memmove (&p[1], &p[3], l);
@@ -2091,7 +2529,7 @@ elf_frob_file_after_relocs (void)
                  bfd_errmsg (bfd_get_error ()));
 
       sec = bfd_get_section_by_name (stdoutput, ".mdebug");
                  bfd_errmsg (bfd_get_error ()));
 
       sec = bfd_get_section_by_name (stdoutput, ".mdebug");
-      assert (sec != NULL);
+      gas_assert (sec != NULL);
 
       know (!stdoutput->output_has_begun);
 
 
       know (!stdoutput->output_has_begun);
 
@@ -2218,6 +2656,29 @@ sco_id (void)
 
 #endif /* SCO_ELF */
 
 
 #endif /* SCO_ELF */
 
+static void
+elf_generate_asm_lineno (void)
+{
+#ifdef NEED_ECOFF_DEBUG
+  if (ECOFF_DEBUGGING)
+    ecoff_generate_asm_lineno ();
+#endif
+}
+
+static void
+elf_process_stab (segT sec ATTRIBUTE_UNUSED,
+                 int what ATTRIBUTE_UNUSED,
+                 const char *string ATTRIBUTE_UNUSED,
+                 int type ATTRIBUTE_UNUSED,
+                 int other ATTRIBUTE_UNUSED,
+                 int desc ATTRIBUTE_UNUSED)
+{
+#ifdef NEED_ECOFF_DEBUG
+  if (ECOFF_DEBUGGING)
+    ecoff_stab (sec, what, string, type, other, desc);
+#endif
+}
+
 static int
 elf_separate_stab_sections (void)
 {
 static int
 elf_separate_stab_sections (void)
 {
@@ -2258,13 +2719,8 @@ const struct format_ops elf_format_ops =
   0,   /* s_get_type */
   0,   /* s_set_type */
   elf_copy_symbol_attributes,
   0,   /* s_get_type */
   0,   /* s_set_type */
   elf_copy_symbol_attributes,
-#ifdef NEED_ECOFF_DEBUG
-  ecoff_generate_asm_lineno,
-  ecoff_stab,
-#else
-  0,   /* generate_asm_lineno */
-  0,   /* process_stab */
-#endif
+  elf_generate_asm_lineno,
+  elf_process_stab,
   elf_separate_stab_sections,
   elf_init_stab_section,
   elf_sec_sym_ok_for_reloc,
   elf_separate_stab_sections,
   elf_init_stab_section,
   elf_sec_sym_ok_for_reloc,
@@ -2275,5 +2731,7 @@ const struct format_ops elf_format_ops =
   0,   /* ecoff_set_ext */
 #endif
   elf_obj_read_begin_hook,
   0,   /* ecoff_set_ext */
 #endif
   elf_obj_read_begin_hook,
-  elf_obj_symbol_new_hook
+  elf_obj_symbol_new_hook,
+  0,
+  elf_adjust_symtab
 };
 };
This page took 0.045398 seconds and 4 git commands to generate.