gas: Extend .symver directive
authorH.J. Lu <hjl.tools@gmail.com>
Tue, 21 Apr 2020 12:33:04 +0000 (05:33 -0700)
committerH.J. Lu <hjl.tools@gmail.com>
Tue, 21 Apr 2020 12:33:17 +0000 (05:33 -0700)
Extend .symver directive to update visibility of the original symbol and
assign one original symbol to different versioned symbols:

  .symver foo, foo@VERS_1, local    # Change foo to a local symbol.
  .symver foo, foo@VERS_2, hidden   # Change foo to a hidden symbol.
  .symver foo, foo@@VERS_3, remove  # Remove foo from symbol table.
  .symver foo, bar@V1               # Assign foo to bar@V1 and baz@V2.
  .symver foo, baz@V2

PR gas/23840
PR gas/25295
* NEWS: Mention .symver extension.
* config/obj-elf.c (obj_elf_find_and_add_versioned_name): New
function.
(obj_elf_symver): Call obj_elf_find_and_add_versioned_name to
add a version name.  Add local, hidden and remove visibility
support.
(elf_frob_symbol): Handle the list of version names.  Update the
original symbol to local, hidden or remove it from the symbol
table.
(elf_frob_file_before_adjust): Handle the list of version names.
* config/obj-elf.h (elf_visibility): New.
(elf_versioned_name_list): Likewise.
(elf_obj_sy): Change local to bitfield. Add rename, bad_version
and visibility.  Change versioned_name pointer to struct
elf_versioned_name_list.
* doc/as.texi: Update .symver directive.
* testsuite/gas/symver/symver.exp: Run all *.d tests.  Add more
error checking tests.
* testsuite/gas/symver/symver6.d: New file.
* testsuite/gas/symver/symver7.d: Likewise.
* testsuite/gas/symver/symver7.s: Likewise.
* testsuite/gas/symver/symver8.d: Likewise.
* testsuite/gas/symver/symver8.s: Likewise.
* testsuite/gas/symver/symver9.s: Likewise.
* testsuite/gas/symver/symver9a.d: Likewise.
* testsuite/gas/symver/symver9b.d: Likewise.
* testsuite/gas/symver/symver10.s: Likewise.
* testsuite/gas/symver/symver10a.d: Likewise.
* testsuite/gas/symver/symver10b.d: Likewise.
* testsuite/gas/symver/symver11.d: Likewise.
* testsuite/gas/symver/symver11.s: Likewise.
* testsuite/gas/symver/symver12.d: Likewise.
* testsuite/gas/symver/symver12.s: Likewise.
* testsuite/gas/symver/symver13.d: Likewise.
* testsuite/gas/symver/symver13.s: Likewise.
* testsuite/gas/symver/symver14.d: Likewise.
* testsuite/gas/symver/symver14.l: Likewise.
* testsuite/gas/symver/symver15.d: Likewise.
* testsuite/gas/symver/symver15.l: Likewise.
* testsuite/gas/symver/symver6.l: Removed.
* testsuite/gas/symver/symver6.s: Updated.

29 files changed:
gas/ChangeLog
gas/NEWS
gas/config/obj-elf.c
gas/config/obj-elf.h
gas/doc/as.texi
gas/testsuite/gas/symver/symver.exp
gas/testsuite/gas/symver/symver10.s [new file with mode: 0644]
gas/testsuite/gas/symver/symver10a.d [new file with mode: 0644]
gas/testsuite/gas/symver/symver10b.d [new file with mode: 0644]
gas/testsuite/gas/symver/symver11.d [new file with mode: 0644]
gas/testsuite/gas/symver/symver11.s [new file with mode: 0644]
gas/testsuite/gas/symver/symver12.d [new file with mode: 0644]
gas/testsuite/gas/symver/symver12.s [new file with mode: 0644]
gas/testsuite/gas/symver/symver13.d [new file with mode: 0644]
gas/testsuite/gas/symver/symver13.s [new file with mode: 0644]
gas/testsuite/gas/symver/symver14.l [new file with mode: 0644]
gas/testsuite/gas/symver/symver14.s [new file with mode: 0644]
gas/testsuite/gas/symver/symver15.l [new file with mode: 0644]
gas/testsuite/gas/symver/symver15.s [new file with mode: 0644]
gas/testsuite/gas/symver/symver6.d [new file with mode: 0644]
gas/testsuite/gas/symver/symver6.l [deleted file]
gas/testsuite/gas/symver/symver6.s
gas/testsuite/gas/symver/symver7.d [new file with mode: 0644]
gas/testsuite/gas/symver/symver7.s [new file with mode: 0644]
gas/testsuite/gas/symver/symver8.d [new file with mode: 0644]
gas/testsuite/gas/symver/symver8.s [new file with mode: 0644]
gas/testsuite/gas/symver/symver9.s [new file with mode: 0644]
gas/testsuite/gas/symver/symver9a.d [new file with mode: 0644]
gas/testsuite/gas/symver/symver9b.d [new file with mode: 0644]

index f821f3d53a0d433130b198c8087072144fc08da7..3185bdcf3669751b35ec92cb53f66660e77ea329 100644 (file)
@@ -1,3 +1,49 @@
+2020-04-21  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR gas/23840
+       PR gas/25295
+       * NEWS: Mention .symver extension.
+       * config/obj-elf.c (obj_elf_find_and_add_versioned_name): New
+       function.
+       (obj_elf_symver): Call obj_elf_find_and_add_versioned_name to
+       add a version name.  Add local, hidden and remove visibility
+       support.
+       (elf_frob_symbol): Handle the list of version names.  Update the
+       original symbol to local, hidden or remove it from the symbol
+       table.
+       (elf_frob_file_before_adjust): Handle the list of version names.
+       * config/obj-elf.h (elf_visibility): New.
+       (elf_versioned_name_list): Likewise.
+       (elf_obj_sy): Change local to bitfield. Add rename, bad_version
+       and visibility.  Change versioned_name pointer to struct
+       elf_versioned_name_list.
+       * doc/as.texi: Update .symver directive.
+       * testsuite/gas/symver/symver.exp: Run all *.d tests.  Add more
+       error checking tests.
+       * testsuite/gas/symver/symver6.d: New file.
+       * testsuite/gas/symver/symver7.d: Likewise.
+       * testsuite/gas/symver/symver7.s: Likewise.
+       * testsuite/gas/symver/symver8.d: Likewise.
+       * testsuite/gas/symver/symver8.s: Likewise.
+       * testsuite/gas/symver/symver9.s: Likewise.
+       * testsuite/gas/symver/symver9a.d: Likewise.
+       * testsuite/gas/symver/symver9b.d: Likewise.
+       * testsuite/gas/symver/symver10.s: Likewise.
+       * testsuite/gas/symver/symver10a.d: Likewise.
+       * testsuite/gas/symver/symver10b.d: Likewise.
+       * testsuite/gas/symver/symver11.d: Likewise.
+       * testsuite/gas/symver/symver11.s: Likewise.
+       * testsuite/gas/symver/symver12.d: Likewise.
+       * testsuite/gas/symver/symver12.s: Likewise.
+       * testsuite/gas/symver/symver13.d: Likewise.
+       * testsuite/gas/symver/symver13.s: Likewise.
+       * testsuite/gas/symver/symver14.d: Likewise.
+       * testsuite/gas/symver/symver14.l: Likewise.
+       * testsuite/gas/symver/symver15.d: Likewise.
+       * testsuite/gas/symver/symver15.l: Likewise.
+       * testsuite/gas/symver/symver6.l: Removed.
+       * testsuite/gas/symver/symver6.s: Updated.
+
 2020-04-20  Sudakshina Das  <sudi.das@arm.com>
 
        * config/tc-aarch64.c (parse_barrier_psb): Update error messages
 2020-04-20  Sudakshina Das  <sudi.das@arm.com>
 
        * config/tc-aarch64.c (parse_barrier_psb): Update error messages
index 6748c179f15ef331fe7e412f2b973b6f3b96477b..58d79caa41db695424a37307b6545b513cb35fee 100644 (file)
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -1,5 +1,8 @@
 -*- text -*-
 
 -*- text -*-
 
+* Extend .symver directive to update visibility of the original symbol
+  and assign one original symbol to different versioned symbols.
+
 * Add support for Intel SERIALIZE and TSXLDTRK instructions.
 
 * Add -mlfence-after-load=, -mlfence-before-indirect-branch= and
 * Add support for Intel SERIALIZE and TSXLDTRK instructions.
 
 * Add -mlfence-after-load=, -mlfence-before-indirect-branch= and
index 5e7e8f0877963107b367965eda2ab5288b20900a..409ea4d6bed5ef4542bc772e9b7b372f9026bc1c 100644 (file)
@@ -1515,6 +1515,70 @@ obj_elf_line (int ignore ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
   demand_empty_rest_of_line ();
 }
 
+static struct elf_versioned_name_list *
+obj_elf_find_and_add_versioned_name (const char *version_name,
+                                    const char *sym_name,
+                                    const char *ver,
+                                    struct elf_obj_sy *sy_obj)
+{
+  struct elf_versioned_name_list *versioned_name;
+  const char *p;
+
+  for (p = ver + 1; *p == ELF_VER_CHR; p++)
+    ;
+
+  /* NB: Since some tests in ld/testsuite/ld-elfvers have no version
+     names, we have to disable this.  */
+  if (0 && *p == '\0')
+    {
+      as_bad (_("missing version name in `%s' for symbol `%s'"),
+             version_name, sym_name);
+      return NULL;
+    }
+
+  versioned_name = sy_obj->versioned_name;
+
+  switch (p - ver)
+    {
+    case 1:
+    case 2:
+      break;
+    case 3:
+      if (sy_obj->rename)
+       {
+         if (strcmp (versioned_name->name, version_name) == 0)
+           return versioned_name;
+         else
+           {
+             as_bad (_("only one version name with `@@@' is allowed "
+                       "for symbol `%s'"), sym_name);
+             return NULL;
+           }
+       }
+      sy_obj->rename = TRUE;
+      break;
+    default:
+      as_bad (_("invalid version name '%s' for symbol `%s'"),
+             version_name, sym_name);
+      return NULL;
+    }
+
+  for (;
+       versioned_name != NULL;
+       versioned_name = versioned_name->next)
+    if (strcmp (versioned_name->name, version_name) == 0)
+      return versioned_name;
+
+  /* Add this versioned name to the head of the list,  */
+  versioned_name = (struct elf_versioned_name_list *)
+    xmalloc (sizeof (*versioned_name));
+  versioned_name->name = xstrdup (version_name);
+  versioned_name->next = sy_obj->versioned_name;
+  sy_obj->versioned_name = versioned_name;
+
+  return versioned_name;
+}
+
 /* This handles the .symver pseudo-op, which is used to specify a
    symbol version.  The syntax is ``.symver NAME,SYMVERNAME''.
    SYMVERNAME may contain ELF_VER_CHR ('@') characters.  This
 /* This handles the .symver pseudo-op, which is used to specify a
    symbol version.  The syntax is ``.symver NAME,SYMVERNAME''.
    SYMVERNAME may contain ELF_VER_CHR ('@') characters.  This
@@ -1525,9 +1589,12 @@ static void
 obj_elf_symver (int ignore ATTRIBUTE_UNUSED)
 {
   char *name;
 obj_elf_symver (int ignore ATTRIBUTE_UNUSED)
 {
   char *name;
+  const char *sym_name;
   char c;
   char old_lexat;
   symbolS *sym;
   char c;
   char old_lexat;
   symbolS *sym;
+  struct elf_obj_sy *sy_obj;
+  char *p;
 
   sym = get_sym_from_input_line_and_check ();
 
 
   sym = get_sym_from_input_line_and_check ();
 
@@ -1546,43 +1613,59 @@ obj_elf_symver (int ignore ATTRIBUTE_UNUSED)
   lex_type[(unsigned char) '@'] |= LEX_NAME;
   c = get_symbol_name (& name);
   lex_type[(unsigned char) '@'] = old_lexat;
   lex_type[(unsigned char) '@'] |= LEX_NAME;
   c = get_symbol_name (& name);
   lex_type[(unsigned char) '@'] = old_lexat;
+  sym_name = S_GET_NAME (sym);
 
   if (S_IS_COMMON (sym))
     {
       as_bad (_("`%s' can't be versioned to common symbol '%s'"),
 
   if (S_IS_COMMON (sym))
     {
       as_bad (_("`%s' can't be versioned to common symbol '%s'"),
-             name, S_GET_NAME (sym));
+             name, sym_name);
       ignore_rest_of_line ();
       return;
     }
 
       ignore_rest_of_line ();
       return;
     }
 
-  if (symbol_get_obj (sym)->versioned_name == NULL)
+  p = strchr (name, ELF_VER_CHR);
+  if (p == NULL)
     {
     {
-      symbol_get_obj (sym)->versioned_name = xstrdup (name);
+      as_bad (_("missing version name in `%s' for symbol `%s'"),
+             name, sym_name);
+      ignore_rest_of_line ();
+      return;
+    }
+
+  sy_obj = symbol_get_obj (sym);
+  if (obj_elf_find_and_add_versioned_name (name, sym_name,
+                                          p, sy_obj) == NULL)
+    {
+      sy_obj->bad_version = TRUE;
+      ignore_rest_of_line ();
+      return;
+    }
 
 
-      (void) restore_line_pointer (c);
+  (void) restore_line_pointer (c);
 
 
-      if (strchr (symbol_get_obj (sym)->versioned_name,
-                 ELF_VER_CHR) == NULL)
+  if (*input_line_pointer == ',')
+    {
+      char *save = input_line_pointer;
+
+      ++input_line_pointer;
+      SKIP_WHITESPACE ();
+      if (strncmp (input_line_pointer, "local", 5) == 0)
        {
        {
-         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;
+         input_line_pointer += 5;
+         sy_obj->visibility = visibility_local;
        }
        }
-    }
-  else
-    {
-      if (strcmp (symbol_get_obj (sym)->versioned_name, name))
+      else if (strncmp (input_line_pointer, "hidden", 6) == 0)
        {
        {
-         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 += 6;
+         sy_obj->visibility = visibility_hidden;
        }
        }
-
-      (void) restore_line_pointer (c);
+      else if (strncmp (input_line_pointer, "remove", 6) == 0)
+       {
+         input_line_pointer += 6;
+         sy_obj->visibility = visibility_remove;
+       }
+      else
+       input_line_pointer = save;
     }
 
   demand_empty_rest_of_line ();
     }
 
   demand_empty_rest_of_line ();
@@ -2382,6 +2465,7 @@ elf_frob_symbol (symbolS *symp, int *puntp)
 {
   struct elf_obj_sy *sy_obj;
   expressionS *size;
 {
   struct elf_obj_sy *sy_obj;
   expressionS *size;
+  struct elf_versioned_name_list *versioned_name;
 
 #ifdef NEED_ECOFF_DEBUG
   if (ECOFF_DEBUGGING)
 
 #ifdef NEED_ECOFF_DEBUG
   if (ECOFF_DEBUGGING)
@@ -2409,73 +2493,47 @@ elf_frob_symbol (symbolS *symp, int *puntp)
       sy_obj->size = NULL;
     }
 
       sy_obj->size = NULL;
     }
 
-  if (sy_obj->versioned_name != NULL)
+  versioned_name = sy_obj->versioned_name;
+  if (versioned_name)
     {
     {
-      char *p;
-
-      p = strchr (sy_obj->versioned_name, ELF_VER_CHR);
-      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.
-
         If this is an external reference, just rename the symbol to
         include the version string.  This will make the relocs be
         If this is an external reference, just rename the symbol to
         include the version string.  This will make the relocs be
-        against the correct versioned symbol.
-
-        If this is a definition, add an alias.  FIXME: Using an alias
-        will permit the debugging information to refer to the right
-        symbol.  However, it's not clear whether it is the best
-        approach.  */
+        against the correct versioned symbol.  */
 
 
-      else if (! S_IS_DEFINED (symp))
+      /* We will have already reported an version error.  */
+      if (sy_obj->bad_version)
+       *puntp = TRUE;
+      /* elf_frob_file_before_adjust only allows one version symbol for
+        renamed symbol.  */
+      else if (sy_obj->rename)
+       S_SET_NAME (symp, versioned_name->name);
+      else if (S_IS_COMMON (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'"),
-                     sy_obj->versioned_name);
-             *puntp = TRUE;
-           }
-         S_SET_NAME (symp, sy_obj->versioned_name);
+         as_bad (_("`%s' can't be versioned to common symbol '%s'"),
+                 versioned_name->name, S_GET_NAME (symp));
+         *puntp = TRUE;
        }
       else
        {
        }
       else
        {
-         if (p[1] == ELF_VER_CHR && p[2] == ELF_VER_CHR)
-           {
-             size_t l;
-
-             /* 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
+         asymbol *bfdsym;
+         elf_symbol_type *elfsym;
+
+         /* This is a definition.  Add an alias for each version.
+            FIXME: Using an alias will permit the debugging information
+            to refer to the right symbol.  However, it's not clear
+            whether it is the best approach.  */
+
+         /* 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.  */
+         for (; versioned_name != NULL;
+              versioned_name = versioned_name->next)
            {
            {
-             symbolS *symp2;
-
-             /* 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.  */
-
-             symp2 = symbol_find_or_make (sy_obj->versioned_name);
-
-             /* Now we act as though we saw symp2 = sym.  */
-             if (S_IS_COMMON (symp))
-               {
-                 as_bad (_("`%s' can't be versioned to common symbol '%s'"),
-                         sy_obj->versioned_name, S_GET_NAME (symp));
-                 *puntp = TRUE;
-                 return;
-               }
+             symbolS *symp2 = symbol_find_or_make (versioned_name->name);
 
              S_SET_SEGMENT (symp2, S_GET_SEGMENT (symp));
 
 
              S_SET_SEGMENT (symp2, S_GET_SEGMENT (symp));
 
@@ -2498,6 +2556,27 @@ elf_frob_symbol (symbolS *symp, int *puntp)
              if (S_IS_EXTERNAL (symp))
                S_SET_EXTERNAL (symp2);
            }
              if (S_IS_EXTERNAL (symp))
                S_SET_EXTERNAL (symp2);
            }
+
+         switch (symbol_get_obj (symp)->visibility)
+           {
+           case visibility_unchanged:
+             break;
+           case visibility_hidden:
+             bfdsym = symbol_get_bfdsym (symp);
+             elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym),
+                                       bfdsym);
+             elfsym->internal_elf_sym.st_other &= ~3;
+             elfsym->internal_elf_sym.st_other |= STV_HIDDEN;
+             break;
+           case visibility_remove:
+             /* Remove the symbol if it isn't used in relocation.  */
+             if (!symbol_used_in_reloc_p (symp))
+               symbol_remove (symp, &symbol_rootP, &symbol_lastP);
+             break;
+           case visibility_local:
+             S_CLEAR_EXTERNAL (symp);
+             break;
+           }
        }
     }
 
        }
     }
 
@@ -2676,36 +2755,61 @@ elf_frob_file_before_adjust (void)
       symbolS *symp;
 
       for (symp = symbol_rootP; symp; symp = symbol_next (symp))
       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);
-               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);
-                 }
-               if (symbol_used_p (symp) == 0
-                   && symbol_used_in_reloc_p (symp) == 0)
-                 symbol_remove (symp, &symbol_rootP, &symbol_lastP);
-             }
+       {
+         struct elf_obj_sy *sy_obj = symbol_get_obj (symp);
+         int is_defined = !!S_IS_DEFINED (symp);
 
 
-           /* If there was .weak foo, but foo was neither defined nor
-              used anywhere, remove it.  */
+         if (sy_obj->versioned_name)
+           {
+             char *p = strchr (sy_obj->versioned_name->name,
+                               ELF_VER_CHR);
 
 
-           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);
-         }
+             if (sy_obj->rename)
+               {
+                 /* The @@@ syntax is a special case. If the symbol is
+                    not defined, 2 `@'s will be removed from the
+                    versioned_name. Otherwise, 1 `@' will be removed.   */
+                 size_t l = strlen (&p[3]) + 1;
+                 memmove (&p[1 + is_defined], &p[3], l);
+               }
+
+             if (!is_defined)
+               {
+                 /* Verify that the name isn't using the @@ syntax--this
+                    is reserved for definitions of the default version
+                    to link against.  */
+                 if (!sy_obj->rename && p[1] == ELF_VER_CHR)
+                   {
+                     as_bad (_("invalid attempt to declare external "
+                               "version name as default in symbol `%s'"),
+                             sy_obj->versioned_name->name);
+                     return;
+                   }
+
+                 /* Only one version symbol is allowed for undefined
+                    symbol.  */
+                 if (sy_obj->versioned_name->next)
+                   {
+                     as_bad (_("multiple versions [`%s'|`%s'] for "
+                               "symbol `%s'"),
+                             sy_obj->versioned_name->name,
+                             sy_obj->versioned_name->next->name,
+                             S_GET_NAME (symp));
+                     return;
+                   }
+
+                 sy_obj->rename = TRUE;
+               }
+           }
+
+         /* If there was .symver or .weak, but symbol was neither
+            defined nor used anywhere, remove it.  */
+         if (!is_defined
+             && (sy_obj->versioned_name || S_IS_WEAK (symp))
+             && symbol_used_p (symp) == 0
+             && symbol_used_in_reloc_p (symp) == 0)
+           symbol_remove (symp, &symbol_rootP, &symbol_lastP);
+       }
     }
 }
 
     }
 }
 
index 54af9ebc0e22129312b882eff5b26edd9ca39620..b39a1a1ab63e5d7093bb846b7f94b6902527d59e 100644 (file)
@@ -55,18 +55,41 @@ extern int mips_flag_mdebug;
 #endif
 #endif
 
 #endif
 #endif
 
+enum elf_visibility
+{
+  visibility_unchanged = 0,
+  visibility_local,
+  visibility_hidden,
+  visibility_remove
+};
+
+struct elf_versioned_name_list
+{
+  char *name;
+  struct elf_versioned_name_list *next;
+};
+
 /* Additional information we keep for each symbol.  */
 struct elf_obj_sy
 {
   /* Whether the symbol has been marked as local.  */
 /* Additional information we keep for each symbol.  */
 struct elf_obj_sy
 {
   /* Whether the symbol has been marked as local.  */
-  int local;
+  unsigned int local : 1;
+
+  /* Whether the symbol has been marked for rename with @@@.  */
+  unsigned int rename : 1;
+
+  /* Whether the symbol has a bad version name.  */
+  unsigned int bad_version : 1;
+
+  /* Whether visibility of the symbol should be changed.  */
+  ENUM_BITFIELD (elf_visibility) visibility : 2;
 
   /* Use this to keep track of .size expressions that involve
      differences that we can't compute yet.  */
   expressionS *size;
 
 
   /* Use this to keep track of .size expressions that involve
      differences that we can't compute yet.  */
   expressionS *size;
 
-  /* The name specified by the .symver directive.  */
-  char *versioned_name;
+  /* The list of names specified by the .symver directive.  */
+  struct elf_versioned_name_list *versioned_name;
 
 #ifdef ECOFF_DEBUGGING
   /* If we are generating ECOFF debugging information, we need some
 
 #ifdef ECOFF_DEBUGGING
   /* If we are generating ECOFF debugging information, we need some
index 0a6727ef848aaf357d2a7822b437a4c393baa562..8669879c87f165b9491b40c7d166a466fef3a5cd 100644 (file)
@@ -4509,7 +4509,7 @@ Some machine configurations provide additional directives.
 * Struct::                     @code{.struct @var{expression}}
 @ifset ELF
 * SubSection::                  @code{.subsection}
 * Struct::                     @code{.struct @var{expression}}
 @ifset ELF
 * SubSection::                  @code{.subsection}
-* Symver::                      @code{.symver @var{name},@var{name2@@nodename}}
+* Symver::                      @code{.symver @var{name},@var{name2@@nodename}[,@var{visibility}]}
 @end ifset
 
 @ifset COFF
 @end ifset
 
 @ifset COFF
@@ -7112,9 +7112,9 @@ shared library.
 
 For ELF targets, the @code{.symver} directive can be used like this:
 @smallexample
 
 For ELF targets, the @code{.symver} directive can be used like this:
 @smallexample
-.symver @var{name}, @var{name2@@nodename}
+.symver @var{name}, @var{name2@@nodename}[ ,@var{visibility}]
 @end smallexample
 @end smallexample
-If the symbol @var{name} is defined within the file
+If the original symbol @var{name} is defined within the file
 being assembled, the @code{.symver} directive effectively creates a symbol
 alias with the name @var{name2@@nodename}, and in fact the main reason that we
 just don't try and create a regular alias is that the @var{@@} character isn't
 being assembled, the @code{.symver} directive effectively creates a symbol
 alias with the name @var{name2@@nodename}, and in fact the main reason that we
 just don't try and create a regular alias is that the @var{@@} character isn't
@@ -7127,7 +7127,15 @@ function is being mentioned.  The @var{nodename} portion of the alias should be
 the name of a node specified in the version script supplied to the linker when
 building a shared library.  If you are attempting to override a versioned
 symbol from a shared library, then @var{nodename} should correspond to the
 the name of a node specified in the version script supplied to the linker when
 building a shared library.  If you are attempting to override a versioned
 symbol from a shared library, then @var{nodename} should correspond to the
-nodename of the symbol you are trying to override.
+nodename of the symbol you are trying to override.  The optional argument
+@var{visibility} updates the visibility of the original symbol.  The valid
+visibilities are @code{local}, @code {hidden}, and @code {remove}.  The
+@code{local} visibility makes the original symbol a local symbol
+(@pxref{Local}).  The @code{hidden} visibility sets the visibility of the
+original symbol to @code{hidden} (@pxref{Hidden}).  The @code{remove}
+visibility removes the original symbol from the symbol table if it isn't
+used in relocation.  If visibility isn't specified, the original symbol
+is unchanged.
 
 If the symbol @var{name} is not defined within the file being assembled, all
 references to @var{name} will be changed to @var{name2@@nodename}.  If no
 
 If the symbol @var{name} is not defined within the file being assembled, all
 references to @var{name} will be changed to @var{name2@@nodename}.  If no
index de122eb61c3324792b9dd53fe7539c1104c2af1d..6b29a12d316fdbc3f6507e45cd3400a86268585b 100644 (file)
@@ -46,8 +46,13 @@ if { [is_elf_format] } then {
       return
     }
 
       return
     }
 
-    run_dump_test "symver0" 
-    run_dump_test "symver1" 
+    set test_list [lsort [glob -nocomplain $srcdir/$subdir/*.d]]
+    foreach t $test_list {
+       # We need to strip the ".d", but can leave the dirname.
+       verbose [file rootname $t]
+       run_dump_test [file rootname $t]
+    }
+
     run_error_test "symver2" ""
     run_error_test "symver3" ""
     # We have to comment out symver4 and symver5, which check the
     run_error_test "symver2" ""
     run_error_test "symver3" ""
     # We have to comment out symver4 and symver5, which check the
@@ -56,5 +61,6 @@ if { [is_elf_format] } then {
     # version name.
 #    run_error_test "symver4" ""
 #    run_error_test "symver5" ""
     # version name.
 #    run_error_test "symver4" ""
 #    run_error_test "symver5" ""
-    run_error_test "symver6" ""
+    run_error_test "symver14" ""
+    run_error_test "symver15" ""
 }
 }
diff --git a/gas/testsuite/gas/symver/symver10.s b/gas/testsuite/gas/symver/symver10.s
new file mode 100644 (file)
index 0000000..967a692
--- /dev/null
@@ -0,0 +1,8 @@
+       .data
+       .globl foo
+       .type foo,%object
+foo:
+       .byte 0
+       .size foo,.-foo
+       .symver foo,foo@@version2,remove
+       .symver foo,foo@version1
diff --git a/gas/testsuite/gas/symver/symver10a.d b/gas/testsuite/gas/symver/symver10a.d
new file mode 100644 (file)
index 0000000..e9bd159
--- /dev/null
@@ -0,0 +1,8 @@
+#source: symver10.s
+#readelf: -sW
+#name: symver symver10a
+
+#...
+ +[0-9]+: +0+ +1 +OBJECT +GLOBAL +DEFAULT +[0-9]+ +foo@version1
+ +[0-9]+: +0+ +1 +OBJECT +GLOBAL +DEFAULT +[0-9]+ +foo@@version2
+#pass
diff --git a/gas/testsuite/gas/symver/symver10b.d b/gas/testsuite/gas/symver/symver10b.d
new file mode 100644 (file)
index 0000000..17d0bfd
--- /dev/null
@@ -0,0 +1,8 @@
+#source: symver10.s
+#readelf: -sW
+#name: symver symver10b
+
+#failif
+#...
+ +[0-9]+: +0+ +1 +OBJECT +GLOBAL +DEFAULT +[0-9]+ +foo
+#pass
diff --git a/gas/testsuite/gas/symver/symver11.d b/gas/testsuite/gas/symver/symver11.d
new file mode 100644 (file)
index 0000000..0e3e7f1
--- /dev/null
@@ -0,0 +1,8 @@
+#readelf: -rsW
+#name: symver symver11
+
+#...
+[0-9a-f]+ +[0-9a-f]+ +R_.* +[0-9a-f]+ +foo *.*
+#...
+ +[0-9]+: +0+ +1 +OBJECT +GLOBAL +DEFAULT +[0-9]+ +foo
+#pass
diff --git a/gas/testsuite/gas/symver/symver11.s b/gas/testsuite/gas/symver/symver11.s
new file mode 100644 (file)
index 0000000..547e812
--- /dev/null
@@ -0,0 +1,9 @@
+       .data
+       .globl foo
+       .type foo,%object
+foo:
+       .byte 0
+       .size foo,.-foo
+       .symver foo,foo@@version2,remove
+       .symver foo,foo@version1
+       .dc.a foo
diff --git a/gas/testsuite/gas/symver/symver12.d b/gas/testsuite/gas/symver/symver12.d
new file mode 100644 (file)
index 0000000..3878f4d
--- /dev/null
@@ -0,0 +1,9 @@
+#readelf: -sW
+#name: symver symver12
+
+#...
+ +[0-9]+: +0+d +1 +FUNC +GLOBAL +DEFAULT +[0-9]+ +foo
+ +[0-9]+: +0+d +1 +FUNC +GLOBAL +DEFAULT +[0-9]+ +foo@VERS_2
+ +[0-9]+: +0+d +1 +FUNC +GLOBAL +DEFAULT +[0-9]+ +foo@VERS_1
+ +[0-9]+: +0+d +1 +FUNC +GLOBAL +DEFAULT +[0-9]+ +foo@@VERS_2
+#pass
diff --git a/gas/testsuite/gas/symver/symver12.s b/gas/testsuite/gas/symver/symver12.s
new file mode 100644 (file)
index 0000000..724c3ef
--- /dev/null
@@ -0,0 +1,10 @@
+       .text
+       .space 13
+       .symver foo, foo@@VERS_2
+       .symver foo, foo@VERS_1
+       .symver foo, foo@VERS_2
+       .globl  foo
+       .type   foo, %function
+foo:
+       .byte 0
+       .size foo,.-foo
diff --git a/gas/testsuite/gas/symver/symver13.d b/gas/testsuite/gas/symver/symver13.d
new file mode 100644 (file)
index 0000000..dce8579
--- /dev/null
@@ -0,0 +1,9 @@
+#readelf: -sW
+#name: symver symver13
+
+#...
+ +[0-9]+: +0+d +1 +FUNC +GLOBAL +HIDDEN +[0-9]+ +foo
+ +[0-9]+: +0+d +1 +FUNC +GLOBAL +HIDDEN +[0-9]+ +foo@VERS_1
+ +[0-9]+: +0+d +1 +FUNC +GLOBAL +HIDDEN +[0-9]+ +foo@@VERS_2
+ +[0-9]+: +0+d +1 +FUNC +GLOBAL +HIDDEN +[0-9]+ +foo@VERS_2
+#pass
diff --git a/gas/testsuite/gas/symver/symver13.s b/gas/testsuite/gas/symver/symver13.s
new file mode 100644 (file)
index 0000000..5426d86
--- /dev/null
@@ -0,0 +1,11 @@
+       .text
+       .space 13
+       .globl  foo
+       .type   foo, %function
+foo:
+       .byte 0
+       .symver foo, foo@VERS_2
+       .symver foo, foo@@VERS_2
+       .symver foo, foo@VERS_1
+       .hidden foo
+       .size foo,.-foo
diff --git a/gas/testsuite/gas/symver/symver14.l b/gas/testsuite/gas/symver/symver14.l
new file mode 100644 (file)
index 0000000..53fb7f4
--- /dev/null
@@ -0,0 +1,2 @@
+.*: Assembler messages:
+.*: Error: only one version name with `@@@' is allowed for symbol `foo'
diff --git a/gas/testsuite/gas/symver/symver14.s b/gas/testsuite/gas/symver/symver14.s
new file mode 100644 (file)
index 0000000..6693ff6
--- /dev/null
@@ -0,0 +1,6 @@
+       .data
+       .global foo
+foo:
+       .byte 1
+       .symver foo,foo@@@version1
+       .symver foo,foo@@@version2
diff --git a/gas/testsuite/gas/symver/symver15.l b/gas/testsuite/gas/symver/symver15.l
new file mode 100644 (file)
index 0000000..903a67c
--- /dev/null
@@ -0,0 +1,2 @@
+.*: Assembler messages:
+.*: Error: multiple versions \[`foo@version2'|`foo@version1'\] for symbol `foo'
diff --git a/gas/testsuite/gas/symver/symver15.s b/gas/testsuite/gas/symver/symver15.s
new file mode 100644 (file)
index 0000000..abf1860
--- /dev/null
@@ -0,0 +1,3 @@
+       .data
+       .symver foo,foo@version1
+       .symver foo,foo@version2
diff --git a/gas/testsuite/gas/symver/symver6.d b/gas/testsuite/gas/symver/symver6.d
new file mode 100644 (file)
index 0000000..cddf7ec
--- /dev/null
@@ -0,0 +1,11 @@
+#nm: -n
+#name: symver symver6
+#
+
+#...
+[      ]+U foo
+#...
+0+00000.. D foo1
+0+0000000 D foo@@version1
+0+00000.. D foo@version1
+0+00000.. d L_foo1
diff --git a/gas/testsuite/gas/symver/symver6.l b/gas/testsuite/gas/symver/symver6.l
deleted file mode 100644 (file)
index c2d12ae..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-.*: Assembler messages:
-.*:7: Error: multiple versions \[`foo@version1'|`foo@@version1'\] for symbol `foo'
-#pass
index 23d9fe20ee4a2b60ba1c792c5616e1c76d86e10f..b0bc0b8b22bd97deadc3c11e850679b5b6c5b0bb 100644 (file)
@@ -3,7 +3,7 @@
        .type foo1,object
 foo1:
        .long foo
        .type foo1,object
 foo1:
        .long foo
-       .symver foo,foo@@version1
-       .symver foo,foo@version1
+       .symver foo1,foo@@version1
+       .symver foo1,foo@version1
 L_foo1:
        .size foo1,L_foo1-foo1
 L_foo1:
        .size foo1,L_foo1-foo1
diff --git a/gas/testsuite/gas/symver/symver7.d b/gas/testsuite/gas/symver/symver7.d
new file mode 100644 (file)
index 0000000..5152678
--- /dev/null
@@ -0,0 +1,8 @@
+#readelf: -sW
+#name: symver symver7
+
+#...
+ +[0-9]+: +0+ +1 +OBJECT +GLOBAL +HIDDEN +[0-9]+ +foo
+ +[0-9]+: +0+ +1 +OBJECT +GLOBAL +DEFAULT +[0-9]+ +foo@version1
+ +[0-9]+: +0+ +1 +OBJECT +GLOBAL +DEFAULT +[0-9]+ +foo@@version2
+#pass
diff --git a/gas/testsuite/gas/symver/symver7.s b/gas/testsuite/gas/symver/symver7.s
new file mode 100644 (file)
index 0000000..20c11b7
--- /dev/null
@@ -0,0 +1,8 @@
+       .data
+       .globl foo
+       .type foo,%object
+foo:
+       .byte 0
+       .size foo,.-foo
+       .symver foo,foo@@version2,local
+       .symver foo,foo@version1,hidden
diff --git a/gas/testsuite/gas/symver/symver8.d b/gas/testsuite/gas/symver/symver8.d
new file mode 100644 (file)
index 0000000..8938aec
--- /dev/null
@@ -0,0 +1,9 @@
+#readelf: -sW
+#name: symver symver8
+
+#...
+ +[0-9]+: +0+ +1 +OBJECT +LOCAL +DEFAULT +[0-9]+ +foo
+#...
+ +[0-9]+: +0+ +1 +OBJECT +GLOBAL +DEFAULT +[0-9]+ +foo@version1
+ +[0-9]+: +0+ +1 +OBJECT +GLOBAL +DEFAULT +[0-9]+ +foo@@version2
+#pass
diff --git a/gas/testsuite/gas/symver/symver8.s b/gas/testsuite/gas/symver/symver8.s
new file mode 100644 (file)
index 0000000..17ab037
--- /dev/null
@@ -0,0 +1,8 @@
+       .data
+       .globl foo
+       .type foo,%object
+foo:
+       .byte 0
+       .size foo,.-foo
+       .symver foo,foo@@version2,hidden
+       .symver foo,foo@version1,local
diff --git a/gas/testsuite/gas/symver/symver9.s b/gas/testsuite/gas/symver/symver9.s
new file mode 100644 (file)
index 0000000..2f60897
--- /dev/null
@@ -0,0 +1,8 @@
+       .data
+       .globl foo
+       .type foo,%object
+foo:
+       .byte 0
+       .size foo,.-foo
+       .symver foo,foo@@version2
+       .symver foo,foo@version1,remove
diff --git a/gas/testsuite/gas/symver/symver9a.d b/gas/testsuite/gas/symver/symver9a.d
new file mode 100644 (file)
index 0000000..1cdbce8
--- /dev/null
@@ -0,0 +1,8 @@
+#source: symver9.s
+#readelf: -sW
+#name: symver symver9a
+
+#...
+ +[0-9]+: +0+ +1 +OBJECT +GLOBAL +DEFAULT +[0-9]+ +foo@version1
+ +[0-9]+: +0+ +1 +OBJECT +GLOBAL +DEFAULT +[0-9]+ +foo@@version2
+#pass
diff --git a/gas/testsuite/gas/symver/symver9b.d b/gas/testsuite/gas/symver/symver9b.d
new file mode 100644 (file)
index 0000000..383d1bd
--- /dev/null
@@ -0,0 +1,8 @@
+#source: symver9.s
+#readelf: -sW
+#name: symver symver9b
+
+#failif
+#...
+ +[0-9]+: +0+ +1 +OBJECT +GLOBAL +DEFAULT +[0-9]+ +foo
+#pass
This page took 0.052134 seconds and 4 git commands to generate.