* elf.c (_bfd_elf_make_section_from_shdr): Set SEC_THREAD_LOCAL
[deliverable/binutils-gdb.git] / gas / config / obj-elf.c
index 1c481a6f5b410b5e5f539743f4497e75b8c23428..5524b07bf94fb2f5c64c97e0d0fae113efb7232b 100644 (file)
@@ -1,6 +1,6 @@
 /* ELF object file format
-   Copyright (C) 1992, 93, 94, 95, 96, 97, 98, 99, 2000
-   Free Software Foundation, Inc.
+   Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
    You should have received a copy of the GNU General Public License
    along with GAS; see the file COPYING.  If not, write to the Free
    Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA. */
+   02111-1307, USA.  */
 
 #define OBJ_HEADER "obj-elf.h"
 #include "as.h"
+#include "safe-ctype.h"
 #include "subsegs.h"
 #include "obstack.h"
 
@@ -55,11 +56,12 @@ static void elf_s_set_size PARAMS ((symbolS *, bfd_vma));
 static bfd_vma elf_s_get_align PARAMS ((symbolS *));
 static void elf_s_set_align PARAMS ((symbolS *, bfd_vma));
 static void elf_s_set_other PARAMS ((symbolS *, int));
-static void elf_copy_symbol_attributes PARAMS ((symbolS *, symbolS *));
 static int elf_sec_sym_ok_for_reloc PARAMS ((asection *));
 static void adjust_stab_sections PARAMS ((bfd *, asection *, PTR));
+static void build_group_lists PARAMS ((bfd *, asection *, PTR));
 static int elf_separate_stab_sections PARAMS ((void));
 static void elf_init_stab_section PARAMS ((segT));
+static symbolS *elf_common PARAMS ((int));
 
 #ifdef NEED_ECOFF_DEBUG
 static boolean elf_get_extr PARAMS ((asymbol *, EXTR *));
@@ -74,11 +76,16 @@ static void obj_elf_ident PARAMS ((int));
 static void obj_elf_weak PARAMS ((int));
 static void obj_elf_local PARAMS ((int));
 static void obj_elf_visibility PARAMS ((int));
+static void obj_elf_change_section
+  PARAMS ((const char *, int, int, int, const char *, int));
+static int obj_elf_parse_section_letters PARAMS ((char *, size_t));
+static int obj_elf_section_word PARAMS ((char *, size_t));
+static char *obj_elf_section_name PARAMS ((void));
+static int obj_elf_section_type PARAMS ((char *, size_t));
 static void obj_elf_symver PARAMS ((int));
-static void obj_elf_vtable_inherit PARAMS ((int));
-static void obj_elf_vtable_entry PARAMS ((int));
 static void obj_elf_subsection PARAMS ((int));
 static void obj_elf_popsection PARAMS ((int));
+static void obj_elf_tls_common PARAMS ((int));
 
 static const pseudo_typeS elf_pseudo_table[] =
 {
@@ -98,7 +105,7 @@ static const pseudo_typeS elf_pseudo_table[] =
   {"version", obj_elf_version, 0},
   {"weak", obj_elf_weak, 0},
 
-  /* These define symbol visibility. */
+  /* These define symbol visibility.  */
   {"internal", obj_elf_visibility, STV_INTERNAL},
   {"hidden", obj_elf_visibility, STV_HIDDEN},
   {"protected", obj_elf_visibility, STV_PROTECTED},
@@ -113,10 +120,10 @@ static const pseudo_typeS elf_pseudo_table[] =
   {"subsection", obj_elf_subsection, 0},
 
   /* These are GNU extensions to aid in garbage collecting C++ vtables.  */
-  {"vtable_inherit", obj_elf_vtable_inherit, 0},
-  {"vtable_entry", obj_elf_vtable_entry, 0},
+  {"vtable_inherit", (void (*) PARAMS ((int))) &obj_elf_vtable_inherit, 0},
+  {"vtable_entry", (void (*) PARAMS ((int))) &obj_elf_vtable_entry, 0},
 
-  /* These are used for dwarf. */
+  /* These are used for dwarf.  */
   {"2byte", cons, 2},
   {"4byte", cons, 4},
   {"8byte", cons, 8},
@@ -125,6 +132,8 @@ static const pseudo_typeS elf_pseudo_table[] =
   {"data", obj_elf_data, 0},
   {"text", obj_elf_text, 0},
 
+  {"tls_common", obj_elf_tls_common, 0},
+
   /* End sentinel.  */
   {NULL, NULL, 0},
 };
@@ -244,13 +253,6 @@ elf_s_set_other (sym, other)
   S_SET_OTHER (sym, other);
 }
 
-static void
-elf_copy_symbol_attributes (dest, src)
-     symbolS *dest, *src;
-{
-  OBJ_COPY_SYMBOL_ATTRIBUTES (dest, src);
-}
-
 static int
 elf_sec_sym_ok_for_reloc (sec)
      asection *sec;
@@ -282,8 +284,8 @@ elf_file_symbol (s)
 #endif
 }
 
-void
-obj_elf_common (is_common)
+static symbolS *
+elf_common (is_common)
      int is_common;
 {
   char *name;
@@ -296,7 +298,7 @@ obj_elf_common (is_common)
   if (flag_mri && is_common)
     {
       s_mri_common (0);
-      return;
+      return NULL;
     }
 
   name = input_line_pointer;
@@ -307,16 +309,16 @@ obj_elf_common (is_common)
   SKIP_WHITESPACE ();
   if (*input_line_pointer != ',')
     {
-      as_bad (_("Expected comma after symbol-name"));
+      as_bad (_("expected comma after symbol-name"));
       ignore_rest_of_line ();
-      return;
+      return NULL;
     }
   input_line_pointer++;                /* skip ',' */
   if ((temp = get_absolute_expression ()) < 0)
     {
       as_bad (_(".COMMon length (%d.) <0! Ignored."), temp);
       ignore_rest_of_line ();
-      return;
+      return NULL;
     }
   size = temp;
   *p = 0;
@@ -324,15 +326,15 @@ obj_elf_common (is_common)
   *p = c;
   if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP))
     {
-      as_bad (_("Ignoring attempt to re-define symbol"));
+      as_bad (_("symbol `%s' is already defined"), S_GET_NAME (symbolP));
       ignore_rest_of_line ();
-      return;
+      return NULL;
     }
   if (S_GET_VALUE (symbolP) != 0)
     {
       if (S_GET_VALUE (symbolP) != (valueT) size)
        {
-         as_warn (_("Length of .comm \"%s\" is already %ld. Not changed to %d."),
+         as_warn (_("length of .comm \"%s\" is already %ld; not changed to %d"),
                   S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), size);
        }
     }
@@ -355,7 +357,7 @@ obj_elf_common (is_common)
          if (temp < 0)
            {
              temp = 0;
-             as_warn (_("Common alignment negative; 0 assumed"));
+             as_warn (_("common alignment negative; 0 assumed"));
            }
        }
       if (symbol_get_obj (symbolP)->local)
@@ -374,9 +376,9 @@ obj_elf_common (is_common)
              for (align = 0; (temp & 1) == 0; temp >>= 1, ++align);
              if (temp != 1)
                {
-                 as_bad (_("Common alignment not a power of 2"));
+                 as_bad (_("common alignment not a power of 2"));
                  ignore_rest_of_line ();
-                 return;
+                 return NULL;
                }
            }
          else
@@ -428,7 +430,7 @@ obj_elf_common (is_common)
   symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT;
 
   demand_empty_rest_of_line ();
-  return;
+  return symbolP;
 
   {
   bad_common_segment:
@@ -441,10 +443,27 @@ obj_elf_common (is_common)
     *p = c;
     input_line_pointer = p;
     ignore_rest_of_line ();
-    return;
+    return NULL;
   }
 }
 
+void
+obj_elf_common (is_common)
+     int is_common;
+{
+  elf_common (is_common);
+}
+
+static void
+obj_elf_tls_common (ignore)
+     int ignore ATTRIBUTE_UNUSED;
+{
+  symbolS *symbolP = elf_common (0);
+
+  if (symbolP)
+    symbol_get_bfdsym (symbolP)->flags |= BSF_THREAD_LOCAL;
+}
+
 static void
 obj_elf_local (ignore)
      int ignore ATTRIBUTE_UNUSED;
@@ -544,7 +563,6 @@ obj_elf_visibility (visibility)
   demand_empty_rest_of_line ();
 }
 
-
 static segT previous_section;
 static int previous_subsection;
 
@@ -557,7 +575,6 @@ struct section_stack
 
 static struct section_stack *section_stack;
 
-
 /* Handle the .section pseudo-op.  This code supports two different
    syntaxes.
 
@@ -598,7 +615,30 @@ static struct special_section const special_sections[] =
   { ".note",   SHT_NOTE,       0                               },
   { ".rodata", SHT_PROGBITS,   SHF_ALLOC                       },
   { ".rodata1",        SHT_PROGBITS,   SHF_ALLOC                       },
+  { ".tbss",   SHT_NOBITS,     SHF_ALLOC + SHF_WRITE + SHF_TLS },
+  { ".tdata",  SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_TLS },
   { ".text",   SHT_PROGBITS,   SHF_ALLOC + SHF_EXECINSTR       },
+#if 0
+  /* FIXME: The current gcc, as of 2002-03-03, will emit
+
+       .section .init_array,"aw",@progbits
+
+     for __attribute__ ((section (".init_array"))). "@progbits" marks
+     the incorrect section type. For now, we make them with
+     SHT_PROGBITS. BFD will fix the section type. Gcc should be changed
+     to emit
+
+       .section .init_array
+
+   */
+  { ".init_array",SHT_INIT_ARRAY, SHF_ALLOC + SHF_WRITE         },
+  { ".fini_array",SHT_FINI_ARRAY, SHF_ALLOC + SHF_WRITE         },
+  { ".preinit_array",SHT_PREINIT_ARRAY, SHF_ALLOC + SHF_WRITE   },
+#else
+  { ".init_array",SHT_PROGBITS, SHF_ALLOC + SHF_WRITE         },
+  { ".fini_array",SHT_PROGBITS, SHF_ALLOC + SHF_WRITE         },
+  { ".preinit_array",SHT_PROGBITS, SHF_ALLOC + SHF_WRITE   },
+#endif
 
 #ifdef ELF_TC_SPECIAL_SECTIONS
   ELF_TC_SPECIAL_SECTIONS
@@ -623,10 +663,14 @@ static struct special_section const special_sections[] =
   { NULL,      0,              0                               }
 };
 
-void
-obj_elf_change_section (name, type, attr, push)
-     char *name;
-     int type, attr, push;
+static void
+obj_elf_change_section (name, type, attr, entsize, group_name, push)
+     const char *name;
+     int type;
+     int attr;
+     int entsize;
+     const char *group_name;
+     int push;
 {
   asection *old_sec;
   segT sec;
@@ -665,11 +709,11 @@ obj_elf_change_section (name, type, attr, push)
          {
            if (old_sec == NULL)
              {
-               as_warn (_("Setting incorrect section type for %s"), name);
+               as_warn (_("setting incorrect section type for %s"), name);
              }
            else
              {
-               as_warn (_("Ignoring incorrect section type for %s"), name);
+               as_warn (_("ignoring incorrect section type for %s"), name);
                type = special_sections[i].type;
              }
          }
@@ -682,7 +726,7 @@ obj_elf_change_section (name, type, attr, push)
               file.  */
            if (strcmp (name, ".note") != 0
                || attr != SHF_ALLOC)
-             as_warn (_("Setting incorrect section attributes for %s"),
+             as_warn (_("setting incorrect section attributes for %s"),
                       name);
          }
        attr |= special_sections[i].attributes;
@@ -694,7 +738,10 @@ obj_elf_change_section (name, type, attr, push)
           | ((attr & SHF_WRITE) ? 0 : SEC_READONLY)
           | ((attr & SHF_ALLOC) ? SEC_ALLOC : 0)
           | (((attr & SHF_ALLOC) && type != SHT_NOBITS) ? SEC_LOAD : 0)
-          | ((attr & SHF_EXECINSTR) ? SEC_CODE : 0));
+          | ((attr & SHF_EXECINSTR) ? SEC_CODE : 0)
+          | ((attr & SHF_MERGE) ? SEC_MERGE : 0)
+          | ((attr & SHF_STRINGS) ? SEC_STRINGS : 0)
+          | ((attr & SHF_TLS) ? SEC_THREAD_LOCAL : 0));
 #ifdef md_elf_section_flags
   flags = md_elf_section_flags (flags, attr, type);
 #endif
@@ -708,6 +755,9 @@ obj_elf_change_section (name, type, attr, push)
         seg_info (sec)->bss = 1;
 
       bfd_set_section_flags (stdoutput, sec, flags);
+      if (flags & SEC_MERGE)
+       sec->entsize = entsize;
+      elf_group_name (sec) = group_name;
 
       /* Add a symbol for this section to the symbol table.  */
       secsym = symbol_find (name);
@@ -723,8 +773,14 @@ obj_elf_change_section (name, type, attr, push)
         saw the first time.  */
       if ((old_sec->flags ^ flags)
          & (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
-            | SEC_EXCLUDE | SEC_SORT_ENTRIES))
-       as_warn (_("Ignoring changed section attributes for %s"), name);
+            | SEC_EXCLUDE | SEC_SORT_ENTRIES | SEC_MERGE | SEC_STRINGS
+            | SEC_THREAD_LOCAL))
+       as_warn (_("ignoring changed section attributes for %s"), name);
+      else if ((flags & SEC_MERGE) && old_sec->entsize != (unsigned) entsize)
+       as_warn (_("ignoring changed section entity size for %s"), name);
+      else if ((attr & SHF_GROUP) != 0
+              && strcmp (elf_group_name (old_sec), group_name) != 0)
+       as_warn (_("ignoring new section group for %s"), name);
     }
 
 #ifdef md_elf_section_change_hook
@@ -732,7 +788,7 @@ obj_elf_change_section (name, type, attr, push)
 #endif
 }
 
-int
+static int
 obj_elf_parse_section_letters (str, len)
      char *str;
      size_t len;
@@ -752,9 +808,33 @@ obj_elf_parse_section_letters (str, len)
        case 'x':
          attr |= SHF_EXECINSTR;
          break;
+       case 'M':
+         attr |= SHF_MERGE;
+         break;
+       case 'S':
+         attr |= SHF_STRINGS;
+         break;
+       case 'G':
+         attr |= SHF_GROUP;
+         break;
+       case 'T':
+         attr |= SHF_TLS;
+         break;
+       /* Compatibility.  */
+       case 'm':
+         if (*(str - 1) == 'a')
+           {
+             attr |= SHF_MERGE;
+             if (len > 1 && str[1] == 's')
+               {
+                 attr |= SHF_STRINGS;
+                 str++, len--;
+               }
+             break;
+           }
        default:
          {
-           char *bad_msg = _("Unrecognized .section attribute: want a,w,x");
+           char *bad_msg = _("unrecognized .section attribute: want a,w,x,M,S,G,T");
 #ifdef md_elf_section_letter
            int md_attr = md_elf_section_letter (*str, &bad_msg);
            if (md_attr >= 0)
@@ -774,7 +854,7 @@ obj_elf_parse_section_letters (str, len)
   return attr;
 }
 
-int
+static int
 obj_elf_section_word (str, len)
      char *str;
      size_t len;
@@ -794,11 +874,11 @@ obj_elf_section_word (str, len)
   }
 #endif
 
-  as_warn (_("Unrecognized section attribute"));
+  as_warn (_("unrecognized section attribute"));
   return 0;
 }
 
-int
+static int
 obj_elf_section_type (str, len)
      char *str;
      size_t len;
@@ -816,16 +896,57 @@ obj_elf_section_type (str, len)
   }
 #endif
 
-  as_warn (_("Unrecognized section type"));
+  as_warn (_("unrecognized section type"));
   return 0;
 }
 
+/* Get name of section.  */
+static char *
+obj_elf_section_name ()
+{
+  char *name;
+
+  SKIP_WHITESPACE ();
+  if (*input_line_pointer == '"')
+    {
+      int dummy;
+
+      name = demand_copy_C_string (&dummy);
+      if (name == NULL)
+       {
+         ignore_rest_of_line ();
+         return NULL;
+       }
+    }
+  else
+    {
+      char *end = input_line_pointer;
+
+      while (0 == strchr ("\n\t,; ", *end))
+       end++;
+      if (end == input_line_pointer)
+       {
+         as_warn (_("missing name"));
+         ignore_rest_of_line ();
+         return NULL;
+       }
+
+      name = xmalloc (end - input_line_pointer + 1);
+      memcpy (name, input_line_pointer, end - input_line_pointer);
+      name[end - input_line_pointer] = '\0';
+      input_line_pointer = end;
+    }
+  SKIP_WHITESPACE ();
+  return name;
+}
+
 void
 obj_elf_section (push)
      int push;
 {
-  char *name, *beg, *end;
+  char *name, *group_name, *beg;
   int type, attr, dummy;
+  int entsize;
 
 #ifndef TC_I370
   if (flag_mri)
@@ -849,38 +970,13 @@ obj_elf_section (push)
     }
 #endif /* ! defined (TC_I370) */
 
-  /* Get name of section.  */
-  SKIP_WHITESPACE ();
-  if (*input_line_pointer == '"')
-    {
-      name = demand_copy_C_string (&dummy);
-      if (name == NULL)
-       {
-         ignore_rest_of_line ();
-         return;
-       }
-    }
-  else
-    {
-      end = input_line_pointer;
-      while (0 == strchr ("\n\t,; ", *end))
-       end++;
-      if (end == input_line_pointer)
-       {
-         as_warn (_("Missing section name"));
-         ignore_rest_of_line ();
-         return;
-       }
-
-      name = xmalloc (end - input_line_pointer + 1);
-      memcpy (name, input_line_pointer, end - input_line_pointer);
-      name[end - input_line_pointer] = '\0';
-      input_line_pointer = end;
-    }
-  SKIP_WHITESPACE ();
-
+  name = obj_elf_section_name ();
+  if (name == NULL)
+    return;
   type = SHT_NULL;
   attr = 0;
+  group_name = NULL;
+  entsize = 0;
 
   if (*input_line_pointer == ',')
     {
@@ -902,6 +998,8 @@ obj_elf_section (push)
          if (*input_line_pointer == ',')
            {
              char c;
+             char *save = input_line_pointer;
+
              ++input_line_pointer;
              SKIP_WHITESPACE ();
              c = *input_line_pointer;
@@ -922,6 +1020,41 @@ obj_elf_section (push)
                  *input_line_pointer = c;
                  type = obj_elf_section_type (beg, input_line_pointer - beg);
                }
+             else
+               input_line_pointer = save;
+           }
+
+         SKIP_WHITESPACE ();
+         if ((attr & SHF_MERGE) != 0 && *input_line_pointer == ',')
+           {
+             ++input_line_pointer;
+             SKIP_WHITESPACE ();
+             entsize = get_absolute_expression ();
+             SKIP_WHITESPACE ();
+             if (entsize < 0)
+               {
+                 as_warn (_("invalid merge entity size"));
+                 attr &= ~SHF_MERGE;
+                 entsize = 0;
+               }
+           }
+         else if ((attr & SHF_MERGE) != 0)
+           {
+             as_warn (_("entity size for SHF_MERGE not specified"));
+             attr &= ~SHF_MERGE;
+           }
+
+         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 ((attr & SHF_GROUP) != 0)
+           {
+             as_warn (_("group name for SHF_GROUP not specified"));
+             attr &= ~SHF_GROUP;
            }
        }
       else
@@ -933,7 +1066,7 @@ obj_elf_section (push)
              SKIP_WHITESPACE ();
              if (*input_line_pointer != '#')
                {
-                 as_warn (_("Bad .section directive - character following name is not '#'"));
+                 as_warn (_("character following name is not '#'"));
                  ignore_rest_of_line ();
                  return;
                }
@@ -952,7 +1085,7 @@ obj_elf_section (push)
 
   demand_empty_rest_of_line ();
 
-  obj_elf_change_section (name, type, attr, push);
+  obj_elf_change_section (name, type, attr, entsize, group_name, push);
 }
 
 /* Change to the .data section.  */
@@ -1034,7 +1167,7 @@ obj_elf_previous (ignore)
 
   if (previous_section == 0)
     {
-      as_bad (_(".previous without corresponding .section; ignored"));
+      as_warn (_(".previous without corresponding .section; ignored"));
       return;
     }
 
@@ -1061,7 +1194,7 @@ obj_elf_popsection (xxx)
 
   if (top == NULL)
     {
-      as_bad (_(".popsection without corresponding .pushsection; ignored"));
+      as_warn (_(".popsection without corresponding .pushsection; ignored"));
       return;
     }
 
@@ -1085,7 +1218,7 @@ obj_elf_line (ignore)
      int ignore ATTRIBUTE_UNUSED;
 {
   /* Assume delimiter is part of expression.  BSD4.2 as fails with
-     delightful bug, so we are not being incompatible here. */
+     delightful bug, so we are not being incompatible here.  */
   new_logical_line ((char *) NULL, (int) (get_absolute_expression ()));
   demand_empty_rest_of_line ();
 }
@@ -1102,6 +1235,7 @@ obj_elf_symver (ignore)
 {
   char *name;
   char c;
+  char old_lexat;
   symbolS *sym;
 
   name = input_line_pointer;
@@ -1111,14 +1245,6 @@ obj_elf_symver (ignore)
 
   *input_line_pointer = c;
 
-  if (symbol_get_obj (sym)->versioned_name != NULL)
-    {
-      as_bad (_("multiple .symver directives for symbol `%s'"),
-             S_GET_NAME (sym));
-      ignore_rest_of_line ();
-      return;
-    }
-
   SKIP_WHITESPACE ();
   if (*input_line_pointer != ',')
     {
@@ -1129,24 +1255,41 @@ obj_elf_symver (ignore)
 
   ++input_line_pointer;
   name = input_line_pointer;
-  while (1)
-    {
-      c = get_symbol_end ();
-      if (c != ELF_VER_CHR)
-       break;
-      *input_line_pointer++ = c;
-    }
 
-  symbol_get_obj (sym)->versioned_name = xstrdup (name);
+  /* Temporarily include '@' in symbol names.  */
+  old_lexat = lex_type[(unsigned char) '@'];
+  lex_type[(unsigned char) '@'] |= LEX_NAME;
+  c = get_symbol_end ();
+  lex_type[(unsigned char) '@'] = old_lexat;
 
-  *input_line_pointer = c;
+  if (symbol_get_obj (sym)->versioned_name == NULL)
+    {
+      symbol_get_obj (sym)->versioned_name = xstrdup (name);
 
-  if (strchr (symbol_get_obj (sym)->versioned_name, ELF_VER_CHR) == NULL)
+      *input_line_pointer = c;
+
+      if (strchr (symbol_get_obj (sym)->versioned_name,
+                 ELF_VER_CHR) == NULL)
+       {
+         as_bad (_("missing version name in `%s' for symbol `%s'"),
+                 symbol_get_obj (sym)->versioned_name,
+                 S_GET_NAME (sym));
+         ignore_rest_of_line ();
+         return;
+       }
+    }
+  else
     {
-      as_bad (_("missing version name in `%s' for symbol `%s'"),
-             symbol_get_obj (sym)->versioned_name, S_GET_NAME (sym));
-      ignore_rest_of_line ();
-      return;
+      if (strcmp (symbol_get_obj (sym)->versioned_name, name))
+       {
+         as_bad (_("multiple versions [`%s'|`%s'] for symbol `%s'"),
+                 name, symbol_get_obj (sym)->versioned_name,
+                 S_GET_NAME (sym));
+         ignore_rest_of_line ();
+         return;
+       }
+
+      *input_line_pointer = c;
     }
 
   demand_empty_rest_of_line ();
@@ -1156,7 +1299,7 @@ obj_elf_symver (ignore)
    to the linker the hierarchy in which a particular table resides.  The
    syntax is ".vtable_inherit CHILDNAME, PARENTNAME".  */
 
-static void
+struct fix *
 obj_elf_vtable_inherit (ignore)
      int ignore ATTRIBUTE_UNUSED;
 {
@@ -1189,7 +1332,7 @@ obj_elf_vtable_inherit (ignore)
     {
       as_bad ("expected comma after name in .vtable_inherit");
       ignore_rest_of_line ();
-      return;
+      return NULL;
     }
 
   ++input_line_pointer;
@@ -1200,7 +1343,7 @@ obj_elf_vtable_inherit (ignore)
 
   if (input_line_pointer[0] == '0'
       && (input_line_pointer[1] == '\0'
-         || isspace ((unsigned char) input_line_pointer[1])))
+         || ISSPACE (input_line_pointer[1])))
     {
       psym = section_symbol (absolute_section);
       ++input_line_pointer;
@@ -1216,19 +1359,19 @@ obj_elf_vtable_inherit (ignore)
   demand_empty_rest_of_line ();
 
   if (bad)
-    return;
+    return NULL;
 
   assert (symbol_get_value_expression (csym)->X_op == O_constant);
-  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);
 }
 
 /* This handles the .vtable_entry pseudo-op, which is used to indicate
    to the linker that a vtable slot was used.  The syntax is
    ".vtable_entry tablename, offset".  */
 
-static void
+struct fix *
 obj_elf_vtable_entry (ignore)
      int ignore ATTRIBUTE_UNUSED;
 {
@@ -1250,7 +1393,7 @@ obj_elf_vtable_entry (ignore)
     {
       as_bad ("expected comma after name in .vtable_entry");
       ignore_rest_of_line ();
-      return;
+      return NULL;
     }
 
   ++input_line_pointer;
@@ -1259,10 +1402,10 @@ obj_elf_vtable_entry (ignore)
 
   offset = get_absolute_expression ();
 
-  fix_new (frag_now, frag_now_fix (), 0, sym, offset, 0,
-          BFD_RELOC_VTABLE_ENTRY);
-
   demand_empty_rest_of_line ();
+
+  return fix_new (frag_now, frag_now_fix (), 0, sym, offset, 0,
+                 BFD_RELOC_VTABLE_ENTRY);
 }
 
 void
@@ -1290,25 +1433,53 @@ elf_obj_symbol_new_hook (symbolP)
 #endif
 }
 
+/* When setting one symbol equal to another, by default we probably
+   want them to have the same "size", whatever it means in the current
+   context.  */
+
+void
+elf_copy_symbol_attributes (dest, src)
+     symbolS *dest, *src;
+{
+  struct elf_obj_sy *srcelf = symbol_get_obj (src);
+  struct elf_obj_sy *destelf = symbol_get_obj (dest);
+  if (srcelf->size)
+    {
+      if (destelf->size == NULL)
+       destelf->size =
+         (expressionS *) xmalloc (sizeof (expressionS));
+      *destelf->size = *srcelf->size;
+    }
+  else
+    {
+      if (destelf->size != NULL)
+       free (destelf->size);
+      destelf->size = NULL;
+    }
+  S_SET_SIZE (dest, S_GET_SIZE (src));
+  /* Don't copy visibility.  */
+  S_SET_OTHER (dest, (ELF_ST_VISIBILITY (S_GET_OTHER (dest))
+                     | (S_GET_OTHER (src) & ~ELF_ST_VISIBILITY (-1))));
+}
+
 void
 obj_elf_version (ignore)
      int ignore ATTRIBUTE_UNUSED;
 {
   char *name;
   unsigned int c;
-  char ch;
   char *p;
   asection *seg = now_seg;
   subsegT subseg = now_subseg;
   Elf_Internal_Note i_note;
   Elf_External_Note e_note;
   asection *note_secp = (asection *) NULL;
-  int i, len;
+  int len;
 
   SKIP_WHITESPACE ();
   if (*input_line_pointer == '\"')
     {
-      ++input_line_pointer;    /* -> 1st char of string. */
+      ++input_line_pointer;    /* -> 1st char of string.  */
       name = input_line_pointer;
 
       while (is_a_char (c = next_char_of_string ()))
@@ -1333,26 +1504,21 @@ obj_elf_version (ignore)
       i_note.descsz = 0;       /* no description */
       i_note.type = NT_VERSION;
       p = frag_more (sizeof (e_note.namesz));
-      md_number_to_chars (p, (valueT) i_note.namesz, 4);
+      md_number_to_chars (p, (valueT) i_note.namesz, sizeof (e_note.namesz));
       p = frag_more (sizeof (e_note.descsz));
-      md_number_to_chars (p, (valueT) i_note.descsz, 4);
+      md_number_to_chars (p, (valueT) i_note.descsz, sizeof (e_note.descsz));
       p = frag_more (sizeof (e_note.type));
-      md_number_to_chars (p, (valueT) i_note.type, 4);
+      md_number_to_chars (p, (valueT) i_note.type, sizeof (e_note.type));
+      p = frag_more (len + 1);
+      strcpy (p, name);
 
-      for (i = 0; i < len; i++)
-       {
-         ch = *(name + i);
-         {
-           FRAG_APPEND_1_CHAR (ch);
-         }
-       }
       frag_align (2, 0, 0);
 
       subseg_set (seg, subseg);
     }
   else
     {
-      as_bad (_("Expected quoted string"));
+      as_bad (_("expected quoted string"));
     }
   demand_empty_rest_of_line ();
 }
@@ -1390,7 +1556,14 @@ obj_elf_size (ignore)
   sym = symbol_find_or_make (name);
   *p = c;
   if (exp.X_op == O_constant)
-    S_SET_SIZE (sym, exp.X_add_number);
+    {
+      S_SET_SIZE (sym, exp.X_add_number);
+      if (symbol_get_obj (sym)->size)
+       {
+         xfree (symbol_get_obj (sym)->size);
+         symbol_get_obj (sym)->size = NULL;
+       }
+    }
   else
     {
       symbol_get_obj (sym)->size =
@@ -1401,7 +1574,7 @@ obj_elf_size (ignore)
 }
 
 /* Handle the ELF .type pseudo-op.  This sets the type of a symbol.
-   There are four syntaxes:
+   There are five syntaxes:
 
    The first (used on Solaris) is
        .type SYM,#function
@@ -1411,6 +1584,8 @@ obj_elf_size (ignore)
        .type SYM STT_FUNC
    The fourth (used on NetBSD/Arm and Linux/ARM) is
        .type SYM,%function
+   The fifth (used on SVR4/860) is
+       .type SYM,"function"
    */
 
 static void
@@ -1422,10 +1597,12 @@ obj_elf_type (ignore)
   int type;
   const char *typename;
   symbolS *sym;
+  elf_symbol_type *elfsym;
 
   name = input_line_pointer;
   c = get_symbol_end ();
   sym = symbol_find_or_make (name);
+  elfsym = (elf_symbol_type *) symbol_get_bfdsym (sym);
   *input_line_pointer = c;
 
   SKIP_WHITESPACE ();
@@ -1435,6 +1612,7 @@ obj_elf_type (ignore)
   SKIP_WHITESPACE ();
   if (   *input_line_pointer == '#'
       || *input_line_pointer == '@'
+      || *input_line_pointer == '"'
       || *input_line_pointer == '%')
     ++input_line_pointer;
 
@@ -1448,12 +1626,19 @@ obj_elf_type (ignore)
   else if (strcmp (typename, "object") == 0
           || strcmp (typename, "STT_OBJECT") == 0)
     type = BSF_OBJECT;
+#ifdef md_elf_symbol_type
+  else if ((type = md_elf_symbol_type (typename, sym, elfsym)) != -1)
+    ;
+#endif
   else
-    as_bad (_("ignoring unrecognized symbol type \"%s\""), typename);
+    as_bad (_("unrecognized symbol type \"%s\""), typename);
 
   *input_line_pointer = c;
 
-  symbol_get_bfdsym (sym)->flags |= type;
+  if (*input_line_pointer == '"')
+    ++input_line_pointer;
+
+  elfsym->symbol.flags |= type;
 
   demand_empty_rest_of_line ();
 }
@@ -1502,12 +1687,12 @@ obj_elf_init_stab_section (seg)
      UnixWare ar crashes.  */
   bfd_set_section_alignment (stdoutput, seg, 2);
 
-  /* Make space for this first symbol. */
+  /* Make space for this first symbol.  */
   p = frag_more (12);
-  /* Zero it out. */
+  /* Zero it out.  */
   memset (p, 0, 12);
   as_where (&file, (unsigned int *) NULL);
-  stabstr_name = (char *) alloca (strlen (segment_name (seg)) + 4);
+  stabstr_name = (char *) xmalloc (strlen (segment_name (seg)) + 4);
   strcpy (stabstr_name, segment_name (seg));
   strcat (stabstr_name, "str");
   stroff = get_stab_string_offset (file, stabstr_name);
@@ -1636,6 +1821,11 @@ elf_frob_symbol (symp, puntp)
 
   if (sy_obj->versioned_name != NULL)
     {
+      char *p;
+
+      p = strchr (sy_obj->versioned_name, ELF_VER_CHR);
+      know (p != NULL);
+
       /* This symbol was given a new name with the .symver directive.
 
          If this is an external reference, just rename the symbol to
@@ -1649,13 +1839,9 @@ elf_frob_symbol (symp, puntp)
 
       if (! S_IS_DEFINED (symp))
        {
-         char *p;
-
          /* Verify that the name isn't using the @@ syntax--this is
              reserved for definitions of the default version to link
              against.  */
-         p = strchr (sy_obj->versioned_name, ELF_VER_CHR);
-         know (p != NULL);
          if (p[1] == ELF_VER_CHR)
            {
              as_bad (_("invalid attempt to declare external version name as default in symbol `%s'"),
@@ -1666,36 +1852,52 @@ elf_frob_symbol (symp, puntp)
        }
       else
        {
-         symbolS *symp2;
+         if (p [1] == ELF_VER_CHR && p [2] == ELF_VER_CHR)
+           {
+             size_t l;
 
-         /* FIXME: Creating a new symbol here is risky.  We're in the
-             final loop over the symbol table.  We can get away with
-             it only because the symbol goes to the end of the list,
-             where the loop will still see it.  It would probably be
-             better to do this in obj_frob_file_before_adjust. */
+             /* The @@@ syntax is a special case. It renames the
+                symbol name to versioned_name with one `@' removed.  */
+             l = strlen (&p[3]) + 1;
+             memmove (&p [2], &p[3], l);
+             S_SET_NAME (symp, sy_obj->versioned_name);
+           }
+         else
+           {
+             symbolS *symp2;
 
-         symp2 = symbol_find_or_make (sy_obj->versioned_name);
+             /* FIXME: Creating a new symbol here is risky.  We're
+                in the final loop over the symbol table.  We can
+                get away with it only because the symbol goes to
+                the end of the list, where the loop will still see
+                it.  It would probably be better to do this in
+                obj_frob_file_before_adjust.  */
 
-         /* Now we act as though we saw symp2 = sym.  */
+             symp2 = symbol_find_or_make (sy_obj->versioned_name);
 
-         S_SET_SEGMENT (symp2, S_GET_SEGMENT (symp));
+             /* Now we act as though we saw symp2 = sym.  */
 
-         /* Subtracting out the frag address here is a hack because
-             we are in the middle of the final loop.  */
-         S_SET_VALUE (symp2,
-                      (S_GET_VALUE (symp)
-                       - symbol_get_frag (symp)->fr_address));
+             S_SET_SEGMENT (symp2, S_GET_SEGMENT (symp));
 
-         symbol_set_frag (symp2, symbol_get_frag (symp));
+             /* Subtracting out the frag address here is a hack
+                because we are in the middle of the final loop.  */
+             S_SET_VALUE (symp2,
+                          (S_GET_VALUE (symp)
+                           - symbol_get_frag (symp)->fr_address));
 
-         /* This will copy over the size information.  */
-         copy_symbol_attributes (symp2, symp);
+             symbol_set_frag (symp2, symbol_get_frag (symp));
 
-         if (S_IS_WEAK (symp))
-           S_SET_WEAK (symp2);
+             /* This will copy over the size information.  */
+             copy_symbol_attributes (symp2, symp);
 
-         if (S_IS_EXTERNAL (symp))
-           S_SET_EXTERNAL (symp2);
+             S_SET_OTHER (symp2, S_GET_OTHER (symp));
+
+             if (S_IS_WEAK (symp))
+               S_SET_WEAK (symp2);
+
+             if (S_IS_EXTERNAL (symp))
+               S_SET_EXTERNAL (symp2);
+           }
        }
     }
 
@@ -1703,7 +1905,7 @@ elf_frob_symbol (symp, puntp)
   if (S_IS_WEAK (symp))
     {
       if (S_IS_COMMON (symp))
-       as_bad (_("Symbol `%s' can not be both weak and common"),
+       as_bad (_("symbol `%s' can not be both weak and common"),
                S_GET_NAME (symp));
     }
 
@@ -1736,16 +1938,150 @@ elf_frob_symbol (symp, puntp)
 #endif
 }
 
+struct group_list
+{
+  asection **head;             /* Section lists.  */
+  unsigned int *elt_count;     /* Number of sections in each list.  */
+  unsigned int num_group;      /* Number of lists.  */
+};
+
+/* Called via bfd_map_over_sections.  If SEC is a member of a group,
+   add it to a list of sections belonging to the group.  INF is a
+   pointer to a struct group_list, which is where we store the head of
+   each list.  */
+
+static void
+build_group_lists (abfd, sec, inf)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *sec;
+     PTR inf;
+{
+  struct group_list *list = (struct group_list *) inf;
+  const char *group_name = elf_group_name (sec);
+  unsigned int i;
+
+  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++)
+    {
+      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;
+       }
+    }
+
+  /* New group.  Make the arrays bigger in chunks to minimize calls to
+     realloc.  */
+  i = list->num_group;
+  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[i] = sec;
+  list->elt_count[i] = 1;
+  list->num_group += 1;
+}
+
 void
 elf_frob_file ()
 {
+  struct group_list list;
+  unsigned int i;
+
   bfd_map_over_sections (stdoutput, adjust_stab_sections, (PTR) 0);
 
+  /* Go find section groups.  */
+  list.num_group = 0;
+  list.head = NULL;
+  list.elt_count = NULL;
+  bfd_map_over_sections (stdoutput, build_group_lists, (PTR) &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++)
+    {
+      const char *group_name = elf_group_name (list.head[i]);
+      asection *s;
+      flagword flags;
+
+      s = subseg_force_new (group_name, 0);
+      flags = SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_GROUP;
+      if (s == NULL
+         || !bfd_set_section_flags (stdoutput, s, flags)
+         || !bfd_set_section_alignment (stdoutput, s, 2))
+       {
+         as_fatal (_("can't create group: %s"),
+                   bfd_errmsg (bfd_get_error ()));
+       }
+
+      /* Pass a pointer to the first section in this group.  */
+      elf_next_in_group (s) = list.head[i];
+
+      s->_raw_size = 4 * (list.elt_count[i] + 1);
+      s->contents = frag_more (s->_raw_size);
+      frag_now->fr_fix = frag_now_fix_octets ();
+    }
+
 #ifdef elf_tc_final_processing
   elf_tc_final_processing ();
 #endif
 }
 
+/* It removes any unneeded versioned symbols from the symbol table.  */
+
+void
+elf_frob_file_before_adjust ()
+{
+  if (symbol_rootP)
+    {
+      symbolS *symp;
+
+      for (symp = symbol_rootP; symp; symp = symbol_next (symp))
+       if (!S_IS_DEFINED (symp))
+         {
+           if (symbol_get_obj (symp)->versioned_name)
+             {
+               char *p;
+
+               /* The @@@ syntax is a special case. If the symbol is
+                  not defined, 2 `@'s will be removed from the
+                  versioned_name.  */
+
+               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)
+                 {
+                   size_t l = strlen (&p[3]) + 1;
+                   memmove (&p [1], &p[3], l);
+                 }
+               if (symbol_used_p (symp) == 0
+                   && symbol_used_in_reloc_p (symp) == 0)
+                 symbol_remove (symp, &symbol_rootP, &symbol_lastP);
+             }
+
+           /* If there was .weak foo, but foo was neither defined nor
+              used anywhere, remove it.  */
+
+           else if (S_IS_WEAK (symp)
+                    && symbol_used_p (symp) == 0
+                    && symbol_used_in_reloc_p (symp) == 0)
+             symbol_remove (symp, &symbol_rootP, &symbol_lastP);
+         }
+    }
+}
+
 /* It is required that we let write_relocs have the opportunity to
    optimize away fixups before output has begun, since it is possible
    to eliminate all fixups for a section and thus we never should
@@ -1790,7 +2126,7 @@ elf_frob_file_after_relocs ()
       debug.external_ext = debug.external_ext_end = NULL;
       if (! bfd_ecoff_debug_externals (stdoutput, &debug, debug_swap, true,
                                       elf_get_extr, elf_set_index))
-       as_fatal (_("Failed to set up debugging information: %s"),
+       as_fatal (_("failed to set up debugging information: %s"),
                  bfd_errmsg (bfd_get_error ()));
 
       sec = bfd_get_section_by_name (stdoutput, ".mdebug");
@@ -1810,7 +2146,7 @@ elf_frob_file_after_relocs ()
          pointer will not be used.  */
       if (! bfd_set_section_contents (stdoutput, sec, (PTR) buf,
                                      (file_ptr) 0, (bfd_size_type) 0))
-       as_fatal (_("Can't start writing .mdebug section: %s"),
+       as_fatal (_("can't start writing .mdebug section: %s"),
                  bfd_errmsg (bfd_get_error ()));
 
       know (stdoutput->output_has_begun == true);
@@ -1818,7 +2154,7 @@ elf_frob_file_after_relocs ()
 
       if (! bfd_ecoff_write_debug (stdoutput, &debug, debug_swap,
                                   sec->filepos))
-       as_fatal (_("Could not write .mdebug section: %s"),
+       as_fatal (_("could not write .mdebug section: %s"),
                  bfd_errmsg (bfd_get_error ()));
     }
 #endif /* NEED_ECOFF_DEBUG */
@@ -1950,6 +2286,7 @@ const struct format_ops elf_format_ops =
   elf_file_symbol,
   elf_frob_symbol,
   elf_frob_file,
+  elf_frob_file_before_adjust,
   elf_frob_file_after_relocs,
   elf_s_get_size, elf_s_set_size,
   elf_s_get_align, elf_s_set_align,
This page took 0.058569 seconds and 4 git commands to generate.