* read.c (potable): Add string8, string16, string32 and string64. Add bit size for...
[binutils-gdb.git] / gas / config / obj-elf.c
index 7bd62d769d4e60df9884fac9cfd7baf6ef866153..8f696d77202325d7af4c3efc188cc4bad448d5e9 100644 (file)
@@ -1,12 +1,13 @@
 /* ELF object file format
    Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003 Free Software Foundation, Inc.
+   2001, 2002, 2003, 2004, 2005, 2006, 2007
+   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
-   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
@@ -16,8 +17,8 @@
 
    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.  */
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
 
 #define OBJ_HEADER "obj-elf.h"
 #include "as.h"
 #include "elf/i370.h"
 #endif
 
+#ifdef TC_I386
+#include "elf/x86-64.h"
+#endif
+
+#ifdef TC_MEP
+#include "elf/mep.h"
+#endif
+
 static void obj_elf_line (int);
 static void obj_elf_size (int);
 static void obj_elf_type (int);
@@ -65,6 +74,7 @@ static void obj_elf_subsection (int);
 static void obj_elf_popsection (int);
 static void obj_elf_tls_common (int);
 static void obj_elf_lcomm (int);
+static void obj_elf_struct (int);
 
 static const pseudo_typeS elf_pseudo_table[] =
 {
@@ -110,9 +120,12 @@ static const pseudo_typeS elf_pseudo_table[] =
   /* These are used for dwarf2.  */
   { "file", (void (*) (int)) dwarf2_directive_file, 0 },
   { "loc",  dwarf2_directive_loc,  0 },
+  { "loc_mark_labels", dwarf2_directive_loc_mark_labels, 0 },
 
   /* We need to trap the section changing calls to handle .previous.  */
   {"data", obj_elf_data, 0},
+  {"offset", obj_elf_struct, 0},
+  {"struct", obj_elf_struct, 0},
   {"text", obj_elf_text, 0},
 
   {"tls_common", obj_elf_tls_common, 0},
@@ -171,6 +184,8 @@ static const pseudo_typeS ecoff_debug_pseudo_table[] =
 
 /* This is called when the assembler starts.  */
 
+asection *elf_com_section_ptr;
+
 void
 elf_begin (void)
 {
@@ -183,6 +198,7 @@ elf_begin (void)
   symbol_table_insert (section_symbol (s));
   s = bfd_get_section_by_name (stdoutput, BSS_SECTION_NAME);
   symbol_table_insert (section_symbol (s));
+  elf_com_section_ptr = bfd_com_section_ptr;
 }
 
 void
@@ -236,32 +252,38 @@ elf_sec_sym_ok_for_reloc (asection *sec)
 }
 
 void
-elf_file_symbol (const char *s)
+elf_file_symbol (const char *s, int appfile)
 {
-  symbolS *sym;
+  if (!appfile
+      || symbol_rootP == NULL
+      || symbol_rootP->bsym == NULL
+      || (symbol_rootP->bsym->flags & BSF_FILE) == 0)
+    {
+      symbolS *sym;
 
-  sym = symbol_new (s, absolute_section, 0, NULL);
-  symbol_set_frag (sym, &zero_address_frag);
-  symbol_get_bfdsym (sym)->flags |= BSF_FILE;
+      sym = symbol_new (s, absolute_section, 0, NULL);
+      symbol_set_frag (sym, &zero_address_frag);
+      symbol_get_bfdsym (sym)->flags |= BSF_FILE;
 
-  if (symbol_rootP != sym)
-    {
-      symbol_remove (sym, &symbol_rootP, &symbol_lastP);
-      symbol_insert (sym, symbol_rootP, &symbol_rootP, &symbol_lastP);
+      if (symbol_rootP != sym)
+       {
+         symbol_remove (sym, &symbol_rootP, &symbol_lastP);
+         symbol_insert (sym, symbol_rootP, &symbol_rootP, &symbol_lastP);
 #ifdef DEBUG
-      verify_symbol_chain (symbol_rootP, symbol_lastP);
+         verify_symbol_chain (symbol_rootP, symbol_lastP);
 #endif
+       }
     }
 
 #ifdef NEED_ECOFF_DEBUG
-  ecoff_new_file (s);
+  ecoff_new_file (s, appfile);
 #endif
 }
 
 /* Called from read.c:s_comm after we've parsed .comm symbol, size.
    Parse a possible alignment value.  */
 
-static symbolS *
+symbolS *
 elf_common_parse (int ignore ATTRIBUTE_UNUSED, symbolS *symbolP, addressT size)
 {
   addressT align = 0;
@@ -325,7 +347,7 @@ elf_common_parse (int ignore ATTRIBUTE_UNUSED, symbolS *symbolP, addressT size)
       S_SET_VALUE (symbolP, size);
       S_SET_ALIGN (symbolP, align);
       S_SET_EXTERNAL (symbolP);
-      S_SET_SEGMENT (symbolP, bfd_com_section_ptr);
+      S_SET_SEGMENT (symbolP, elf_com_section_ptr);
     }
 
   symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT;
@@ -511,6 +533,7 @@ obj_elf_change_section (const char *name,
   asection *old_sec;
   segT sec;
   flagword flags;
+  const struct elf_backend_data *bed;
   const struct bfd_elf_special_section *ssect;
 
 #ifdef md_flush_pending_output
@@ -542,7 +565,8 @@ obj_elf_change_section (const char *name,
   else
     sec = subseg_force_new (name, 0);
 
-  ssect = _bfd_elf_get_sec_type_attr (stdoutput, name);
+  bed = get_elf_backend_data (stdoutput);
+  ssect = (*bed->get_sec_type_attr) (stdoutput, sec);
 
   if (ssect != NULL)
     {
@@ -558,7 +582,16 @@ obj_elf_change_section (const char *name,
                 .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
+
+                .section .lbss,"aw",@progbits
+
                 "@progbits" is incorrect.  */
+#ifdef TC_I386
+             && (bed->s->arch_size != 64
+                 || !(ssect->attr & SHF_X86_64_LARGE))
+#endif
              && ssect->type != SHT_INIT_ARRAY
              && ssect->type != SHT_FINI_ARRAY
              && ssect->type != SHT_PREINIT_ARRAY)
@@ -600,6 +633,15 @@ obj_elf_change_section (const char *name,
                       || strcmp (name, ".strtab") == 0
                       || strcmp (name, ".symtab") == 0))
            override = TRUE;
+         /* .note.GNU-stack can have SHF_EXECINSTR.  */
+         else if (attr == SHF_EXECINSTR
+                  && strcmp (name, ".note.GNU-stack") == 0)
+           override = TRUE;
+#ifdef TC_ALPHA
+         /* A section on Alpha may have SHF_ALPHA_GPREL.  */
+         else if ((attr & ~ssect->attr) == SHF_ALPHA_GPREL)
+           override = TRUE;
+#endif
          else
            {
              if (group_name == NULL)
@@ -612,11 +654,6 @@ obj_elf_change_section (const char *name,
        attr |= ssect->attr;
     }
 
-  if (type != SHT_NULL)
-    elf_section_type (sec) = type;
-  if (attr != 0)
-    elf_section_flags (sec) = attr;
-
   /* Convert ELF type and flags to BFD flags.  */
   flags = (SEC_RELOC
           | ((attr & SHF_WRITE) ? 0 : SEC_READONLY)
@@ -637,6 +674,9 @@ obj_elf_change_section (const char *name,
     {
       symbolS *secsym;
 
+      elf_section_type (sec) = type;
+      elf_section_flags (sec) = attr;
+
       /* Prevent SEC_HAS_CONTENTS from being inadvertently set.  */
       if (type == SHT_NOBITS)
        seg_info (sec)->bss = 1;
@@ -653,19 +693,26 @@ obj_elf_change_section (const char *name,
       else
        symbol_table_insert (section_symbol (sec));
     }
-  else if (attr != 0)
+  else
     {
-      /* If section attributes are specified the second time we see a
-        particular section, then check that they are the same as we
-        saw the first time.  */
-      if (((old_sec->flags ^ flags)
-          & (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
-             | SEC_EXCLUDE | SEC_SORT_ENTRIES | SEC_MERGE | SEC_STRINGS
-             | SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD
-             | SEC_THREAD_LOCAL)))
-       as_warn (_("ignoring changed section attributes for %s"), name);
-      if ((flags & SEC_MERGE) && old_sec->entsize != (unsigned) entsize)
-       as_warn (_("ignoring changed section entity size for %s"), name);
+      if (type != SHT_NULL
+         && (unsigned) type != elf_section_type (old_sec))
+       as_warn (_("ignoring changed section type for %s"), name);
+
+      if (attr != 0)
+       {
+         /* If section attributes are specified the second time we see a
+            particular section, then check that they are the same as we
+            saw the first time.  */
+         if (((old_sec->flags ^ flags)
+              & (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
+                 | SEC_EXCLUDE | SEC_SORT_ENTRIES | SEC_MERGE | SEC_STRINGS
+                 | SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD
+                 | SEC_THREAD_LOCAL)))
+           as_warn (_("ignoring changed section attributes for %s"), name);
+         if ((flags & SEC_MERGE) && old_sec->entsize != (unsigned) entsize)
+           as_warn (_("ignoring changed section entity size for %s"), name);
+       }
     }
 
 #ifdef md_elf_section_change_hook
@@ -767,6 +814,12 @@ obj_elf_section_type (char *str, size_t len)
     return SHT_NOBITS;
   if (len == 4 && strncmp (str, "note", 4) == 0)
     return SHT_NOTE;
+  if (len == 10 && strncmp (str, "init_array", 10) == 0)
+    return SHT_INIT_ARRAY;
+  if (len == 10 && strncmp (str, "fini_array", 10) == 0)
+    return SHT_FINI_ARRAY;
+  if (len == 13 && strncmp (str, "preinit_array", 13) == 0)
+    return SHT_PREINIT_ARRAY;
 
 #ifdef md_elf_section_type
   {
@@ -1015,6 +1068,24 @@ obj_elf_text (int i)
 #endif
 }
 
+/* Change to the *ABS* section.  */
+
+void
+obj_elf_struct (int i)
+{
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
+
+  previous_section = now_seg;
+  previous_subsection = now_subseg;
+  s_struct (i);
+
+#ifdef md_elf_section_change_hook
+  md_elf_section_change_hook ();
+#endif
+}
+
 static void
 obj_elf_subsection (int ignore ATTRIBUTE_UNUSED)
 {
@@ -1353,11 +1424,12 @@ obj_elf_version (int ignore ATTRIBUTE_UNUSED)
   Elf_Internal_Note i_note;
   Elf_External_Note e_note;
   asection *note_secp = NULL;
-  int len;
 
   SKIP_WHITESPACE ();
   if (*input_line_pointer == '\"')
     {
+      unsigned int len;
+
       ++input_line_pointer;    /* -> 1st char of string.  */
       name = input_line_pointer;
 
@@ -1368,19 +1440,19 @@ obj_elf_version (int ignore ATTRIBUTE_UNUSED)
       *(input_line_pointer - 1) = '\0';
       *input_line_pointer = c;
 
-      /* create the .note section */
-
+      /* Create the .note section.  */
       note_secp = subseg_new (".note", 0);
       bfd_set_section_flags (stdoutput,
                             note_secp,
                             SEC_HAS_CONTENTS | SEC_READONLY);
 
-      /* process the version string */
-
-      len = strlen (name);
+      /* Process the version string.  */
+      len = strlen (name) + 1;
 
-      i_note.namesz = ((len + 1) + 3) & ~3; /* round this to word boundary */
-      i_note.descsz = 0;       /* no description */
+      /* PR 3456: Although the name field is padded out to an 4-byte
+        boundary, the namesz field should not be adjusted.  */
+      i_note.namesz = len;
+      i_note.descsz = 0;       /* No description.  */
       i_note.type = NT_VERSION;
       p = frag_more (sizeof (e_note.namesz));
       md_number_to_chars (p, i_note.namesz, sizeof (e_note.namesz));
@@ -1388,17 +1460,16 @@ obj_elf_version (int ignore ATTRIBUTE_UNUSED)
       md_number_to_chars (p, i_note.descsz, sizeof (e_note.descsz));
       p = frag_more (sizeof (e_note.type));
       md_number_to_chars (p, i_note.type, sizeof (e_note.type));
-      p = frag_more (len + 1);
-      strcpy (p, name);
+      p = frag_more (len);
+      memcpy (p, name, len);
 
       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 ();
 }
 
@@ -1547,7 +1618,7 @@ obj_elf_ident (int ignore ATTRIBUTE_UNUSED)
     }
   else
     subseg_set (comment_section, 0);
-  stringer (1);
+  stringer (8 + 1);
   subseg_set (old_section, old_subsection);
 }
 
@@ -1623,6 +1694,9 @@ adjust_stab_sections (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
    this at the moment, so we do it ourselves.  We save the information
    in the symbol.  */
 
+#ifdef OBJ_MAYBE_ELF
+static
+#endif
 void
 elf_ecoff_set_ext (symbolS *sym, struct ecoff_extr *ext)
 {
@@ -1794,17 +1868,6 @@ elf_frob_symbol (symbolS *symp, int *puntp)
       && (symbol_get_bfdsym (symp)->flags & BSF_FUNCTION) == 0)
     symbol_get_bfdsym (symp)->flags |= BSF_OBJECT;
 #endif
-
-#if 0 /* TC_PPC */
-  /* If TC_PPC is defined, we used to force the type of a symbol to be
-     BSF_OBJECT if it was otherwise unset.  This was required by some
-     version of VxWorks.  Thomas de Lellis <tdel@windriver.com> says
-     that this is no longer needed, so it is now commented out.  */
-  if ((symbol_get_bfdsym (symp)->flags
-       & (BSF_FUNCTION | BSF_FILE | BSF_SECTION_SYM)) == 0
-      && S_IS_DEFINED (symp))
-    symbol_get_bfdsym (symp)->flags |= BSF_OBJECT;
-#endif
 }
 
 struct group_list
@@ -1883,6 +1946,7 @@ elf_frob_file (void)
       flagword flags;
       struct symbol *sy;
       int has_sym;
+      bfd_size_type size;
 
       flags = SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_GROUP;
       for (s = list.head[i]; s != NULL; s = elf_next_in_group (s))
@@ -1923,9 +1987,11 @@ elf_frob_file (void)
       if (has_sym)
        elf_group_id (s) = sy->bsym;
 
-      s->_raw_size = 4 * (list.elt_count[i] + 1);
-      s->contents = frag_more (s->_raw_size);
+      size = 4 * (list.elt_count[i] + 1);
+      bfd_set_section_size (stdoutput, s, size);
+      s->contents = (unsigned char *) frag_more (size);
       frag_now->fr_fix = frag_now_fix_octets ();
+      frag_wane (frag_now);
     }
 
 #ifdef elf_tc_final_processing
@@ -2033,7 +2099,8 @@ elf_frob_file_after_relocs (void)
         to force the ELF backend to allocate a file position, and then
         write out the data.  FIXME: Is this really the best way to do
         this?  */
-      sec->_raw_size = bfd_ecoff_debug_size (stdoutput, &debug, debug_swap);
+      bfd_set_section_size
+       (stdoutput, sec, bfd_ecoff_debug_size (stdoutput, &debug, debug_swap));
 
       /* Pass BUF to bfd_set_section_contents because this will
         eventually become a call to fwrite, and ISO C prohibits