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
index 6748c179f15ef331fe7e412f2b973b6f3b96477b..58d79caa41db695424a37307b6545b513cb35fee 100644 (file)
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -1,5 +1,8 @@
 -*- 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
index 5e7e8f0877963107b367965eda2ab5288b20900a..409ea4d6bed5ef4542bc772e9b7b372f9026bc1c 100644 (file)
@@ -1515,6 +1515,70 @@ obj_elf_line (int ignore ATTRIBUTE_UNUSED)
   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
@@ -1525,9 +1589,12 @@ static void
 obj_elf_symver (int ignore ATTRIBUTE_UNUSED)
 {
   char *name;
+  const char *sym_name;
   char c;
   char old_lexat;
   symbolS *sym;
+  struct elf_obj_sy *sy_obj;
+  char *p;
 
   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;
+  sym_name = S_GET_NAME (sym);
 
   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;
     }
 
-  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 ();
@@ -2382,6 +2465,7 @@ elf_frob_symbol (symbolS *symp, int *puntp)
 {
   struct elf_obj_sy *sy_obj;
   expressionS *size;
+  struct elf_versioned_name_list *versioned_name;
 
 #ifdef NEED_ECOFF_DEBUG
   if (ECOFF_DEBUGGING)
@@ -2409,73 +2493,47 @@ elf_frob_symbol (symbolS *symp, int *puntp)
       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.
-
         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
        {
-         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));
 
@@ -2498,6 +2556,27 @@ elf_frob_symbol (symbolS *symp, int *puntp)
              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))
-       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
 
+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.  */
-  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;
 
-  /* 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
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}
-* Symver::                      @code{.symver @var{name},@var{name2@@nodename}}
+* Symver::                      @code{.symver @var{name},@var{name2@@nodename}[,@var{visibility}]}
 @end ifset
 
 @ifset COFF
@@ -7112,9 +7112,9 @@ shared library.
 
 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
-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
@@ -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
-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
index de122eb61c3324792b9dd53fe7539c1104c2af1d..6b29a12d316fdbc3f6507e45cd3400a86268585b 100644 (file)
@@ -46,8 +46,13 @@ if { [is_elf_format] } then {
       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
@@ -56,5 +61,6 @@ if { [is_elf_format] } then {
     # 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
-       .symver foo,foo@@version1
-       .symver foo,foo@version1
+       .symver foo1,foo@@version1
+       .symver foo1,foo@version1
 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