diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index fa3aec79a48..c85d3482c8b 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -765,18 +765,6 @@ process_symver_attribute (symtab_node *n) "% cannot be versioned"); return; } - if (!TREE_PUBLIC (n->decl)) - { - error_at (DECL_SOURCE_LOCATION (n->decl), - "versioned symbol must be public"); - return; - } - if (DECL_VISIBILITY (n->decl) != VISIBILITY_DEFAULT) - { - error_at (DECL_SOURCE_LOCATION (n->decl), - "versioned symbol must have default visibility"); - return; - } /* Create new symbol table entry representing the version. */ tree new_decl = copy_node (n->decl); @@ -2239,8 +2227,7 @@ cgraph_node::assemble_thunks_and_aliases (void) of buffering it in same alias pairs. */ TREE_ASM_WRITTEN (decl) = 1; if (alias->symver) - do_assemble_symver (alias->decl, - DECL_ASSEMBLER_NAME (decl)); + do_assemble_symver (alias->decl, decl); else do_assemble_alias (alias->decl, DECL_ASSEMBLER_NAME (decl)); diff --git a/gcc/config/elfos.h b/gcc/config/elfos.h index 74a3eafda6b..6c9b73320b9 100644 --- a/gcc/config/elfos.h +++ b/gcc/config/elfos.h @@ -248,15 +248,17 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see } \ while (0) -#define ASM_OUTPUT_SYMVER_DIRECTIVE(FILE, NAME, NAME2) \ - do \ - { \ - fputs ("\t.symver\t", (FILE)); \ - assemble_name ((FILE), (NAME)); \ - fputs (", ", (FILE)); \ - assemble_name ((FILE), (NAME2)); \ - fputc ('\n', (FILE)); \ - } \ +#define ASM_OUTPUT_SYMVER_DIRECTIVE(FILE, NAME, NAME2, VISIBILITY) \ + do \ + { \ + fputs ("\t.symver\t", (FILE)); \ + assemble_name ((FILE), (NAME)); \ + fputs (", ", (FILE)); \ + assemble_name ((FILE), (NAME2)); \ + if (visibility != NULL) \ + fprintf ((FILE), ", %s", (VISIBILITY)); \ + fputc ('\n', (FILE)); \ + } \ while (0) /* The following macro defines the format used to output the second diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 97ae1ee0843..22e62f36714 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -3729,8 +3729,7 @@ On ELF targets this attribute creates a symbol version. The @var{name2} part of the parameter is the actual name of the symbol by which it will be externally referenced. The @code{nodename} portion should be the name of a node specified in the version script supplied to the linker when building a -shared library. Versioned symbol must be defined and must be exported with -default visibility. +shared library. @smallexample __attribute__ ((__symver__ ("foo@@VERS_1"))) int diff --git a/gcc/symtab.c b/gcc/symtab.c index d7dfbb676df..51628fe625f 100644 --- a/gcc/symtab.c +++ b/gcc/symtab.c @@ -1178,22 +1178,6 @@ symtab_node::verify_base (void) error ("node is symver but not alias"); error_found = true; } - /* Limitation of gas requires us to output targets of symver aliases as - global symbols. This is binutils PR 25295. */ - if (symver - && (!TREE_PUBLIC (get_alias_target ()->decl) - || DECL_VISIBILITY (get_alias_target ()->decl) != VISIBILITY_DEFAULT)) - { - error ("symver target is not exported with default visibility"); - error_found = true; - } - if (symver - && (!TREE_PUBLIC (decl) - || DECL_VISIBILITY (decl) != VISIBILITY_DEFAULT)) - { - error ("symver is not exported with default visibility"); - error_found = true; - } if (same_comdat_group) { symtab_node *n = same_comdat_group; diff --git a/gcc/testsuite/gcc.dg/ipa/symver2.c b/gcc/testsuite/gcc.dg/ipa/symver2.c new file mode 100644 index 00000000000..9cb50a54e08 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/symver2.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ + +__attribute__ ((__symver__ ("foo@VER_2"))) +static int foo() +{ + return 2; +} + +/* { dg-final { scan-assembler ".symver.*foo, foo@VER_2, remove" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/symver3.c b/gcc/testsuite/gcc.dg/ipa/symver3.c new file mode 100644 index 00000000000..fb30503d808 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/symver3.c @@ -0,0 +1,13 @@ +/* { dg-do link } */ +/* { dg-require-symver "" } */ + +__attribute__ ((__symver__ ("foo@VERS_2"))) +int foo() +{ + return 2; +} + +int main() +{ + return foo() - 2; +} diff --git a/gcc/varasm.c b/gcc/varasm.c index 84df52013d7..9a0f12e17f3 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -5964,15 +5964,23 @@ do_assemble_alias (tree decl, tree target) /* Output .symver directive. */ void -do_assemble_symver (tree decl, tree target) +do_assemble_symver (tree decl, tree origin_decl) { + tree target = DECL_ASSEMBLER_NAME (origin_decl); tree id = DECL_ASSEMBLER_NAME (decl); ultimate_transparent_alias_target (&id); ultimate_transparent_alias_target (&target); #ifdef ASM_OUTPUT_SYMVER_DIRECTIVE + const char *visibility = NULL; + if (!TREE_PUBLIC (origin_decl)) + visibility = "remove"; + else if (DECL_VISIBILITY (origin_decl) == VISIBILITY_INTERNAL) + visibility = "local"; + else if (DECL_VISIBILITY (origin_decl) == VISIBILITY_HIDDEN) + visibility = "hidden"; ASM_OUTPUT_SYMVER_DIRECTIVE (asm_out_file, IDENTIFIER_POINTER (target), - IDENTIFIER_POINTER (id)); + IDENTIFIER_POINTER (id), visibility); #else error ("symver is only supported on ELF platforms"); #endif diff --git a/gcc/varpool.c b/gcc/varpool.c index 458cdf1bf37..95d7844a398 100644 --- a/gcc/varpool.c +++ b/gcc/varpool.c @@ -540,8 +540,7 @@ varpool_node::assemble_aliases (void) { varpool_node *alias = dyn_cast (ref->referring); if (alias->symver) - do_assemble_symver (alias->decl, - DECL_ASSEMBLER_NAME (decl)); + do_assemble_symver (alias->decl, decl); else if (!alias->transparent_alias) do_assemble_alias (alias->decl, DECL_ASSEMBLER_NAME (decl));