callfuncs.exp: avoid spurious register differences in sparc64 targets.
[deliverable/binutils-gdb.git] / gas / config / obj-elf.c
index 30eb8163ddea395a4f0ff5aff30ff930c76dbd77..031fafb91b406872c83da9041721b627b35f7032 100644 (file)
@@ -1,7 +1,5 @@
 /* ELF object file format
-   Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
-   Free Software Foundation, Inc.
+   Copyright (C) 1992-2015 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
 #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);
@@ -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_gnu_attribute (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},
 
+  /* A GNU extension for object attributes.  */
+  {"gnu_attribute", obj_elf_gnu_attribute, 0},
+
   /* These are used for dwarf.  */
   {"2byte", cons, 2},
   {"4byte", cons, 4},
@@ -260,7 +266,7 @@ elf_file_symbol (const char *s, int appfile)
       || (symbol_rootP->bsym->flags & BSF_FILE) == 0)
     {
       symbolS *sym;
-      unsigned int name_length;
+      size_t name_length;
 
       sym = symbol_new (s, absolute_section, 0, NULL);
       symbol_set_frag (sym, &zero_address_frag);
@@ -400,11 +406,10 @@ get_sym_from_input_line_and_check (void)
   char c;
   symbolS *sym;
 
-  name = input_line_pointer;
-  c = get_symbol_end ();
+  c = get_symbol_name (& name);
   sym = symbol_find_or_make (name);
   *input_line_pointer = c;
-  SKIP_WHITESPACE ();
+  SKIP_WHITESPACE_AFTER_NAME ();
 
   /* There is no symbol name if input_line_pointer has not moved.  */
   if (name == input_line_pointer)
@@ -447,7 +452,6 @@ obj_elf_weak (int ignore ATTRIBUTE_UNUSED)
       symbolP = get_sym_from_input_line_and_check ();
       c = *input_line_pointer;
       S_SET_WEAK (symbolP);
-      symbol_get_obj (symbolP)->local = 1;
       if (c == ',')
        {
          input_line_pointer++;
@@ -658,6 +662,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;
+#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
            {
@@ -741,10 +753,10 @@ obj_elf_change_section (const char *name,
 }
 
 static bfd_vma
-obj_elf_parse_section_letters (char *str, size_t len, bfd_boolean *clone)
+obj_elf_parse_section_letters (char *str, size_t len, bfd_boolean *is_clone)
 {
   bfd_vma attr = 0;
-  *clone = FALSE;
+  *is_clone = FALSE;
 
   while (len > 0)
     {
@@ -775,7 +787,7 @@ obj_elf_parse_section_letters (char *str, size_t len, bfd_boolean *clone)
          attr |= SHF_TLS;
          break;
        case '?':
-         *clone = TRUE;
+         *is_clone = TRUE;
          break;
        /* Compatibility.  */
        case 'm':
@@ -904,6 +916,27 @@ obj_elf_section_name (void)
       name = (char *) xmalloc (end - input_line_pointer + 1);
       memcpy (name, input_line_pointer, end - input_line_pointer);
       name[end - input_line_pointer] = '\0';
+
+      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 = (char *) xmalloc (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
@@ -978,16 +1011,15 @@ obj_elf_section (int push)
 
       if (*input_line_pointer == '"')
        {
-         bfd_boolean clone;
+         bfd_boolean is_clone;
 
          beg = demand_copy_C_string (&dummy);
          if (beg == NULL)
            {
              ignore_rest_of_line ();
-             xfree (name);
              return;
            }
-         attr |= obj_elf_parse_section_letters (beg, strlen (beg), &clone);
+         attr |= obj_elf_parse_section_letters (beg, strlen (beg), &is_clone);
 
          SKIP_WHITESPACE ();
          if (*input_line_pointer == ',')
@@ -1004,16 +1036,15 @@ obj_elf_section (int push)
                  if (beg == NULL)
                    {
                      ignore_rest_of_line ();
-                     xfree (name);
                      return;
                    }
                  type = obj_elf_section_type (beg, strlen (beg), TRUE);
                }
              else if (c == '@' || c == '%')
                {
-                 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);
                  type = obj_elf_section_type (beg, input_line_pointer - beg, TRUE);
                }
              else
@@ -1040,10 +1071,10 @@ obj_elf_section (int push)
              attr &= ~SHF_MERGE;
            }
 
-         if ((attr & SHF_GROUP) != 0 && clone)
+         if ((attr & SHF_GROUP) != 0 && is_clone)
            {
              as_warn (_("? section flag ignored with G present"));
-             clone = FALSE;
+             is_clone = FALSE;
            }
          if ((attr & SHF_GROUP) != 0 && *input_line_pointer == ',')
            {
@@ -1051,10 +1082,15 @@ obj_elf_section (int push)
              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;
@@ -1065,7 +1101,7 @@ obj_elf_section (int push)
              attr &= ~SHF_GROUP;
            }
 
-         if (clone)
+         if (is_clone)
            {
              const char *now_group = elf_group_name (now_seg);
              if (now_group != NULL)
@@ -1086,12 +1122,11 @@ obj_elf_section (int push)
                {
                  as_bad (_("character following name is not '#'"));
                  ignore_rest_of_line ();
-                 xfree (name);
                  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, & type);
 
@@ -1283,19 +1318,18 @@ obj_elf_symver (int ignore ATTRIBUTE_UNUSED)
 
   ++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;
-  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);
 
-      *input_line_pointer = c;
+      (void) restore_line_pointer (c);
 
       if (strchr (symbol_get_obj (sym)->versioned_name,
                  ELF_VER_CHR) == NULL)
@@ -1318,7 +1352,7 @@ obj_elf_symver (int ignore ATTRIBUTE_UNUSED)
          return;
        }
 
-      *input_line_pointer = c;
+      (void) restore_line_pointer (c);
     }
 
   demand_empty_rest_of_line ();
@@ -1338,8 +1372,7 @@ obj_elf_vtable_inherit (int ignore ATTRIBUTE_UNUSED)
   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
@@ -1355,7 +1388,7 @@ obj_elf_vtable_inherit (int ignore ATTRIBUTE_UNUSED)
 
   *input_line_pointer = c;
 
-  SKIP_WHITESPACE ();
+  SKIP_WHITESPACE_AFTER_NAME ();
   if (*input_line_pointer != ',')
     {
       as_bad (_("expected comma after name in .vtable_inherit"));
@@ -1378,10 +1411,9 @@ obj_elf_vtable_inherit (int ignore ATTRIBUTE_UNUSED)
     }
   else
     {
-      pname = input_line_pointer;
-      c = get_symbol_end ();
+      c = get_symbol_name (& pname);
       psym = symbol_find_or_make (pname);
-      *input_line_pointer = c;
+      restore_line_pointer (c);
     }
 
   demand_empty_rest_of_line ();
@@ -1428,6 +1460,195 @@ obj_elf_vtable_entry (int ignore ATTRIBUTE_UNUSED)
                  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 = (char *) alloca (i + 1);
+      memcpy (name, s, i);
+      name[i] = '\0';
+
+#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 ();
+         return 0;
+       }
+    }
+
+  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)
 {
@@ -1542,15 +1763,15 @@ obj_elf_version (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;
-  SKIP_WHITESPACE ();
+  SKIP_WHITESPACE_AFTER_NAME ();
   if (*input_line_pointer != ',')
     {
       *p = 0;
@@ -1622,7 +1843,7 @@ obj_elf_type_name (char *cp)
       *input_line_pointer = '\0';
     }
   else
-    *cp = get_symbol_end ();
+    *cp = get_symbol_name (&p);
 
   return p;
 }
@@ -1704,10 +1925,11 @@ obj_elf_type (int ignore ATTRIBUTE_UNUSED)
       const struct elf_backend_data *bed;
 
       bed = get_elf_backend_data (stdoutput);
-      if (!(bed->elf_osabi == ELFOSABI_LINUX
-           /* GNU/Linux is still using the default value 0.  */
+      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 targets"),
+       as_bad (_("symbol type \"%s\" is supported only by GNU and FreeBSD targets"),
                type_name);
       type = BSF_FUNCTION | BSF_GNU_INDIRECT_FUNCTION;
     }
@@ -1716,14 +1938,14 @@ obj_elf_type (int ignore ATTRIBUTE_UNUSED)
       struct elf_backend_data *bed;
 
       bed = (struct elf_backend_data *) get_elf_backend_data (stdoutput);
-      if (!(bed->elf_osabi == ELFOSABI_LINUX
-           /* GNU/Linux is still using the default value 0.  */
+      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 LINUX for objects containing unique symbols.  */
-      bed->elf_osabi = ELFOSABI_LINUX;
+      /* PR 10549: Always set OSABI field to GNU for objects containing unique symbols.  */
+      bed->elf_osabi = ELFOSABI_GNU;
     }
 #ifdef md_elf_symbol_type
   else if ((type = md_elf_symbol_type (type_name, sym, elfsym)) != -1)
@@ -1915,7 +2137,9 @@ elf_frob_symbol (symbolS *symp, int *puntp)
       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.
 
@@ -1928,14 +2152,15 @@ elf_frob_symbol (symbolS *symp, int *puntp)
         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)
            {
-             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;
            }
@@ -2092,7 +2317,7 @@ elf_adjust_symtab (void)
   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
@@ -2198,8 +2423,7 @@ elf_frob_file_before_adjust (void)
 
                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);
This page took 0.030084 seconds and 4 git commands to generate.