Symver attribute

Message ID 20191115090505.fc7vvjxwstkbtkkh@kam.mff.cuni.cz
State New
Headers show
Series
  • Symver attribute
Related show

Commit Message

Jan Hubicka Nov. 15, 2019, 9:05 a.m.
Hi,
this patch implements symver attribute which can be use din place of
.symver directive and is LTO friendly.  I would welcome feedback for
this, in particular some evidence that codebases can be easily converted
to use it.

There is some discussion in the PR and its duplicate filled by Carlos.
He suggests bit more elaborate syntax then just passing name@nodename
as a string.  I can implement it easily if that is preferred based on
the current infrastructure (basically handle_symver_attribute will need
to parse the parameters and produce the actual assembler name).

I found the PR only after drafing the patch and my goal was to keep
things similar to .symver GAS directive.  I am not sure which variant is
preferred. I sort of like to keep symver attribute name same as the gas
directive and i think users are used to the node@nodename strings since
they appear everywhere else.

Internally the patch tries to mimic what happens in ELF.  In particular

__attribute__ ((__symver__ ("foo@VERS_1"))) int
foo_v1 (void)
{
}

creates a special form of alias with symver flag. Its assembler name is
foo@VERS_1 since it is what happens in ELF too (normally @ is not
allowed in symbol name).  Rest of GCC and LTO path handles is as normal
alias (since it seems what binutils does as well) and instead of
outputting it via .set we use .symver directive at the end.

I added some sanity checks: for duplicated directives, for versions of
weakrefs and commons (which are not accepted by gas) and for versions of
symbols not exported to final symbol table (which are accepted by gas
but seems to have no effect).

I am by no means expert in the area so feedback is welcome.  I would
like to get the patch to trunk early next week if it works well.

Also I wonder for testsuite bits, I think I need to implement
dl-require-symver and then use it to gate the individual tests? Or do we
have some common way to check for ELF?

Honza

	PR lto/48200
	* c-family/c-attribs.c (handle_symver_attribute): New.
	(c_common_attribytes): Add symver.
	* cgraph.h (symtab_node): Add symver flag.
	* cgraphunit.c (process_symver_attribute): New.
	(process_common_attributes): Use it.
	(cgraph_node::assemble_thunks_and_aliases): Assemble symvers.
	* config/elfos.h (ASM_OUTPUT_SYMVER_DIRECTIVE): New.
	* lto-cgraph.c (lto_output_node, lto_output_varpool_node,
	input_overwrite_node, input_varpool_node): Stream symver attributes.
	* output.h (do_assemble_symver): Declare.
	* symtab.c (symtab_node::dump_base): Dump symver flag.
	(symtab_node::verify_base): Sanity check symver.
	* varasm.c (do_assemble_symver): New.
	* varpool.c (varpool_node::assemble_aliases): Output symver.

	* doc/extend.texi (symver): Document new attribute.

Comments

Florian Weimer Nov. 15, 2019, 9:47 a.m. | #1
* Jan Hubicka:

> Internally the patch tries to mimic what happens in ELF.  In particular

>

> __attribute__ ((__symver__ ("foo@VERS_1"))) int

> foo_v1 (void)

> {

> }

>

> creates a special form of alias with symver flag. Its assembler name is

> foo@VERS_1 since it is what happens in ELF too (normally @ is not

> allowed in symbol name).  Rest of GCC and LTO path handles is as normal

> alias (since it seems what binutils does as well) and instead of

> outputting it via .set we use .symver directive at the end.


Do you support foo@@VERS_1 for setting the default version as well?

It's sometimes useful to define multiple versions for a single symbol.
For maximum binutils compatibility, you would have to use intermediate
aliases.  __attribute__ ((__symver__ ("foo@VERS_1", "foo@@VERS_2")))
could turn into this:

  .set foo_v1.symver.1, foo_v1
  .symver foo_v1.symver.1, foo_v1@VERS_1
  .set foo_v1.symver.2, foo_v1
  .symver foo_v1.symver.2, foo_v1@@VERS_2

Sometimes it's also necessary to reference a symbol version.  I
suspect we'd need a separate attribute for that, or enhance the
__asm__ alias code to recognize @ and @@ symbols (also creating
internal aliases).

We would use both extensions (multiple symbol versions and symbol
references) internally for glibc eventually, once compiler versions
before GCC 10 are no longer supported.
Jan Hubicka Nov. 15, 2019, 10:02 a.m. | #2
> * Jan Hubicka:

> 

> > Internally the patch tries to mimic what happens in ELF.  In particular

> >

> > __attribute__ ((__symver__ ("foo@VERS_1"))) int

> > foo_v1 (void)

> > {

> > }

> >

> > creates a special form of alias with symver flag. Its assembler name is

> > foo@VERS_1 since it is what happens in ELF too (normally @ is not

> > allowed in symbol name).  Rest of GCC and LTO path handles is as normal

> > alias (since it seems what binutils does as well) and instead of

> > outputting it via .set we use .symver directive at the end.

> 

> Do you support foo@@VERS_1 for setting the default version as well?


Yes, i only reject the string if number of @'s is less then 1 or more
than 2 :)
(I wonder if there is better checking on that string)
> 

> It's sometimes useful to define multiple versions for a single symbol.

> For maximum binutils compatibility, you would have to use intermediate

> aliases.  __attribute__ ((__symver__ ("foo@VERS_1", "foo@@VERS_2")))

> could turn into this:

> 

>   .set foo_v1.symver.1, foo_v1

>   .symver foo_v1.symver.1, foo_v1@VERS_1

>   .set foo_v1.symver.2, foo_v1

>   .symver foo_v1.symver.2, foo_v1@@VERS_2


I was originaly supporting multiple symvers like:
__attribute__ ((__symver__ ("foo@VERS_1"))) int
__attribute__ ((__symver__ ("foo@VERS_2"))) int
foo_v1 (void)
{
}

but then noticed it is rejected by gas.

I intended to support:

__attribute__ ((__symver__ ("foo@VERS_1"))) int
foo_v1 (void)
{
}

int symver_foo_v1 (void)
__attribute__ ((__symver__ ("foo@VERS_2")))
__attribute__ ((alias ("foo_v1")))

This describes what you want to do: create an alias symbol and then
attach version to it.  This is broken in current patch (though i
indended it to work).  I will fix that:
        .symver foo_v1, foo@VERS_2
        .globl  symver_foo_v1
        .set    symver_foo_v1,foo_v1
        .symver foo_v1, foo@VERS_1
GCC currently redirect aliases to the their ultimate targets. I need to
implement an exception here. (We already do that for weakrefs and
syntactic aliases)

It would be prettier to support former but we need an exported symbol
name for the second alis, right?

Honza
> 

> Sometimes it's also necessary to reference a symbol version.  I

> suspect we'd need a separate attribute for that, or enhance the

> __asm__ alias code to recognize @ and @@ symbols (also creating

> internal aliases).

> 

> We would use both extensions (multiple symbol versions and symbol

> references) internally for glibc eventually, once compiler versions

> before GCC 10 are no longer supported.
Florian Weimer Nov. 15, 2019, 10:36 a.m. | #3
* Jan Hubicka:

>> It's sometimes useful to define multiple versions for a single symbol.

>> For maximum binutils compatibility, you would have to use intermediate

>> aliases.  __attribute__ ((__symver__ ("foo@VERS_1", "foo@@VERS_2")))

>> could turn into this:

>> 

>>   .set foo_v1.symver.1, foo_v1

>>   .symver foo_v1.symver.1, foo_v1@VERS_1

>>   .set foo_v1.symver.2, foo_v1

>>   .symver foo_v1.symver.2, foo_v1@@VERS_2

>

> I was originaly supporting multiple symvers like:

> __attribute__ ((__symver__ ("foo@VERS_1"))) int

> __attribute__ ((__symver__ ("foo@VERS_2"))) int

> foo_v1 (void)

> {

> }

>

> but then noticed it is rejected by gas.


Yeah, I think that failure is somewhat dependent on the target and the
GAS version.

> I intended to support:

>

> __attribute__ ((__symver__ ("foo@VERS_1"))) int

> foo_v1 (void)

> {

> }

>

> int symver_foo_v1 (void)

> __attribute__ ((__symver__ ("foo@VERS_2")))

> __attribute__ ((alias ("foo_v1")))


That's a bit of a mouthful.  We probably could hide it behind a macro
using __COUNTER.

> It would be prettier to support former but we need an exported symbol

> name for the second alis, right?


I assumed that .symver would make the versioned alias global, but
sadly it does not.  You are right, you currently need to start with a
global symbol.  Maybe there is a way around that.  I'm going to ask on
the binutils list.
Martin Liška Nov. 15, 2019, 2:01 p.m. | #4
On 11/15/19 10:05 AM, Jan Hubicka wrote:
> Index: params.opt

> ===================================================================

> --- params.opt	(revision 278220)

> +++ params.opt	(working copy)

> @@ -483,7 +483,7 @@ Common Joined UInteger Var(param_max_inl

>   The maximum number of instructions in a single function eligible for inlining with -O3 and -Ofast.

>   

>   -param=max-inline-insns-single-O2=

> -Common Joined UInteger Var(param_max_inline_insns_single_o2) Init(30) Param

> +Common Joined UInteger Var(param_max_inline_insns_single_o2) Init(70) Param

>   The maximum number of instructions in a single function eligible for inlining.

>   

>   -param=max-inline-insns-size=


The following hunk is definitely not intended :)

Martin
Martin Liška Nov. 15, 2019, 2:43 p.m. | #5
On 11/15/19 10:05 AM, Jan Hubicka wrote:
> I am by no means expert in the area so feedback is welcome.  I would

> like to get the patch to trunk early next week if it works well.


Thank you Honza for the patch. The idea looks nice to me and I have just
few comments:

1) we should also support foo@@@VER_1 format:
https://sourceware.org/binutils/docs/as/Symver.html#Symver

2) I quoted some error format messages

Martin
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 8dcd38631d2..1723111bec0 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -2338,12 +2338,11 @@ handle_symver_attribute (tree *node, tree ARG_UNUSED (name), tree args,
 {
   tree symver;
   const char *symver_str;
-  unsigned n;
 
   if (TREE_CODE (*node) != FUNCTION_DECL && TREE_CODE (*node) != VAR_DECL)
     {
       warning (OPT_Wattributes,
-	       "symver attribute is only applicable on functions and variables");
+	       "%<symver%> attribute is only applicable on functions and variables");
       *no_add_attrs = true;
       return NULL_TREE;
     }
@@ -2351,7 +2350,7 @@ handle_symver_attribute (tree *node, tree ARG_UNUSED (name), tree args,
   if (!decl_in_symtab_p (*node))
     {
       warning (OPT_Wattributes,
-	       "symver attribute is only applicable to symbols");
+	       "%<symver%> attribute is only applicable to symbols");
       *no_add_attrs = true;
       return NULL_TREE;
     }
@@ -2361,7 +2360,7 @@ handle_symver_attribute (tree *node, tree ARG_UNUSED (name), tree args,
       symver = TREE_VALUE (args);
       if (TREE_CODE (symver) != STRING_CST)
 	{
-	  error ("symver attribute argument not a string constant");
+	  error ("%<symver%> attribute argument not a string constant");
 	  *no_add_attrs = true;
 	  return NULL_TREE;
 	}
@@ -2369,13 +2368,14 @@ handle_symver_attribute (tree *node, tree ARG_UNUSED (name), tree args,
       symver_str = TREE_STRING_POINTER (symver);
 
       int ats = 0;
-      for (n = 0; n < TREE_STRING_LENGTH (symver); n++)
+      for (int n = 0; n < TREE_STRING_LENGTH (symver); n++)
 	if (symver_str[n] == '@')
 	  ats++;
 
-      if (ats != 1 && ats != 2)
+      if (ats < 1 || ats > 3)
 	{
-	  error ("symver attribute argument must have format %<name@nodename%>");
+	  error ("%<symver%> attribute argument %qs must contain one, "
+		 "two or three %<@%>", symver_str);
 	  *no_add_attrs = true;
 	  return NULL_TREE;
 	}
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index b45a864f3ed..c7caff5023a 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -776,7 +776,7 @@ process_symver_attribute (symtab_node *n)
       return;
     }
 
-  /* Create new symbol table entry represneting the version.  */
+  /* Create new symbol table entry representing the version.  */
   tree new_decl = copy_node (n->decl);
 
   DECL_INITIAL (new_decl) = NULL_TREE;
Jan Hubicka Nov. 15, 2019, 4:04 p.m. | #6
Hi,
thanks for feedback. Here is updated patch that incorporates Martin's
changes, formatting corrections and makes symvers of aliases work.

Honza

	* c-family/c-attribs.c (handle_symver_attribute): New.
	(c_common_attribytes): Add symver.
	* cgraph.h (symtab_node): Add symver flag.
	* cgraphunit.c (process_symver_attribute): New.
	(process_common_attributes): Use it.
	(cgraph_node::assemble_thunks_and_aliases): Assemble symvers.
	* config/elfos.h (ASM_OUTPUT_SYMVER_DIRECTIVE): New.
	* lto-cgraph.c (lto_output_node, lto_output_varpool_node,
	input_overwrite_node, input_varpool_node): Stream symver attributes.
	* output.h (do_assemble_symver): Declare.
	* symtab.c (symtab_node::dump_base): Dump symver flag.
	(symtab_node::verify_base): Sanity check symver.
	(symtab_node::resolve_alias): Add support for symvers.
	* varasm.c (do_assemble_symver): New.
	* varpool.c (varpool_node::assemble_aliases): Output symver.

	* doc/extend.texi (symver): Document new attribute.
Index: c-family/c-attribs.c
===================================================================
--- c-family/c-attribs.c	(revision 278293)
+++ c-family/c-attribs.c	(working copy)
@@ -146,6 +146,7 @@ static tree handle_omp_declare_target_at
 static tree handle_designated_init_attribute (tree *, tree, tree, int, bool *);
 static tree handle_patchable_function_entry_attribute (tree *, tree, tree,
 						       int, bool *);
+static tree handle_symver_attribute (tree *, tree, tree, int, bool *);
 static tree handle_copy_attribute (tree *, tree, tree, int, bool *);
 
 /* Helper to define attribute exclusions.  */
@@ -473,6 +474,8 @@ const struct attribute_spec c_common_att
 			      NULL },
   { "nocf_check",	      0, 0, false, true, true, true,
 			      handle_nocf_check_attribute, NULL },
+  { "symver",		      1, -1, true, false, false, false,
+			      handle_symver_attribute, NULL},
   { "copy",                   1, 1, false, false, false, false,
 			      handle_copy_attribute, NULL },
   { "noinit",		      0, 0, true,  false, false, false,
@@ -2329,6 +2332,59 @@ handle_noplt_attribute (tree *node, tree
   return NULL_TREE;
 }
 
+static tree
+handle_symver_attribute (tree *node, tree ARG_UNUSED (name), tree args,
+			 int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  tree symver;
+  const char *symver_str;
+
+  if (TREE_CODE (*node) != FUNCTION_DECL && TREE_CODE (*node) != VAR_DECL)
+    {
+      warning (OPT_Wattributes,
+	       "%<symver%> attribute is only applicable on functions and "
+	       "variables");
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  if (!decl_in_symtab_p (*node))
+    {
+      warning (OPT_Wattributes,
+	       "%<symver%> attribute is only applicable to symbols");
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  for (; args; args = TREE_CHAIN (args))
+    {
+      symver = TREE_VALUE (args);
+      if (TREE_CODE (symver) != STRING_CST)
+	{
+	  error ("%<symver%> attribute argument not a string constant");
+	  *no_add_attrs = true;
+	  return NULL_TREE;
+	}
+
+      symver_str = TREE_STRING_POINTER (symver);
+
+      int ats = 0;
+      for (int n = 0; n < TREE_STRING_LENGTH (symver); n++)
+	if (symver_str[n] == '@')
+	  ats++;
+
+      if (ats != 1 && ats != 2)
+	{
+	  error ("symver attribute argument must have format "
+		 "%<name@nodename%>");
+	  *no_add_attrs = true;
+	  return NULL_TREE;
+	}
+    }
+
+  return NULL_TREE;
+}
+
 /* Handle an "alias" or "ifunc" attribute; arguments as in
    struct attribute_spec.handler, except that IS_ALIAS tells us
    whether this is an alias as opposed to ifunc attribute.  */
Index: cgraph.h
===================================================================
--- cgraph.h	(revision 278293)
+++ cgraph.h	(working copy)
@@ -497,6 +497,8 @@ public:
      and their visibility needs to be copied from their "masters" at
      the end of parsing.  */
   unsigned cpp_implicit_alias : 1;
+  /* The alias is a symbol version.  */
+  unsigned symver : 1;
   /* Set once the definition was analyzed.  The list of references and
      other properties are built during analysis.  */
   unsigned analyzed : 1;
Index: cgraphunit.c
===================================================================
--- cgraphunit.c	(revision 278293)
+++ cgraphunit.c	(working copy)
@@ -711,6 +711,89 @@ symbol_table::process_same_body_aliases
   cpp_implicit_aliases_done = true;
 }
 
+/* Process a symver attribute.  */
+
+static void
+process_symver_attribute (symtab_node *n)
+{
+  tree value = lookup_attribute ("symver", DECL_ATTRIBUTES (n->decl));
+
+  if (!value)
+    return;
+  if (lookup_attribute ("symver", TREE_CHAIN (value)))
+    {
+      error_at (DECL_SOURCE_LOCATION (n->decl),
+		"multiple versions for one symbol");
+      return;
+    }
+  tree symver = get_identifier_with_length
+		  (TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (value))),
+		   TREE_STRING_LENGTH (TREE_VALUE (TREE_VALUE (value))));
+  symtab_node *def = symtab_node::get_for_asmname (symver);
+
+  if (def)
+    {
+      error_at (DECL_SOURCE_LOCATION (n->decl),
+		"duplicate definition of a symbol version");
+      inform (DECL_SOURCE_LOCATION (def->decl),
+	      "same version was previously defined here");
+      return;
+    }
+  if (!n->definition)
+    {
+      error_at (DECL_SOURCE_LOCATION (n->decl),
+		"symbol needs to be defined to have a version");
+      return;
+    }
+  if (DECL_COMMON (n->decl))
+    {
+      error_at (DECL_SOURCE_LOCATION (n->decl),
+		"common symbol can't be versioned");
+      return;
+    }
+  if (DECL_COMDAT (n->decl))
+    {
+      error_at (DECL_SOURCE_LOCATION (n->decl),
+		"comdat symbol can't be versioned");
+      return;
+    }
+  if (n->weakref)
+    {
+      error_at (DECL_SOURCE_LOCATION (n->decl),
+		"weakref can't 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);
+
+  DECL_INITIAL (new_decl) = NULL_TREE;
+  if (TREE_CODE (new_decl) == FUNCTION_DECL)
+    DECL_STRUCT_FUNCTION (new_decl) = NULL;
+  SET_DECL_ASSEMBLER_NAME (new_decl, symver);
+  TREE_PUBLIC (new_decl) = 1;
+  DECL_ATTRIBUTES (new_decl) = NULL;
+
+  symtab_node *symver_node = symtab_node::get_create (new_decl);
+  symver_node->alias = true;
+  symver_node->definition = true;
+  symver_node->symver = true;
+  symver_node->create_reference (n, IPA_REF_ALIAS, NULL);
+  symver_node->analyzed = true;
+}
+
 /* Process attributes common for vars and functions.  */
 
 static void
@@ -730,6 +813,7 @@ process_common_attributes (symtab_node *
 
   if (lookup_attribute ("no_reorder", DECL_ATTRIBUTES (decl)))
     node->no_reorder = 1;
+  process_symver_attribute (node);
 }
 
 /* Look for externally_visible and used attributes and mark cgraph nodes
@@ -2137,8 +2221,12 @@ cgraph_node::assemble_thunks_and_aliases
 	  /* Force assemble_alias to really output the alias this time instead
 	     of buffering it in same alias pairs.  */
 	  TREE_ASM_WRITTEN (decl) = 1;
-	  do_assemble_alias (alias->decl,
-			     DECL_ASSEMBLER_NAME (decl));
+	  if (alias->symver)
+	    do_assemble_symver (alias->decl,
+				DECL_ASSEMBLER_NAME (decl));
+	  else
+	    do_assemble_alias (alias->decl,
+			       DECL_ASSEMBLER_NAME (decl));
 	  alias->assemble_thunks_and_aliases ();
 	  TREE_ASM_WRITTEN (decl) = saved_written;
 	}
Index: config/elfos.h
===================================================================
--- config/elfos.h	(revision 278293)
+++ config/elfos.h	(working copy)
@@ -248,6 +248,17 @@ see the files COPYING3 and COPYING.RUNTI
     }					\
   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));					\
+    }								\
+  while (0)
+
 /* The following macro defines the format used to output the second
    operand of the .type assembler directive.  Different svr4 assemblers
    expect various different forms for this operand.  The one given here
Index: doc/extend.texi
===================================================================
--- doc/extend.texi	(revision 278293)
+++ doc/extend.texi	(working copy)
@@ -3640,6 +3640,34 @@ Function Attributes}, @ref{PowerPC Funct
 @ref{Nios II Function Attributes}, and @ref{S/390 Function Attributes}
 for details.
 
+@item symver ("@var{name2}@@@var{nodename}")
+On ELF targets this attribute creates 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 of the alias 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.
+
+@smallexample
+__attribute__ ((__symver__ ("foo@@VERS_1"))) int
+foo_v1 (void)
+@{
+@}
+@end smallexample
+
+Will produce @code{.symver foo_v1, foo@@VERS_1} directive in the assembler
+output.  It is not allowed to make multiple versions out of one symbol, however
+versioned symbol may also be an alias.
+
+@smallexample
+__attribute__ ((__symver__ ("foo@VERS_2")))
+__attribute__ ((alias ("foo_v1")))
+int symver_foo_v1 (void);
+@end smallexample
+
+This example creates alias an of @code{foo_v1} with symbol name
+@code{symver_foo_v1} which will be version @code{VERS_2} of @code{foo}.
+
 @item target_clones (@var{options})
 @cindex @code{target_clones} function attribute
 The @code{target_clones} attribute is used to specify that a function
Index: lto-cgraph.c
===================================================================
--- lto-cgraph.c	(revision 278293)
+++ lto-cgraph.c	(working copy)
@@ -526,6 +526,7 @@ lto_output_node (struct lto_simple_outpu
   bp_pack_value (&bp, node->alias, 1);
   bp_pack_value (&bp, node->transparent_alias, 1);
   bp_pack_value (&bp, node->weakref, 1);
+  bp_pack_value (&bp, node->symver, 1);
   bp_pack_value (&bp, node->frequency, 2);
   bp_pack_value (&bp, node->only_called_at_startup, 1);
   bp_pack_value (&bp, node->only_called_at_exit, 1);
@@ -606,6 +607,7 @@ lto_output_varpool_node (struct lto_simp
   bp_pack_value (&bp, node->alias, 1);
   bp_pack_value (&bp, node->transparent_alias, 1);
   bp_pack_value (&bp, node->weakref, 1);
+  bp_pack_value (&bp, node->symver, 1);
   bp_pack_value (&bp, node->analyzed && (!boundary_p || node->alias), 1);
   gcc_assert (node->definition || !node->analyzed);
   /* Constant pool initializers can be de-unified into individual ltrans units.
@@ -1170,6 +1172,7 @@ input_overwrite_node (struct lto_file_de
   node->alias = bp_unpack_value (bp, 1);
   node->transparent_alias = bp_unpack_value (bp, 1);
   node->weakref = bp_unpack_value (bp, 1);
+  node->symver = bp_unpack_value (bp, 1);
   node->frequency = (enum node_frequency)bp_unpack_value (bp, 2);
   node->only_called_at_startup = bp_unpack_value (bp, 1);
   node->only_called_at_exit = bp_unpack_value (bp, 1);
@@ -1363,6 +1366,7 @@ input_varpool_node (struct lto_file_decl
   node->alias = bp_unpack_value (&bp, 1);
   node->transparent_alias = bp_unpack_value (&bp, 1);
   node->weakref = bp_unpack_value (&bp, 1);
+  node->symver = bp_unpack_value (&bp, 1);
   node->analyzed = bp_unpack_value (&bp, 1);
   node->used_from_other_partition = bp_unpack_value (&bp, 1);
   node->in_other_partition = bp_unpack_value (&bp, 1);
Index: output.h
===================================================================
--- output.h	(revision 278293)
+++ output.h	(working copy)
@@ -167,6 +167,7 @@ extern int decode_reg_name (const char *
 extern int decode_reg_name_and_count (const char *, int *);
 
 extern void do_assemble_alias (tree, tree);
+extern void do_assemble_symver (tree, tree);
 
 extern void default_assemble_visibility (tree, int);
 
Index: symtab.c
===================================================================
--- symtab.c	(revision 278293)
+++ symtab.c	(working copy)
@@ -848,6 +848,8 @@ symtab_node::dump_base (FILE *f)
     fprintf (f, " transparent_alias");
   if (weakref)
     fprintf (f, " weakref");
+  if (symver)
+    fprintf (f, " symver");
   if (cpp_implicit_alias)
     fprintf (f, " cpp_implicit_alias");
   if (alias_target)
@@ -1145,6 +1147,11 @@ symtab_node::verify_base (void)
       error ("node is transparent_alias but not an alias");
       error_found = true;
     }
+  if (symver && !alias)
+    {
+      error ("node is symver but not alias");
+      error_found = true;
+    }
   if (same_comdat_group)
     {
       symtab_node *n = same_comdat_group;
@@ -1780,7 +1787,9 @@ symtab_node::resolve_alias (symtab_node
 	  if (target->get_comdat_group ())
 	    alias_alias->add_to_same_comdat_group (target);
 	}
-      if (!alias_alias->transparent_alias || transparent)
+      if ((!alias_alias->transparent_alias
+	   && !alias_alias->symver)
+	  || transparent)
 	{
 	  alias_alias->remove_all_references ();
 	  alias_alias->create_reference (target, IPA_REF_ALIAS, NULL);
Index: varasm.c
===================================================================
--- varasm.c	(revision 278293)
+++ varasm.c	(working copy)
@@ -1921,6 +1921,7 @@ assemble_end_function (tree decl, const
     switch_to_section (function_section (decl));
   ASM_DECLARE_FUNCTION_SIZE (asm_out_file, fnname, decl);
 #endif
+
   if (! CONSTANT_POOL_BEFORE_FUNCTION)
     {
       output_constant_pool (fnname, decl);
@@ -5960,6 +5961,23 @@ do_assemble_alias (tree decl, tree targe
 #endif
 }
 
+/* Output .symver directive.  */
+
+void
+do_assemble_symver (tree decl, tree target)
+{
+  tree id = DECL_ASSEMBLER_NAME (decl);
+  ultimate_transparent_alias_target (&id);
+  ultimate_transparent_alias_target (&target);
+#ifdef ASM_OUTPUT_SYMVER_DIRECTIVE
+  ASM_OUTPUT_SYMVER_DIRECTIVE (asm_out_file,
+			       IDENTIFIER_POINTER (target),
+			       IDENTIFIER_POINTER (id));
+#else
+  error ("symver is only supported on ELF platforms");
+#endif
+}
+
 /* Emit an assembler directive to make the symbol for DECL an alias to
    the symbol for TARGET.  */
 
Index: varpool.c
===================================================================
--- varpool.c	(revision 278293)
+++ varpool.c	(working copy)
@@ -540,7 +540,10 @@ varpool_node::assemble_aliases (void)
   FOR_EACH_ALIAS (this, ref)
     {
       varpool_node *alias = dyn_cast <varpool_node *> (ref->referring);
-      if (!alias->transparent_alias)
+      if (alias->symver)
+	do_assemble_symver (alias->decl,
+			    DECL_ASSEMBLER_NAME (decl));
+      else if (!alias->transparent_alias)
 	do_assemble_alias (alias->decl,
 			   DECL_ASSEMBLER_NAME (decl));
       alias->assemble_aliases ();
Joseph Myers Nov. 15, 2019, 6:19 p.m. | #7
On Fri, 15 Nov 2019, Jan Hubicka wrote:

> I was originaly supporting multiple symvers like:

> __attribute__ ((__symver__ ("foo@VERS_1"))) int

> __attribute__ ((__symver__ ("foo@VERS_2"))) int

> foo_v1 (void)

> {

> }

> 

> but then noticed it is rejected by gas.


That's <https://sourceware.org/bugzilla/show_bug.cgi?id=23840>.

> int symver_foo_v1 (void)

> __attribute__ ((__symver__ ("foo@VERS_2")))

> __attribute__ ((alias ("foo_v1")))

> 

> This describes what you want to do: create an alias symbol and then

> attach version to it.  This is broken in current patch (though i


I'd rather GCC created those aliases automatically (with names that can't 
be used as C symbols, e.g. containing '.', if possible, or failing that 
implementation-namespace names that are unlikely to conflict with C 
symbols), so that the API doesn't replicate a peculiarity of the assembler 
implementation.

-- 
Joseph S. Myers
joseph@codesourcery.com
Martin Sebor Nov. 16, 2019, 1:21 a.m. | #8
On 11/15/19 9:04 AM, Jan Hubicka wrote:
> Hi,

> thanks for feedback. Here is updated patch that incorporates Martin's

> changes, formatting corrections and makes symvers of aliases work.


Just a couple of questions and a few minor nits, mostly having to
do with my favorite subject of quoting things in diagnostics ;-)

> 

> Honza

> 

> 	* c-family/c-attribs.c (handle_symver_attribute): New.

> 	(c_common_attribytes): Add symver.

> 	* cgraph.h (symtab_node): Add symver flag.

> 	* cgraphunit.c (process_symver_attribute): New.

> 	(process_common_attributes): Use it.

> 	(cgraph_node::assemble_thunks_and_aliases): Assemble symvers.

> 	* config/elfos.h (ASM_OUTPUT_SYMVER_DIRECTIVE): New.

> 	* lto-cgraph.c (lto_output_node, lto_output_varpool_node,

> 	input_overwrite_node, input_varpool_node): Stream symver attributes.

> 	* output.h (do_assemble_symver): Declare.

> 	* symtab.c (symtab_node::dump_base): Dump symver flag.

> 	(symtab_node::verify_base): Sanity check symver.

> 	(symtab_node::resolve_alias): Add support for symvers.

> 	* varasm.c (do_assemble_symver): New.

> 	* varpool.c (varpool_node::assemble_aliases): Output symver.

> 

> 	* doc/extend.texi (symver): Document new attribute.

> Index: c-family/c-attribs.c

> ===================================================================

> --- c-family/c-attribs.c	(revision 278293)

> +++ c-family/c-attribs.c	(working copy)

> @@ -146,6 +146,7 @@ static tree handle_omp_declare_target_at

>   static tree handle_designated_init_attribute (tree *, tree, tree, int, bool *);

>   static tree handle_patchable_function_entry_attribute (tree *, tree, tree,

>   						       int, bool *);

> +static tree handle_symver_attribute (tree *, tree, tree, int, bool *);

>   static tree handle_copy_attribute (tree *, tree, tree, int, bool *);

>   

>   /* Helper to define attribute exclusions.  */

> @@ -473,6 +474,8 @@ const struct attribute_spec c_common_att

>   			      NULL },

>     { "nocf_check",	      0, 0, false, true, true, true,

>   			      handle_nocf_check_attribute, NULL },

> +  { "symver",		      1, -1, true, false, false, false,

> +			      handle_symver_attribute, NULL},

>     { "copy",                   1, 1, false, false, false, false,

>   			      handle_copy_attribute, NULL },

>     { "noinit",		      0, 0, true,  false, false, false,

> @@ -2329,6 +2332,59 @@ handle_noplt_attribute (tree *node, tree

>     return NULL_TREE;

>   }

>   

> +static tree

> +handle_symver_attribute (tree *node, tree ARG_UNUSED (name), tree args,

> +			 int ARG_UNUSED (flags), bool *no_add_attrs)

> +{

> +  tree symver;

> +  const char *symver_str;

> +

> +  if (TREE_CODE (*node) != FUNCTION_DECL && TREE_CODE (*node) != VAR_DECL)


Should the attribute apply to member functions as well?  If not,
FWIW, I think VAR_OR_FUNCTION_DECL_P() tests for just functions
and variables.

> +    {

> +      warning (OPT_Wattributes,

> +	       "%<symver%> attribute is only applicable on functions and "

> +	       "variables");


"applicable to functions" as below (though I think the far more
common phrase among GCC messages is "applies to functions").

> +      *no_add_attrs = true;

> +      return NULL_TREE;

> +    }

> +

> +  if (!decl_in_symtab_p (*node))

> +    {

> +      warning (OPT_Wattributes,

> +	       "%<symver%> attribute is only applicable to symbols");

> +      *no_add_attrs = true;

> +      return NULL_TREE;

> +    }

> +

> +  for (; args; args = TREE_CHAIN (args))

> +    {

> +      symver = TREE_VALUE (args);

> +      if (TREE_CODE (symver) != STRING_CST)

> +	{

> +	  error ("%<symver%> attribute argument not a string constant");

> +	  *no_add_attrs = true;

> +	  return NULL_TREE;

> +	}

> +

> +      symver_str = TREE_STRING_POINTER (symver);

> +

> +      int ats = 0;

> +      for (int n = 0; n < TREE_STRING_LENGTH (symver); n++)

> +	if (symver_str[n] == '@')

> +	  ats++;

> +

> +      if (ats != 1 && ats != 2)

> +	{

> +	  error ("symver attribute argument must have format "


The "symver" part should be quoted same as above.

> +		 "%<name@nodename%>");

> +	  *no_add_attrs = true;

> +	  return NULL_TREE;

> +	}

> +    }

> +

> +  return NULL_TREE;

> +}

> +

>   /* Handle an "alias" or "ifunc" attribute; arguments as in

>      struct attribute_spec.handler, except that IS_ALIAS tells us

>      whether this is an alias as opposed to ifunc attribute.  */

> Index: cgraph.h

> ===================================================================

> --- cgraph.h	(revision 278293)

> +++ cgraph.h	(working copy)

> @@ -497,6 +497,8 @@ public:

>        and their visibility needs to be copied from their "masters" at

>        the end of parsing.  */

>     unsigned cpp_implicit_alias : 1;

> +  /* The alias is a symbol version.  */

> +  unsigned symver : 1;

>     /* Set once the definition was analyzed.  The list of references and

>        other properties are built during analysis.  */

>     unsigned analyzed : 1;

> Index: cgraphunit.c

> ===================================================================

> --- cgraphunit.c	(revision 278293)

> +++ cgraphunit.c	(working copy)

> @@ -711,6 +711,89 @@ symbol_table::process_same_body_aliases

>     cpp_implicit_aliases_done = true;

>   }

>   

> +/* Process a symver attribute.  */

> +

> +static void

> +process_symver_attribute (symtab_node *n)

> +{

> +  tree value = lookup_attribute ("symver", DECL_ATTRIBUTES (n->decl));

> +

> +  if (!value)

> +    return;

> +  if (lookup_attribute ("symver", TREE_CHAIN (value)))

> +    {

> +      error_at (DECL_SOURCE_LOCATION (n->decl),

> +		"multiple versions for one symbol");

> +      return;

> +    }

> +  tree symver = get_identifier_with_length

> +		  (TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (value))),

> +		   TREE_STRING_LENGTH (TREE_VALUE (TREE_VALUE (value))));

> +  symtab_node *def = symtab_node::get_for_asmname (symver);

> +

> +  if (def)

> +    {

> +      error_at (DECL_SOURCE_LOCATION (n->decl),

> +		"duplicate definition of a symbol version");

> +      inform (DECL_SOURCE_LOCATION (def->decl),

> +	      "same version was previously defined here");

> +      return;

> +    }

> +  if (!n->definition)

> +    {

> +      error_at (DECL_SOURCE_LOCATION (n->decl),

> +		"symbol needs to be defined to have a version");

> +      return;

> +    }

> +  if (DECL_COMMON (n->decl))

> +    {

> +      error_at (DECL_SOURCE_LOCATION (n->decl),

> +		"common symbol can't be versioned");


The "can't" should trigger -Wformat-diag warnings suggesting to use
"cannot" instead.  There are a few remaining warnings like that we
haven't cleaned up yet but I'm hoping to get to it at some point and
make the warning an error.

> +      return;

> +    }

> +  if (DECL_COMDAT (n->decl))

> +    {

> +      error_at (DECL_SOURCE_LOCATION (n->decl),

> +		"comdat symbol can't be versioned");

> +      return;

> +    }

> +  if (n->weakref)

> +    {

> +      error_at (DECL_SOURCE_LOCATION (n->decl),

> +		"weakref can't be versioned");


Same here.  If weakref refers to attribute weakref it should also
be quoted (-Wformat-diag should suggest that; if it doesn't I'll
enhance it).

> +      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);

> +

> +  DECL_INITIAL (new_decl) = NULL_TREE;

> +  if (TREE_CODE (new_decl) == FUNCTION_DECL)

> +    DECL_STRUCT_FUNCTION (new_decl) = NULL;

> +  SET_DECL_ASSEMBLER_NAME (new_decl, symver);

> +  TREE_PUBLIC (new_decl) = 1;

> +  DECL_ATTRIBUTES (new_decl) = NULL;

> +

> +  symtab_node *symver_node = symtab_node::get_create (new_decl);

> +  symver_node->alias = true;

> +  symver_node->definition = true;

> +  symver_node->symver = true;

> +  symver_node->create_reference (n, IPA_REF_ALIAS, NULL);

> +  symver_node->analyzed = true;

> +}

> +

>   /* Process attributes common for vars and functions.  */

>   

>   static void

> @@ -730,6 +813,7 @@ process_common_attributes (symtab_node *

>   

>     if (lookup_attribute ("no_reorder", DECL_ATTRIBUTES (decl)))

>       node->no_reorder = 1;

> +  process_symver_attribute (node);

>   }

>   

>   /* Look for externally_visible and used attributes and mark cgraph nodes

> @@ -2137,8 +2221,12 @@ cgraph_node::assemble_thunks_and_aliases

>   	  /* Force assemble_alias to really output the alias this time instead

>   	     of buffering it in same alias pairs.  */

>   	  TREE_ASM_WRITTEN (decl) = 1;

> -	  do_assemble_alias (alias->decl,

> -			     DECL_ASSEMBLER_NAME (decl));

> +	  if (alias->symver)

> +	    do_assemble_symver (alias->decl,

> +				DECL_ASSEMBLER_NAME (decl));

> +	  else

> +	    do_assemble_alias (alias->decl,

> +			       DECL_ASSEMBLER_NAME (decl));

>   	  alias->assemble_thunks_and_aliases ();

>   	  TREE_ASM_WRITTEN (decl) = saved_written;

>   	}

> Index: config/elfos.h

> ===================================================================

> --- config/elfos.h	(revision 278293)

> +++ config/elfos.h	(working copy)

> @@ -248,6 +248,17 @@ see the files COPYING3 and COPYING.RUNTI

>       }					\

>     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));					\

> +    }								\

> +  while (0)

> +

>   /* The following macro defines the format used to output the second

>      operand of the .type assembler directive.  Different svr4 assemblers

>      expect various different forms for this operand.  The one given here

> Index: doc/extend.texi

> ===================================================================

> --- doc/extend.texi	(revision 278293)

> +++ doc/extend.texi	(working copy)

> @@ -3640,6 +3640,34 @@ Function Attributes}, @ref{PowerPC Funct

>   @ref{Nios II Function Attributes}, and @ref{S/390 Function Attributes}

>   for details.

>   

> +@item symver ("@var{name2}@@@var{nodename}")

> +On ELF targets this attribute creates symbol version.


Just a few minor spelling nits here that jumped out at me about
missing articles:

   "creates <ins>a </ins>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 of the alias 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.


Just for clarity, the text refers to "the alias" without having ever
mentioned an alias.  What alias is it talking about?  If a symbol
version is a kind of an alias the text should probably introduce
that notion before referring to it.

Missing article:

   "building <ins>a </ins> shared library."

and

   "Versioned symbol<ins>s</ins>..."

> +

> +@smallexample

> +__attribute__ ((__symver__ ("foo@@VERS_1"))) int

> +foo_v1 (void)

> +@{

> +@}

> +@end smallexample

> +

> +Will produce @code{.symver foo_v1, foo@@VERS_1} directive in the assembler


"produce <ins>a </ins>@code{.symver...} directive..."

> +output.  It is not allowed to make multiple versions out of one symbol, however

> +versioned symbol may also be an alias.


I'm not sure I understand what the above restriction means.  That
"it's an error to define multiple versions of the same symbol?"
(That doesn't make sense to me if this is all about making it
possible to do just that so I must be misunderstanding it.  If
that's the problem it may be worth clarifying a bit.)

> +

> +@smallexample

> +__attribute__ ((__symver__ ("foo@VERS_2")))

> +__attribute__ ((alias ("foo_v1")))

> +int symver_foo_v1 (void);

> +@end smallexample

> +

> +This example creates alias an of @code{foo_v1} with symbol name


"crates <ins>an </ins>alias."

> +@code{symver_foo_v1} which will be version @code{VERS_2} of @code{foo}.

> +

>   @item target_clones (@var{options})

>   @cindex @code{target_clones} function attribute

>   The @code{target_clones} attribute is used to specify that a function

> Index: lto-cgraph.c

> ===================================================================

> --- lto-cgraph.c	(revision 278293)

> +++ lto-cgraph.c	(working copy)

> @@ -526,6 +526,7 @@ lto_output_node (struct lto_simple_outpu

>     bp_pack_value (&bp, node->alias, 1);

>     bp_pack_value (&bp, node->transparent_alias, 1);

>     bp_pack_value (&bp, node->weakref, 1);

> +  bp_pack_value (&bp, node->symver, 1);

>     bp_pack_value (&bp, node->frequency, 2);

>     bp_pack_value (&bp, node->only_called_at_startup, 1);

>     bp_pack_value (&bp, node->only_called_at_exit, 1);

> @@ -606,6 +607,7 @@ lto_output_varpool_node (struct lto_simp

>     bp_pack_value (&bp, node->alias, 1);

>     bp_pack_value (&bp, node->transparent_alias, 1);

>     bp_pack_value (&bp, node->weakref, 1);

> +  bp_pack_value (&bp, node->symver, 1);

>     bp_pack_value (&bp, node->analyzed && (!boundary_p || node->alias), 1);

>     gcc_assert (node->definition || !node->analyzed);

>     /* Constant pool initializers can be de-unified into individual ltrans units.

> @@ -1170,6 +1172,7 @@ input_overwrite_node (struct lto_file_de

>     node->alias = bp_unpack_value (bp, 1);

>     node->transparent_alias = bp_unpack_value (bp, 1);

>     node->weakref = bp_unpack_value (bp, 1);

> +  node->symver = bp_unpack_value (bp, 1);

>     node->frequency = (enum node_frequency)bp_unpack_value (bp, 2);

>     node->only_called_at_startup = bp_unpack_value (bp, 1);

>     node->only_called_at_exit = bp_unpack_value (bp, 1);

> @@ -1363,6 +1366,7 @@ input_varpool_node (struct lto_file_decl

>     node->alias = bp_unpack_value (&bp, 1);

>     node->transparent_alias = bp_unpack_value (&bp, 1);

>     node->weakref = bp_unpack_value (&bp, 1);

> +  node->symver = bp_unpack_value (&bp, 1);

>     node->analyzed = bp_unpack_value (&bp, 1);

>     node->used_from_other_partition = bp_unpack_value (&bp, 1);

>     node->in_other_partition = bp_unpack_value (&bp, 1);

> Index: output.h

> ===================================================================

> --- output.h	(revision 278293)

> +++ output.h	(working copy)

> @@ -167,6 +167,7 @@ extern int decode_reg_name (const char *

>   extern int decode_reg_name_and_count (const char *, int *);

>   

>   extern void do_assemble_alias (tree, tree);

> +extern void do_assemble_symver (tree, tree);

>   

>   extern void default_assemble_visibility (tree, int);

>   

> Index: symtab.c

> ===================================================================

> --- symtab.c	(revision 278293)

> +++ symtab.c	(working copy)

> @@ -848,6 +848,8 @@ symtab_node::dump_base (FILE *f)

>       fprintf (f, " transparent_alias");

>     if (weakref)

>       fprintf (f, " weakref");

> +  if (symver)

> +    fprintf (f, " symver");

>     if (cpp_implicit_alias)

>       fprintf (f, " cpp_implicit_alias");

>     if (alias_target)

> @@ -1145,6 +1147,11 @@ symtab_node::verify_base (void)

>         error ("node is transparent_alias but not an alias");

>         error_found = true;

>       }

> +  if (symver && !alias)

> +    {

> +      error ("node is symver but not alias");


symver should be quoted: %<symver%>.

Martin
Rainer Orth Nov. 18, 2019, 2:14 p.m. | #9
Hi Jan,

> Also I wonder for testsuite bits, I think I need to implement

> dl-require-symver and then use it to gate the individual tests? Or do we

> have some common way to check for ELF?


there's a misunderstanding throughout here: symbol versioning is *not* a
(generic) ELF feature, i.e. it is not part of the ELF gABI.  Instead it
started off as a Solaris extension initially, later to be adopted and
extended again by gas/gld/glibc.  There are certainly ELF platforms that
don't support it at all (cf. HP-UX in gccinstall, maybe some of the
BSDs, historically even more like IRIX), so you cannot assume that any
ELF platform will support it.  On top of that, the GNU extension of
having the same symbol in multiple versions was never taken up by
Solaris (and never will be AFAICT), so even when using gas and gld, uses
will break when they reach ld.so.1.

So you certainly need such an effective-target test and, at least as
importantly, a configure test at build time that you can assemble, link,
and run a test correctly before enabling it in gcc.  Just
unconditionally dropping it into elfos.h is wrong.

	Rainer

-- 
-----------------------------------------------------------------------------
Rainer Orth, Center for Biotechnology, Bielefeld University
Rainer Orth Nov. 18, 2019, 2:22 p.m. | #10
Hi Jan,

> thanks for feedback. Here is updated patch that incorporates Martin's

> changes, formatting corrections and makes symvers of aliases work.


just a few nits.

> Index: doc/extend.texi

> ===================================================================

> --- doc/extend.texi	(revision 278293)

> +++ doc/extend.texi	(working copy)

> @@ -3640,6 +3640,34 @@ Function Attributes}, @ref{PowerPC Funct

>  @ref{Nios II Function Attributes}, and @ref{S/390 Function Attributes}

>  for details.

>  

> +@item symver ("@var{name2}@@@var{nodename}")

> +On ELF targets this attribute creates 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 of the alias should be the name of a


Better be consistent and use @var{} in both cases.

> +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.

> +

> +@smallexample

> +__attribute__ ((__symver__ ("foo@@VERS_1"))) int

> +foo_v1 (void)

> +@{

> +@}

> +@end smallexample

> +

> +Will produce @code{.symver foo_v1, foo@@VERS_1} directive in the assembler

> +output.  It is not allowed to make multiple versions out of one symbol, however

> +versioned symbol may also be an alias.

> +

> +@smallexample

> +__attribute__ ((__symver__ ("foo@VERS_2")))


this broke bootstrap:

/vol/gcc/src/hg/trunk/local/gcc/doc/extend.texi:3663: unknown command `VERS'
make[3]: *** [Makefile:3273: doc/gcc.info] Error 1

You need to be careful to properly quote @'s in texinfo.

> +__attribute__ ((alias ("foo_v1")))

> +int symver_foo_v1 (void);

> +@end smallexample

> +

> +This example creates alias an of @code{foo_v1} with symbol name

> +@code{symver_foo_v1} which will be version @code{VERS_2} of @code{foo}.

> +

>  @item target_clones (@var{options})

>  @cindex @code{target_clones} function attribute

>  The @code{target_clones} attribute is used to specify that a function


Martin already commented on the doc snippet.  I guess you'd better have
it double-checked by a native speaker.

> Index: symtab.c

> ===================================================================

> --- symtab.c	(revision 278293)

> +++ symtab.c	(working copy)

> @@ -848,6 +848,8 @@ symtab_node::dump_base (FILE *f)

>      fprintf (f, " transparent_alias");

>    if (weakref)

>      fprintf (f, " weakref");

> +  if (symver)

> +    fprintf (f, " symver");

>    if (cpp_implicit_alias)

>      fprintf (f, " cpp_implicit_alias");

>    if (alias_target)

> @@ -1145,6 +1147,11 @@ symtab_node::verify_base (void)

>        error ("node is transparent_alias but not an alias");

>        error_found = true;

>      }

> +  if (symver && !alias)

> +    {

> +      error ("node is symver but not alias");

> +      error_found = true;

> +    }

>    if (same_comdat_group)

>      {

>        symtab_node *n = same_comdat_group;

> @@ -1780,7 +1787,9 @@ symtab_node::resolve_alias (symtab_node

>  	  if (target->get_comdat_group ())

>  	    alias_alias->add_to_same_comdat_group (target);

>  	}

> -      if (!alias_alias->transparent_alias || transparent)

> +      if ((!alias_alias->transparent_alias

> +	   && !alias_alias->symver)


No need for the linebreak.

> +	  || transparent)

>  	{

>  	  alias_alias->remove_all_references ();

>  	  alias_alias->create_reference (target, IPA_REF_ALIAS, NULL);

> Index: varasm.c

> ===================================================================

> --- varasm.c	(revision 278293)

> +++ varasm.c	(working copy)

> @@ -1921,6 +1921,7 @@ assemble_end_function (tree decl, const

>      switch_to_section (function_section (decl));

>    ASM_DECLARE_FUNCTION_SIZE (asm_out_file, fnname, decl);

>  #endif

> +

>    if (! CONSTANT_POOL_BEFORE_FUNCTION)

>      {

>        output_constant_pool (fnname, decl);

> @@ -5960,6 +5961,23 @@ do_assemble_alias (tree decl, tree targe

>  #endif

>  }

>  

> +/* Output .symver directive.  */

> +

> +void

> +do_assemble_symver (tree decl, tree target)

> +{

> +  tree id = DECL_ASSEMBLER_NAME (decl);

> +  ultimate_transparent_alias_target (&id);

> +  ultimate_transparent_alias_target (&target);

> +#ifdef ASM_OUTPUT_SYMVER_DIRECTIVE

> +  ASM_OUTPUT_SYMVER_DIRECTIVE (asm_out_file,

> +			       IDENTIFIER_POINTER (target),

> +			       IDENTIFIER_POINTER (id));

> +#else

> +  error ("symver is only supported on ELF platforms");


As I said, this is misleading: better say something like "not supported
in this configuration".

	Rainer

-- 
-----------------------------------------------------------------------------
Rainer Orth, Center for Biotechnology, Bielefeld University
Florian Weimer Nov. 18, 2019, 2:23 p.m. | #11
* Rainer Orth:

> Hi Jan,

>

>> Also I wonder for testsuite bits, I think I need to implement

>> dl-require-symver and then use it to gate the individual tests? Or do we

>> have some common way to check for ELF?

>

> there's a misunderstanding throughout here: symbol versioning is *not* a

> (generic) ELF feature, i.e. it is not part of the ELF gABI.  Instead it

> started off as a Solaris extension initially, later to be adopted and

> extended again by gas/gld/glibc.


The GNU implementation is incompatible at a conceptual level, it's not
just an extension.

> There are certainly ELF platforms that don't support it at all

> (cf. HP-UX in gccinstall, maybe some of the BSDs, historically even

> more like IRIX), so you cannot assume that any ELF platform will

> support it.  On top of that, the GNU extension of having the same

> symbol in multiple versions was never taken up by Solaris (and never

> will be AFAICT), so even when using gas and gld, uses will break when

> they reach ld.so.1.


I think symbols don't carry versions in Solaris, which is the conceptual
difference. 8-)

The musl dynamic loader does not support symbol versioning (of either
kind), but binutils targeting for musl still has support for it because
there isn't really a separate non-GNU target for musl, which means that
some run-time tests involving symbol versions will fail.  (musl doesn't
want to identify as musl in its headers, so it's not really possible to
write a straightforward compile-time check for this, but maybe the GCC
build process already has this information from somewhere else.)

Thanks,
Florian
Rainer Orth Nov. 18, 2019, 2:42 p.m. | #12
Florian Weimer <fweimer@redhat.com> writes:

> * Rainer Orth:

>

>> Hi Jan,

>>

>>> Also I wonder for testsuite bits, I think I need to implement

>>> dl-require-symver and then use it to gate the individual tests? Or do we

>>> have some common way to check for ELF?

>>

>> there's a misunderstanding throughout here: symbol versioning is *not* a

>> (generic) ELF feature, i.e. it is not part of the ELF gABI.  Instead it

>> started off as a Solaris extension initially, later to be adopted and

>> extended again by gas/gld/glibc.

>

> The GNU implementation is incompatible at a conceptual level, it's not

> just an extension.


Huh?  The gld manual claims otherwise:

https://sourceware.org/binutils/docs/ld/VERSION.html#VERSION

and the ELF representation is certainly the same.  Check

https://docs.oracle.com/cd/E37838_01/html/E36783/chapter5-84101.html#scrolltoc

>> There are certainly ELF platforms that don't support it at all

>> (cf. HP-UX in gccinstall, maybe some of the BSDs, historically even

>> more like IRIX), so you cannot assume that any ELF platform will

>> support it.  On top of that, the GNU extension of having the same

>> symbol in multiple versions was never taken up by Solaris (and never

>> will be AFAICT), so even when using gas and gld, uses will break when

>> they reach ld.so.1.

>

> I think symbols don't carry versions in Solaris, which is the conceptual

> difference. 8-)


Huh again: you can certainly bind a symbol to a particular version (just
one though) using linker scripts which use exactly the same format as
gld (minus support for C++ mangling and globbing).

	Rainer

-- 
-----------------------------------------------------------------------------
Rainer Orth, Center for Biotechnology, Bielefeld University
Florian Weimer Nov. 18, 2019, 2:51 p.m. | #13
* Rainer Orth:

> Florian Weimer <fweimer@redhat.com> writes:

>

>> * Rainer Orth:

>>

>>> Hi Jan,

>>>

>>>> Also I wonder for testsuite bits, I think I need to implement

>>>> dl-require-symver and then use it to gate the individual tests? Or do we

>>>> have some common way to check for ELF?

>>>

>>> there's a misunderstanding throughout here: symbol versioning is *not* a

>>> (generic) ELF feature, i.e. it is not part of the ELF gABI.  Instead it

>>> started off as a Solaris extension initially, later to be adopted and

>>> extended again by gas/gld/glibc.

>>

>> The GNU implementation is incompatible at a conceptual level, it's not

>> just an extension.

>

> Huh?  The gld manual claims otherwise:

>

> https://sourceware.org/binutils/docs/ld/VERSION.html#VERSION

>

> and the ELF representation is certainly the same.  Check

>

> https://docs.oracle.com/cd/E37838_01/html/E36783/chapter5-84101.html#scrolltoc

>

>>> There are certainly ELF platforms that don't support it at all

>>> (cf. HP-UX in gccinstall, maybe some of the BSDs, historically even

>>> more like IRIX), so you cannot assume that any ELF platform will

>>> support it.  On top of that, the GNU extension of having the same

>>> symbol in multiple versions was never taken up by Solaris (and never

>>> will be AFAICT), so even when using gas and gld, uses will break when

>>> they reach ld.so.1.

>>

>> I think symbols don't carry versions in Solaris, which is the conceptual

>> difference. 8-)

>

> Huh again: you can certainly bind a symbol to a particular version (just

> one though) using linker scripts which use exactly the same format as

> gld (minus support for C++ mangling and globbing).


Ahh, sorry, I looked at this from the dynamic linker perspective.  I
still think the Solaris link editor uses those tables to map symbols to
versions.  But the correspondence is gone when loading.

The question is to what extent does this matter for .symver support in
GCC?  Does Solaris support a way to encode versioned symbol definitions
in ET_REL files?

Thanks,
Florian
Joseph Myers Nov. 19, 2019, 12:46 a.m. | #14
On Mon, 18 Nov 2019, Rainer Orth wrote:

> So you certainly need such an effective-target test and, at least as

> importantly, a configure test at build time that you can assemble, link,

> and run a test correctly before enabling it in gcc.  Just

> unconditionally dropping it into elfos.h is wrong.


Tests in gcc/configure for linking or running something are a bad idea 
because they don't work for cross compilation (at all, for run tests; when 
bootstrapping and target libc hasn't been built, for link tests).

I'd assume any bare-metal ELF target used with GNU binutils *could* 
support symbol versioning if it happens to be used with an RTOS that has a 
dynamic linker with that support, even if in fact it's much more likely to 
be used with static linking only.  So I don't think the information is 
available when GCC is built, beyond (a) it's definitely not supported for 
non-ELF targets (as determined through by a list of targets such as in 
config/elf.m4:ACX_ELF_TARGET_IFELSE) and (b) there might be a list of ELF 
OS targets known to lack support.

-- 
Joseph S. Myers
joseph@codesourcery.com
Jan Hubicka Nov. 19, 2019, 6:29 a.m. | #15
> On Mon, 18 Nov 2019, Rainer Orth wrote:

> 

> > So you certainly need such an effective-target test and, at least as

> > importantly, a configure test at build time that you can assemble, link,

> > and run a test correctly before enabling it in gcc.  Just

> > unconditionally dropping it into elfos.h is wrong.

> 

> Tests in gcc/configure for linking or running something are a bad idea 

> because they don't work for cross compilation (at all, for run tests; when 

> bootstrapping and target libc hasn't been built, for link tests).

> 

> I'd assume any bare-metal ELF target used with GNU binutils *could* 

> support symbol versioning if it happens to be used with an RTOS that has a 

> dynamic linker with that support, even if in fact it's much more likely to 

> be used with static linking only.  So I don't think the information is 

> available when GCC is built, beyond (a) it's definitely not supported for 

> non-ELF targets (as determined through by a list of targets such as in 

> config/elf.m4:ACX_ELF_TARGET_IFELSE) and (b) there might be a list of ELF 

> OS targets known to lack support.


Current patch makes GCC to accept symver attribute on all ELF targets
and simply output .symver directive into the assembly file hoping for
the best.  I hope that is acceptable since user will be informed by
assembler that symver is not supported.

For testsuite we however needs tests to not fail when .symver is not
accepted by assembler that can probably by tested by the dg-require
infrastructure...

It is not perfect solution but also not much worse than what we do
elsewhere...

Honza
Segher Boessenkool Nov. 19, 2019, 12:29 p.m. | #16
On Tue, Nov 19, 2019 at 07:29:37AM +0100, Jan Hubicka wrote:
> Current patch makes GCC to accept symver attribute on all ELF targets

> and simply output .symver directive into the assembly file hoping for

> the best.  I hope that is acceptable since user will be informed by

> assembler that symver is not supported.

> 

> For testsuite we however needs tests to not fail when .symver is not

> accepted by assembler that can probably by tested by the dg-require

> infrastructure...

> 

> It is not perfect solution but also not much worse than what we do

> elsewhere...


Sounds perfectly fine to me, but how many tests will need changing?  Is
it only those that use symbol versioning directly?


Segher
Jan Hubicka Nov. 19, 2019, 2:53 p.m. | #17
> On Tue, Nov 19, 2019 at 07:29:37AM +0100, Jan Hubicka wrote:

> > Current patch makes GCC to accept symver attribute on all ELF targets

> > and simply output .symver directive into the assembly file hoping for

> > the best.  I hope that is acceptable since user will be informed by

> > assembler that symver is not supported.

> > 

> > For testsuite we however needs tests to not fail when .symver is not

> > accepted by assembler that can probably by tested by the dg-require

> > infrastructure...

> > 

> > It is not perfect solution but also not much worse than what we do

> > elsewhere...

> 

> Sounds perfectly fine to me, but how many tests will need changing?  Is

> it only those that use symbol versioning directly?


There are no tests presently, I plan to write some so those will get
dg-require-symver.

.symver is output only if you use explicit symver function/variable
attribute. So the "only" downdisde of this is that instead of getting
friendly error message from GCC that your target does not support
symvers (because we can not easily check for it) you will get less
friendly error message from assembler.  I hope that is acceptale since
we have pre-existing situations like that already.

Honza


> 

> 

> Segher
Segher Boessenkool Nov. 19, 2019, 4:19 p.m. | #18
On Tue, Nov 19, 2019 at 03:53:43PM +0100, Jan Hubicka wrote:
> > Sounds perfectly fine to me, but how many tests will need changing?  Is

> > it only those that use symbol versioning directly?

> 

> There are no tests presently, I plan to write some so those will get

> dg-require-symver.

> 

> .symver is output only if you use explicit symver function/variable

> attribute. So the "only" downdisde of this is that instead of getting

> friendly error message from GCC that your target does not support

> symvers (because we can not easily check for it) you will get less

> friendly error message from assembler.  I hope that is acceptale since

> we have pre-existing situations like that already.


Ah, I thought this would happen for various things from libc as well, so
there would be a lot of random fallout.  I probably misunderstood :-)


Segher
Jakub Jelinek Nov. 19, 2019, 4:37 p.m. | #19
On Tue, Nov 19, 2019 at 10:19:05AM -0600, Segher Boessenkool wrote:
> On Tue, Nov 19, 2019 at 03:53:43PM +0100, Jan Hubicka wrote:

> > > Sounds perfectly fine to me, but how many tests will need changing?  Is

> > > it only those that use symbol versioning directly?

> > 

> > There are no tests presently, I plan to write some so those will get

> > dg-require-symver.

> > 

> > .symver is output only if you use explicit symver function/variable

> > attribute. So the "only" downdisde of this is that instead of getting

> > friendly error message from GCC that your target does not support

> > symvers (because we can not easily check for it) you will get less

> > friendly error message from assembler.  I hope that is acceptale since

> > we have pre-existing situations like that already.

> 

> Ah, I thought this would happen for various things from libc as well, so

> there would be a lot of random fallout.  I probably misunderstood :-)


glibc so far uses inline asm with .symver directives.  That could change one
day of course conditionally to use the GCC symver attribute.

	Jakub
Jan Hubicka Nov. 30, 2019, 1:44 p.m. | #20
> On 11/15/19 10:05 AM, Jan Hubicka wrote:

> > I am by no means expert in the area so feedback is welcome.  I would

> > like to get the patch to trunk early next week if it works well.

> 

> Thank you Honza for the patch. The idea looks nice to me and I have just

> few comments:

> 

> 1) we should also support foo@@@VER_1 format:

> https://sourceware.org/binutils/docs/as/Symver.html#Symver


We currently support symvers only on definitions, since symvers to
external symbols has different semantics (so it should go in
incrementally).  @@@ makes sense only if you do not attach attribute
dirrectly to a definition as we require right now.

   The third usage of the '.symver' directive is:
        .symver NAME, NAME2@@@NODENAME
   When NAME is not defined within the file being assembled, it is
   treated as NAME2@NODENAME.  When NAME is defined within the file
   being
   assembled, the symbol name, NAME, will be changed to NAME2@@NODENAME.

I really think versioned symbol references should have different
attribute (such as symver_ref since it does different thing). 
> 

> 2) I quoted some error format messages


Thanks,
I updated the patch.

Honza
> 

> Martin


> diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c

> index 8dcd38631d2..1723111bec0 100644

> --- a/gcc/c-family/c-attribs.c

> +++ b/gcc/c-family/c-attribs.c

> @@ -2338,12 +2338,11 @@ handle_symver_attribute (tree *node, tree ARG_UNUSED (name), tree args,

>  {

>    tree symver;

>    const char *symver_str;

> -  unsigned n;

>  

>    if (TREE_CODE (*node) != FUNCTION_DECL && TREE_CODE (*node) != VAR_DECL)

>      {

>        warning (OPT_Wattributes,

> -	       "symver attribute is only applicable on functions and variables");

> +	       "%<symver%> attribute is only applicable on functions and variables");

>        *no_add_attrs = true;

>        return NULL_TREE;

>      }

> @@ -2351,7 +2350,7 @@ handle_symver_attribute (tree *node, tree ARG_UNUSED (name), tree args,

>    if (!decl_in_symtab_p (*node))

>      {

>        warning (OPT_Wattributes,

> -	       "symver attribute is only applicable to symbols");

> +	       "%<symver%> attribute is only applicable to symbols");

>        *no_add_attrs = true;

>        return NULL_TREE;

>      }

> @@ -2361,7 +2360,7 @@ handle_symver_attribute (tree *node, tree ARG_UNUSED (name), tree args,

>        symver = TREE_VALUE (args);

>        if (TREE_CODE (symver) != STRING_CST)

>  	{

> -	  error ("symver attribute argument not a string constant");

> +	  error ("%<symver%> attribute argument not a string constant");

>  	  *no_add_attrs = true;

>  	  return NULL_TREE;

>  	}

> @@ -2369,13 +2368,14 @@ handle_symver_attribute (tree *node, tree ARG_UNUSED (name), tree args,

>        symver_str = TREE_STRING_POINTER (symver);

>  

>        int ats = 0;

> -      for (n = 0; n < TREE_STRING_LENGTH (symver); n++)

> +      for (int n = 0; n < TREE_STRING_LENGTH (symver); n++)

>  	if (symver_str[n] == '@')

>  	  ats++;

>  

> -      if (ats != 1 && ats != 2)

> +      if (ats < 1 || ats > 3)

>  	{

> -	  error ("symver attribute argument must have format %<name@nodename%>");

> +	  error ("%<symver%> attribute argument %qs must contain one, "

> +		 "two or three %<@%>", symver_str);

>  	  *no_add_attrs = true;

>  	  return NULL_TREE;

>  	}

> diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c

> index b45a864f3ed..c7caff5023a 100644

> --- a/gcc/cgraphunit.c

> +++ b/gcc/cgraphunit.c

> @@ -776,7 +776,7 @@ process_symver_attribute (symtab_node *n)

>        return;

>      }

>  

> -  /* Create new symbol table entry represneting the version.  */

> +  /* Create new symbol table entry representing the version.  */

>    tree new_decl = copy_node (n->decl);

>  

>    DECL_INITIAL (new_decl) = NULL_TREE;
Jan Hubicka Nov. 30, 2019, 1:47 p.m. | #21
> On Fri, 15 Nov 2019, Jan Hubicka wrote:

> 

> > I was originaly supporting multiple symvers like:

> > __attribute__ ((__symver__ ("foo@VERS_1"))) int

> > __attribute__ ((__symver__ ("foo@VERS_2"))) int

> > foo_v1 (void)

> > {

> > }

> > 

> > but then noticed it is rejected by gas.

> 

> That's <https://sourceware.org/bugzilla/show_bug.cgi?id=23840>.

> 

> > int symver_foo_v1 (void)

> > __attribute__ ((__symver__ ("foo@VERS_2")))

> > __attribute__ ((alias ("foo_v1")))

> > 

> > This describes what you want to do: create an alias symbol and then

> > attach version to it.  This is broken in current patch (though i

> 

> I'd rather GCC created those aliases automatically (with names that can't 

> be used as C symbols, e.g. containing '.', if possible, or failing that 

> implementation-namespace names that are unlikely to conflict with C 

> symbols), so that the API doesn't replicate a peculiarity of the assembler 

> implementation.


OK, this is quite easy to implement incrementally.  So the idea would be
to accept
__attribute__ ((__symver__ ("foo@VERS_1"))) int
__attribute__ ((__symver__ ("foo@VERS_2"))) int
foo_v1 (void)
{
}
and make GCC to produce two public symbols (foo_v1 and
foo_v1.somemangling) and attaching first symver alias
to foo_v1 and other to foo_v1.somemangling?

Honza
> 

> -- 

> Joseph S. Myers

> joseph@codesourcery.com
Jan Hubicka Nov. 30, 2019, 1:57 p.m. | #22
Hi,
> > +static tree

> > +handle_symver_attribute (tree *node, tree ARG_UNUSED (name), tree args,

> > +			 int ARG_UNUSED (flags), bool *no_add_attrs)

> > +{

> > +  tree symver;

> > +  const char *symver_str;

> > +

> > +  if (TREE_CODE (*node) != FUNCTION_DECL && TREE_CODE (*node) != VAR_DECL)

> 

> Should the attribute apply to member functions as well?  If not,

> FWIW, I think VAR_OR_FUNCTION_DECL_P() tests for just functions

> and variables.


I do not see particular reason why one would not want to create versions
of member functions.  So I guess i will keep it here.
> 

> > +    {

> > +      warning (OPT_Wattributes,

> > +	       "%<symver%> attribute is only applicable on functions and "

> > +	       "variables");

> 

> "applicable to functions" as below (though I think the far more

> common phrase among GCC messages is "applies to functions").


Thanks, I updated the wording.
> I'm not sure I understand what the above restriction means.  That

> "it's an error to define multiple versions of the same symbol?"


yes, though the thread with Jason suggestst that we may want to lift the
restriction and maek GCC to implicitly produce the aliases.

I have updated the patch.

Honza
Joseph Myers Nov. 30, 2019, 2:59 p.m. | #23
On Sat, 30 Nov 2019, Jan Hubicka wrote:

> > I'd rather GCC created those aliases automatically (with names that can't 

> > be used as C symbols, e.g. containing '.', if possible, or failing that 

> > implementation-namespace names that are unlikely to conflict with C 

> > symbols), so that the API doesn't replicate a peculiarity of the assembler 

> > implementation.

> 

> OK, this is quite easy to implement incrementally.  So the idea would be

> to accept

> __attribute__ ((__symver__ ("foo@VERS_1"))) int

> __attribute__ ((__symver__ ("foo@VERS_2"))) int

> foo_v1 (void)

> {

> }

> and make GCC to produce two public symbols (foo_v1 and

> foo_v1.somemangling) and attaching first symver alias

> to foo_v1 and other to foo_v1.somemangling?


Yes, that sort of thing.  For glibc we'd want to be able to add extra 
symbol versions on separate declarations of foo_v1 after it's been defined 
rather than requiring all the attributes to be on the definition.

-- 
Joseph S. Myers
joseph@codesourcery.com
Jan Hubicka Nov. 30, 2019, 3:04 p.m. | #24
> On Sat, 30 Nov 2019, Jan Hubicka wrote:

> 

> > > I'd rather GCC created those aliases automatically (with names that can't 

> > > be used as C symbols, e.g. containing '.', if possible, or failing that 

> > > implementation-namespace names that are unlikely to conflict with C 

> > > symbols), so that the API doesn't replicate a peculiarity of the assembler 

> > > implementation.

> > 

> > OK, this is quite easy to implement incrementally.  So the idea would be

> > to accept

> > __attribute__ ((__symver__ ("foo@VERS_1"))) int

> > __attribute__ ((__symver__ ("foo@VERS_2"))) int

> > foo_v1 (void)

> > {

> > }

> > and make GCC to produce two public symbols (foo_v1 and

> > foo_v1.somemangling) and attaching first symver alias

> > to foo_v1 and other to foo_v1.somemangling?

> 

> Yes, that sort of thing.  For glibc we'd want to be able to add extra 

> symbol versions on separate declarations of foo_v1 after it's been defined 

> rather than requiring all the attributes to be on the definition.


OK, if I get it right, the gcc-generated mangled symbol will be exported
and end up in the DSO symbol table that is not very cool.  Can we use
local aliases here (where such thing would be OK) with foo@@@vers_1
.symver directive?  This seem to produce symbol version but does not
export anything?

Honza
Jan Hubicka Nov. 30, 2019, 9:13 p.m. | #25
Hi,
this is patch incorporating (I hope) all the suggestions and corrections
which I applied.  I will work incremnetaly on supporting the name@@@node
semantics which is bit different from @ and @@ one by actually removing
the original symbol.  Here I need to change assembler name of the symbol
itself but then I still need an alternative assembler name for the local
use. This is bit like weakref rewriting but not quite and it seems it is
better to do that incrementally.

It would be great to convert libstdc++ to the new infrastructure so it
becomes LTO safe and gives some real world testing to this
infrastructure.  I tried that but found it is bit non-trivial since
currently way we need to attach the attribute to definition itself,
while current .symver output is done in separate C++ files.

Bootstrapped/regtested x86_64-linux, comitted.  I will work on the @@@
support and symbol_ref attribute for non-definitions.

Honza

2019-11-30  Jan Hubicka  <hubicka@ucw.cz>

	* cgraph.h (symtab_node): Add symver flag.
	* cgraphunit.c (process_symver_attribute): New.
	(process_common_attributes): Use process_symver_attribute.
	* lto-cgraph.c (lto_output_node): Stream symver.
	(lto_output_varpool_node): Stream symver.
	(input_overwrite_node): Stream symver.
	(input_varpool_node): Stream symver.
	* output.h (do_assemble_symver): Decalre.
	* symtab.c (symtab_node::dump_base): Dump symver.
	(symtab_node::verify_base): Verify symver.
	(symtab_node::resolve_alias): Handle symver.
	* varasm.c (do_assemble_symver): New function.
	* varpool.c (varpool_node::assemble_aliases): Use it.
	* doc/extend.texi: (symver attribute): Document.
	* config/elfos.h (ASM_OUTPUT_SYMVER_DIRECTIVE): New.

c-family/ChangeLog:

2019-11-30  Jan Hubicka  <hubicka@ucw.cz>

	* c-attribs.c (handle_symver_attribute): New function
	(c_common_attributes): Add symver.


Index: c-family/c-attribs.c
===================================================================
--- c-family/c-attribs.c	(revision 278877)
+++ c-family/c-attribs.c	(working copy)
@@ -66,6 +66,7 @@ static tree handle_stack_protect_attribu
 static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
 static tree handle_noclone_attribute (tree *, tree, tree, int, bool *);
 static tree handle_nocf_check_attribute (tree *, tree, tree, int, bool *);
+static tree handle_symver_attribute (tree *, tree, tree, int, bool *);
 static tree handle_noicf_attribute (tree *, tree, tree, int, bool *);
 static tree handle_noipa_attribute (tree *, tree, tree, int, bool *);
 static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
@@ -475,6 +476,8 @@ const struct attribute_spec c_common_att
 			      NULL },
   { "nocf_check",	      0, 0, false, true, true, true,
 			      handle_nocf_check_attribute, NULL },
+  { "symver",		      1, -1, true, false, false, false,
+			      handle_symver_attribute, NULL},
   { "copy",                   1, 1, false, false, false, false,
 			      handle_copy_attribute, NULL },
   { "noinit",		      0, 0, true,  false, false, false,
@@ -2335,6 +2338,62 @@ handle_noplt_attribute (tree *node, tree
   return NULL_TREE;
 }
 
+/* Handle a "symver" attribute.  */
+
+static tree
+handle_symver_attribute (tree *node, tree ARG_UNUSED (name), tree args,
+			 int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  tree symver;
+  const char *symver_str;
+
+  if (TREE_CODE (*node) != FUNCTION_DECL && TREE_CODE (*node) != VAR_DECL)
+    {
+      warning (OPT_Wattributes,
+	       "%<symver%> attribute only applies to functions and variables");
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  if (!decl_in_symtab_p (*node))
+    {
+      warning (OPT_Wattributes,
+	       "%<symver%> attribute is only applicable to symbols");
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  for (; args; args = TREE_CHAIN (args))
+    {
+      symver = TREE_VALUE (args);
+      if (TREE_CODE (symver) != STRING_CST)
+	{
+	  error ("%<symver%> attribute argument not a string constant");
+	  *no_add_attrs = true;
+	  return NULL_TREE;
+	}
+
+      symver_str = TREE_STRING_POINTER (symver);
+
+      int ats = 0;
+      for (int n = 0; (int)n < TREE_STRING_LENGTH (symver); n++)
+	if (symver_str[n] == '@')
+	  ats++;
+
+      if (ats != 1 && ats != 2)
+	{
+	  error ("symver attribute argument must have format %<name@nodename%>");
+	  error ("%<symver%> attribute argument %qs must contain one or two "
+		 "%<@%>", symver_str);
+	  *no_add_attrs = true;
+	  return NULL_TREE;
+	}
+    }
+
+  return NULL_TREE;
+}
+
+
 /* Handle an "alias" or "ifunc" attribute; arguments as in
    struct attribute_spec.handler, except that IS_ALIAS tells us
    whether this is an alias as opposed to ifunc attribute.  */
Index: cgraph.h
===================================================================
--- cgraph.h	(revision 278877)
+++ cgraph.h	(working copy)
@@ -497,6 +497,8 @@ public:
      and their visibility needs to be copied from their "masters" at
      the end of parsing.  */
   unsigned cpp_implicit_alias : 1;
+  /* The alias is a symbol version.  */
+  unsigned symver : 1;
   /* Set once the definition was analyzed.  The list of references and
      other properties are built during analysis.  */
   unsigned analyzed : 1;
Index: cgraphunit.c
===================================================================
--- cgraphunit.c	(revision 278877)
+++ cgraphunit.c	(working copy)
@@ -711,6 +711,89 @@ symbol_table::process_same_body_aliases
   cpp_implicit_aliases_done = true;
 }
 
+/* Process a symver attribute.  */
+
+static void
+process_symver_attribute (symtab_node *n)
+{
+  tree value = lookup_attribute ("symver", DECL_ATTRIBUTES (n->decl));
+
+  if (!value)
+    return;
+  if (lookup_attribute ("symver", TREE_CHAIN (value)))
+    {
+      error_at (DECL_SOURCE_LOCATION (n->decl),
+		"multiple versions for one symbol");
+      return;
+    }
+  tree symver = get_identifier_with_length
+		  (TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (value))),
+		   TREE_STRING_LENGTH (TREE_VALUE (TREE_VALUE (value))));
+  symtab_node *def = symtab_node::get_for_asmname (symver);
+
+  if (def)
+    {
+      error_at (DECL_SOURCE_LOCATION (n->decl),
+		"duplicate definition of a symbol version");
+      inform (DECL_SOURCE_LOCATION (def->decl),
+	      "same version was previously defined here");
+      return;
+    }
+  if (!n->definition)
+    {
+      error_at (DECL_SOURCE_LOCATION (n->decl),
+		"symbol needs to be defined to have a version");
+      return;
+    }
+  if (DECL_COMMON (n->decl))
+    {
+      error_at (DECL_SOURCE_LOCATION (n->decl),
+		"common symbol cannot be versioned");
+      return;
+    }
+  if (DECL_COMDAT (n->decl))
+    {
+      error_at (DECL_SOURCE_LOCATION (n->decl),
+		"comdat symbol cannot be versioned");
+      return;
+    }
+  if (n->weakref)
+    {
+      error_at (DECL_SOURCE_LOCATION (n->decl),
+		"weakref 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);
+
+  DECL_INITIAL (new_decl) = NULL_TREE;
+  if (TREE_CODE (new_decl) == FUNCTION_DECL)
+    DECL_STRUCT_FUNCTION (new_decl) = NULL;
+  SET_DECL_ASSEMBLER_NAME (new_decl, symver);
+  TREE_PUBLIC (new_decl) = 1;
+  DECL_ATTRIBUTES (new_decl) = NULL;
+
+  symtab_node *symver_node = symtab_node::get_create (new_decl);
+  symver_node->alias = true;
+  symver_node->definition = true;
+  symver_node->symver = true;
+  symver_node->create_reference (n, IPA_REF_ALIAS, NULL);
+  symver_node->analyzed = true;
+}
+
 /* Process attributes common for vars and functions.  */
 
 static void
@@ -730,6 +813,7 @@ process_common_attributes (symtab_node *
 
   if (lookup_attribute ("no_reorder", DECL_ATTRIBUTES (decl)))
     node->no_reorder = 1;
+  process_symver_attribute (node);
 }
 
 /* Look for externally_visible and used attributes and mark cgraph nodes
@@ -2137,8 +2221,12 @@ cgraph_node::assemble_thunks_and_aliases
 	  /* Force assemble_alias to really output the alias this time instead
 	     of buffering it in same alias pairs.  */
 	  TREE_ASM_WRITTEN (decl) = 1;
-	  do_assemble_alias (alias->decl,
-			     DECL_ASSEMBLER_NAME (decl));
+	  if (alias->symver)
+	    do_assemble_symver (alias->decl,
+				DECL_ASSEMBLER_NAME (decl));
+	  else
+	    do_assemble_alias (alias->decl,
+			       DECL_ASSEMBLER_NAME (decl));
 	  alias->assemble_thunks_and_aliases ();
 	  TREE_ASM_WRITTEN (decl) = saved_written;
 	}
Index: config/elfos.h
===================================================================
--- config/elfos.h	(revision 278877)
+++ config/elfos.h	(working copy)
@@ -248,6 +248,17 @@ see the files COPYING3 and COPYING.RUNTI
     }					\
   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));					\
+    }								\
+  while (0)
+
 /* The following macro defines the format used to output the second
    operand of the .type assembler directive.  Different svr4 assemblers
    expect various different forms for this operand.  The one given here
Index: doc/extend.texi
===================================================================
--- doc/extend.texi	(revision 278877)
+++ doc/extend.texi	(working copy)
@@ -3711,6 +3711,41 @@ Function Attributes}, @ref{PowerPC Funct
 @ref{Nios II Function Attributes}, and @ref{S/390 Function Attributes}
 for details.
 
+@item symver ("@var{name2}@@@var{nodename}")
+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.
+
+@smallexample
+__attribute__ ((__symver__ ("foo@@VERS_1"))) int
+foo_v1 (void)
+@{
+@}
+@end smallexample
+
+Will produce a @code{.symver foo_v1, foo@@VERS_1} directive in the assembler
+output. 
+
+It's an error to define multiple version of a given symbol.  In such case
+an alias can be used.
+
+@smallexample
+__attribute__ ((__symver__ ("foo@@VERS_2")))
+__attribute__ ((alias ("foo_v1")))
+int symver_foo_v1 (void);
+@end smallexample
+
+This example creates an alias of @code{foo_v1} with symbol name
+@code{symver_foo_v1} which will be version @code{VERS_2} of @code{foo}.
+
+Finally if the parameter is @code{"@var{name2}@@@@@var{nodename}"} then in
+addition to creating a symbol version (as if
+@code{"@var{name2}@@@var{nodename}"} was used) the version will be also used
+to resolve @var{name2} by the linker.
+
 @item target_clones (@var{options})
 @cindex @code{target_clones} function attribute
 The @code{target_clones} attribute is used to specify that a function
Index: lto-cgraph.c
===================================================================
--- lto-cgraph.c	(revision 278877)
+++ lto-cgraph.c	(working copy)
@@ -526,6 +526,7 @@ lto_output_node (struct lto_simple_outpu
   bp_pack_value (&bp, node->alias, 1);
   bp_pack_value (&bp, node->transparent_alias, 1);
   bp_pack_value (&bp, node->weakref, 1);
+  bp_pack_value (&bp, node->symver, 1);
   bp_pack_value (&bp, node->frequency, 2);
   bp_pack_value (&bp, node->only_called_at_startup, 1);
   bp_pack_value (&bp, node->only_called_at_exit, 1);
@@ -609,6 +610,7 @@ lto_output_varpool_node (struct lto_simp
   bp_pack_value (&bp, node->alias, 1);
   bp_pack_value (&bp, node->transparent_alias, 1);
   bp_pack_value (&bp, node->weakref, 1);
+  bp_pack_value (&bp, node->symver, 1);
   bp_pack_value (&bp, node->analyzed && (!boundary_p || node->alias), 1);
   gcc_assert (node->definition || !node->analyzed);
   /* Constant pool initializers can be de-unified into individual ltrans units.
@@ -1173,6 +1175,7 @@ input_overwrite_node (struct lto_file_de
   node->alias = bp_unpack_value (bp, 1);
   node->transparent_alias = bp_unpack_value (bp, 1);
   node->weakref = bp_unpack_value (bp, 1);
+  node->symver = bp_unpack_value (bp, 1);
   node->frequency = (enum node_frequency)bp_unpack_value (bp, 2);
   node->only_called_at_startup = bp_unpack_value (bp, 1);
   node->only_called_at_exit = bp_unpack_value (bp, 1);
@@ -1371,6 +1374,7 @@ input_varpool_node (struct lto_file_decl
   node->alias = bp_unpack_value (&bp, 1);
   node->transparent_alias = bp_unpack_value (&bp, 1);
   node->weakref = bp_unpack_value (&bp, 1);
+  node->symver = bp_unpack_value (&bp, 1);
   node->analyzed = bp_unpack_value (&bp, 1);
   node->used_from_other_partition = bp_unpack_value (&bp, 1);
   node->in_other_partition = bp_unpack_value (&bp, 1);
Index: output.h
===================================================================
--- output.h	(revision 278877)
+++ output.h	(working copy)
@@ -167,6 +167,7 @@ extern int decode_reg_name (const char *
 extern int decode_reg_name_and_count (const char *, int *);
 
 extern void do_assemble_alias (tree, tree);
+extern void do_assemble_symver (tree, tree);
 
 extern void default_assemble_visibility (tree, int);
 
Index: symtab.c
===================================================================
--- symtab.c	(revision 278877)
+++ symtab.c	(working copy)
@@ -848,6 +848,8 @@ symtab_node::dump_base (FILE *f)
     fprintf (f, " transparent_alias");
   if (weakref)
     fprintf (f, " weakref");
+  if (symver)
+    fprintf (f, " symver");
   if (cpp_implicit_alias)
     fprintf (f, " cpp_implicit_alias");
   if (alias_target)
@@ -1147,6 +1149,11 @@ symtab_node::verify_base (void)
       error ("node is transparent_alias but not an alias");
       error_found = true;
     }
+  if (symver && !alias)
+    {
+      error ("node is symver but not alias");
+      error_found = true;
+    }
   if (same_comdat_group)
     {
       symtab_node *n = same_comdat_group;
@@ -1782,7 +1789,9 @@ symtab_node::resolve_alias (symtab_node
 	  if (target->get_comdat_group ())
 	    alias_alias->add_to_same_comdat_group (target);
 	}
-      if (!alias_alias->transparent_alias || transparent)
+      if ((!alias_alias->transparent_alias
+	   && !alias_alias->symver)
+	  || transparent)
 	{
 	  alias_alias->remove_all_references ();
 	  alias_alias->create_reference (target, IPA_REF_ALIAS, NULL);
Index: varasm.c
===================================================================
--- varasm.c	(revision 278877)
+++ varasm.c	(working copy)
@@ -5960,6 +5961,23 @@ do_assemble_alias (tree decl, tree targe
 #endif
 }
 
+/* Output .symver directive.  */
+
+void
+do_assemble_symver (tree decl, tree target)
+{
+  tree id = DECL_ASSEMBLER_NAME (decl);
+  ultimate_transparent_alias_target (&id);
+  ultimate_transparent_alias_target (&target);
+#ifdef ASM_OUTPUT_SYMVER_DIRECTIVE
+  ASM_OUTPUT_SYMVER_DIRECTIVE (asm_out_file,
+			       IDENTIFIER_POINTER (target),
+			       IDENTIFIER_POINTER (id));
+#else
+  error ("symver is only supported on ELF platforms");
+#endif
+}
+
 /* Emit an assembler directive to make the symbol for DECL an alias to
    the symbol for TARGET.  */
 
Index: varpool.c
===================================================================
--- varpool.c	(revision 278877)
+++ varpool.c	(working copy)
@@ -540,7 +540,10 @@ varpool_node::assemble_aliases (void)
   FOR_EACH_ALIAS (this, ref)
     {
       varpool_node *alias = dyn_cast <varpool_node *> (ref->referring);
-      if (!alias->transparent_alias)
+      if (alias->symver)
+	do_assemble_symver (alias->decl,
+			    DECL_ASSEMBLER_NAME (decl));
+      else if (!alias->transparent_alias)
 	do_assemble_alias (alias->decl,
 			   DECL_ASSEMBLER_NAME (decl));
       alias->assemble_aliases ();
Jonathan Wakely Dec. 2, 2019, 11:07 a.m. | #26
On 30/11/19 22:13 +0100, Jan Hubicka wrote:
>Hi,

>this is patch incorporating (I hope) all the suggestions and corrections

>which I applied.  I will work incremnetaly on supporting the name@@@node

>semantics which is bit different from @ and @@ one by actually removing

>the original symbol.  Here I need to change assembler name of the symbol

>itself but then I still need an alternative assembler name for the local

>use. This is bit like weakref rewriting but not quite and it seems it is

>better to do that incrementally.

>

>It would be great to convert libstdc++ to the new infrastructure so it

>becomes LTO safe and gives some real world testing to this

>infrastructure.  I tried that but found it is bit non-trivial since

>currently way we need to attach the attribute to definition itself,

>while current .symver output is done in separate C++ files.


I will add it to my TODO list.


>Index: doc/extend.texi

>===================================================================

>--- doc/extend.texi	(revision 278877)

>+++ doc/extend.texi	(working copy)

>@@ -3711,6 +3711,41 @@ Function Attributes}, @ref{PowerPC Funct

> @ref{Nios II Function Attributes}, and @ref{S/390 Function Attributes}

> for details.

>

>+@item symver ("@var{name2}@@@var{nodename}")

>+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


I think this should be either "A versioned symbol" or "Versioned
symbols".

>+default visibility.

>+

>+@smallexample

>+__attribute__ ((__symver__ ("foo@@VERS_1"))) int

>+foo_v1 (void)

>+@{

>+@}

>+@end smallexample

>+

>+Will produce a @code{.symver foo_v1, foo@@VERS_1} directive in the assembler

>+output.

>+

>+It's an error to define multiple version of a given symbol.  In such case


"In such cases"

>+an alias can be used.

>+

>+@smallexample

>+__attribute__ ((__symver__ ("foo@@VERS_2")))

>+__attribute__ ((alias ("foo_v1")))

>+int symver_foo_v1 (void);

>+@end smallexample

>+

>+This example creates an alias of @code{foo_v1} with symbol name

>+@code{symver_foo_v1} which will be version @code{VERS_2} of @code{foo}.

>+

>+Finally if the parameter is @code{"@var{name2}@@@@@var{nodename}"} then in

>+addition to creating a symbol version (as if

>+@code{"@var{name2}@@@var{nodename}"} was used) the version will be also used


s/was used/had been used/

s/will be also used/will also be used/
Jan Hubicka Dec. 2, 2019, 12:53 p.m. | #27
> > It would be great to convert libstdc++ to the new infrastructure so it

> > becomes LTO safe and gives some real world testing to this

> > infrastructure.  I tried that but found it is bit non-trivial since

> > currently way we need to attach the attribute to definition itself,

> > while current .symver output is done in separate C++ files.

> 

> I will add it to my TODO list.


Thank you! It would be great to have some evidence that things works as
expected and the attribute is practically useful for real world
projects.

I will update the documentation by your suggestions.

Honza
Jakub Jelinek Dec. 2, 2019, 1:32 p.m. | #28
On Mon, Dec 02, 2019 at 01:53:09PM +0100, Jan Hubicka wrote:
> > > It would be great to convert libstdc++ to the new infrastructure so it

> > > becomes LTO safe and gives some real world testing to this

> > > infrastructure.  I tried that but found it is bit non-trivial since

> > > currently way we need to attach the attribute to definition itself,

> > > while current .symver output is done in separate C++ files.


What is the reason for this limitation?  I think that is pretty severe.
Wouldn't it be enough to accept symver attribute on any declaration, but at
the end verify that declarations that have that attribute have the
definition in the current TU?

I mean, it is fairly common to:
void foo ()
{
   ...
}

asm (".symver ...");
where the foo definition comes from one source and symver from another one,
which includes the first source.

So, the corresponding new rewrite for that might be:
void foo ()
{
  ...
}

extern __typeof (foo) foo __attribute__((symver ("bar@@BAZ")));

	Jakub
Jan Hubicka Dec. 2, 2019, 1:37 p.m. | #29
> On Mon, Dec 02, 2019 at 01:53:09PM +0100, Jan Hubicka wrote:

> > > > It would be great to convert libstdc++ to the new infrastructure so it

> > > > becomes LTO safe and gives some real world testing to this

> > > > infrastructure.  I tried that but found it is bit non-trivial since

> > > > currently way we need to attach the attribute to definition itself,

> > > > while current .symver output is done in separate C++ files.

> 

> What is the reason for this limitation?  I think that is pretty severe.

> Wouldn't it be enough to accept symver attribute on any declaration, but at

> the end verify that declarations that have that attribute have the

> definition in the current TU?

> 

> I mean, it is fairly common to:

> void foo ()

> {

>    ...

> }

> 

> asm (".symver ...");

> where the foo definition comes from one source and symver from another one,

> which includes the first source.

> 

> So, the corresponding new rewrite for that might be:

> void foo ()

> {

>   ...

> }

> 

> extern __typeof (foo) foo __attribute__((symver ("bar@@BAZ")));


Aha, this works :)  I basically meant that I need the declaration which
I found somewhat nontrivial to dig out of the libstdc++ headers.  I did
not think of typeof. I suppose I can add this as an example to the
dcumentation (as an example convertion .symver assembly into attribute).

Honza
> 

> 	Jakub

>

Patch

Index: c-family/c-attribs.c
===================================================================
--- c-family/c-attribs.c	(revision 278220)
+++ c-family/c-attribs.c	(working copy)
@@ -149,6 +149,7 @@  static tree handle_designated_init_attri
 static tree handle_fallthrough_attribute (tree *, tree, tree, int, bool *);
 static tree handle_patchable_function_entry_attribute (tree *, tree, tree,
 						       int, bool *);
+static tree handle_symver_attribute (tree *, tree, tree, int, bool *);
 static tree handle_copy_attribute (tree *, tree, tree, int, bool *);
 
 /* Helper to define attribute exclusions.  */
@@ -476,6 +477,8 @@  const struct attribute_spec c_common_att
 			      NULL },
   { "nocf_check",	      0, 0, false, true, true, true,
 			      handle_nocf_check_attribute, NULL },
+  { "symver",		      1, -1, true, false, false, false,
+			      handle_symver_attribute, NULL},
   { "copy",                   1, 1, false, false, false, false,
 			      handle_copy_attribute, NULL },
   { "noinit",		      0, 0, true,  false, false, false,
@@ -2332,6 +2335,58 @@  handle_noplt_attribute (tree *node, tree
   return NULL_TREE;
 }
 
+static tree
+handle_symver_attribute (tree *node, tree ARG_UNUSED (name), tree args,
+			 int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  tree symver;
+  const char *symver_str;
+  unsigned n;
+
+  if (TREE_CODE (*node) != FUNCTION_DECL && TREE_CODE (*node) != VAR_DECL)
+    {
+      warning (OPT_Wattributes,
+	       "symver attribute is only applicable on functions and variables");
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  if (!decl_in_symtab_p (*node))
+    {
+      warning (OPT_Wattributes,
+	       "symver attribute is only applicable to symbols");
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  for (; args; args = TREE_CHAIN (args))
+    {
+      symver = TREE_VALUE (args);
+      if (TREE_CODE (symver) != STRING_CST)
+	{
+	  error ("symver attribute argument not a string constant");
+	  *no_add_attrs = true;
+	  return NULL_TREE;
+	}
+
+      symver_str = TREE_STRING_POINTER (symver);
+
+      int ats = 0;
+      for (n = 0; n < TREE_STRING_LENGTH (symver); n++)
+	if (symver_str[n] == '@')
+	  ats++;
+
+      if (ats != 1 && ats != 2)
+	{
+	  error ("symver attribute argument must have format %<name@nodename%>");
+	  *no_add_attrs = true;
+	  return NULL_TREE;
+	}
+    }
+
+  return NULL_TREE;
+}
+
 /* Handle an "alias" or "ifunc" attribute; arguments as in
    struct attribute_spec.handler, except that IS_ALIAS tells us
    whether this is an alias as opposed to ifunc attribute.  */
Index: cgraph.h
===================================================================
--- cgraph.h	(revision 278220)
+++ cgraph.h	(working copy)
@@ -497,6 +497,8 @@  public:
      and their visibility needs to be copied from their "masters" at
      the end of parsing.  */
   unsigned cpp_implicit_alias : 1;
+  /* The alias is a symbol version.  */
+  unsigned symver : 1;
   /* Set once the definition was analyzed.  The list of references and
      other properties are built during analysis.  */
   unsigned analyzed : 1;
Index: cgraphunit.c
===================================================================
--- cgraphunit.c	(revision 278220)
+++ cgraphunit.c	(working copy)
@@ -711,6 +711,89 @@  symbol_table::process_same_body_aliases
   cpp_implicit_aliases_done = true;
 }
 
+/* Process a symver attribute.  */
+
+static void
+process_symver_attribute (symtab_node *n)
+{
+  tree value = lookup_attribute ("symver", DECL_ATTRIBUTES (n->decl));
+
+  if (!value)
+    return;
+  if (lookup_attribute ("symver", TREE_CHAIN (value)))
+    {
+      error_at (DECL_SOURCE_LOCATION (n->decl),
+		"multiple versions for one symbol");
+      return;
+    }
+  tree symver = get_identifier_with_length
+		  (TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (value))),
+		   TREE_STRING_LENGTH (TREE_VALUE (TREE_VALUE (value))));
+  symtab_node *def = symtab_node::get_for_asmname (symver);
+
+  if (def)
+    {
+      error_at (DECL_SOURCE_LOCATION (n->decl),
+		"duplicate definition of a symbol version");
+      inform (DECL_SOURCE_LOCATION (def->decl),
+	      "same version was previously defined here");
+      return;
+    }
+  if (!n->definition)
+    {
+      error_at (DECL_SOURCE_LOCATION (n->decl),
+		"symbol needs to be defined to have a version");
+      return;
+    }
+  if (DECL_COMMON (n->decl))
+    {
+      error_at (DECL_SOURCE_LOCATION (n->decl),
+		"common symbol can't be versioned");
+      return;
+    }
+  if (DECL_COMDAT (n->decl))
+    {
+      error_at (DECL_SOURCE_LOCATION (n->decl),
+		"comdat symbol can't be versioned");
+      return;
+    }
+  if (n->weakref)
+    {
+      error_at (DECL_SOURCE_LOCATION (n->decl),
+		"weakref can't 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 represneting the version.  */
+  tree new_decl = copy_node (n->decl);
+
+  DECL_INITIAL (new_decl) = NULL_TREE;
+  if (TREE_CODE (new_decl) == FUNCTION_DECL)
+    DECL_STRUCT_FUNCTION (new_decl) = NULL;
+  SET_DECL_ASSEMBLER_NAME (new_decl, symver);
+  TREE_PUBLIC (new_decl) = 1;
+  DECL_ATTRIBUTES (new_decl) = NULL;
+
+  symtab_node *symver_node = symtab_node::get_create (new_decl);
+  symver_node->alias = true;
+  symver_node->definition = true;
+  symver_node->symver = true;
+  symver_node->create_reference (n, IPA_REF_ALIAS, NULL);
+  symver_node->analyzed = true;
+}
+
 /* Process attributes common for vars and functions.  */
 
 static void
@@ -730,6 +813,7 @@  process_common_attributes (symtab_node *
 
   if (lookup_attribute ("no_reorder", DECL_ATTRIBUTES (decl)))
     node->no_reorder = 1;
+  process_symver_attribute (node);
 }
 
 /* Look for externally_visible and used attributes and mark cgraph nodes
@@ -2137,8 +2221,12 @@  cgraph_node::assemble_thunks_and_aliases
 	  /* Force assemble_alias to really output the alias this time instead
 	     of buffering it in same alias pairs.  */
 	  TREE_ASM_WRITTEN (decl) = 1;
-	  do_assemble_alias (alias->decl,
-			     DECL_ASSEMBLER_NAME (decl));
+	  if (alias->symver)
+	    do_assemble_symver (alias->decl,
+			        DECL_ASSEMBLER_NAME (decl));
+	  else
+	    do_assemble_alias (alias->decl,
+			       DECL_ASSEMBLER_NAME (decl));
 	  alias->assemble_thunks_and_aliases ();
 	  TREE_ASM_WRITTEN (decl) = saved_written;
 	}
Index: config/elfos.h
===================================================================
--- config/elfos.h	(revision 278220)
+++ config/elfos.h	(working copy)
@@ -248,6 +248,17 @@  see the files COPYING3 and COPYING.RUNTI
     }					\
   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));					\
+    }								\
+  while (0)
+
 /* The following macro defines the format used to output the second
    operand of the .type assembler directive.  Different svr4 assemblers
    expect various different forms for this operand.  The one given here
Index: doc/extend.texi
===================================================================
--- doc/extend.texi	(revision 278220)
+++ doc/extend.texi	(working copy)
@@ -3640,6 +3640,29 @@  Function Attributes}, @ref{PowerPC Funct
 @ref{Nios II Function Attributes}, and @ref{S/390 Function Attributes}
 for details.
 
+@item symver ("@var{name2}@@@var{nodename}")
+On ELF targets this attribute creates 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 of the alias 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.
+
+@smallexample
+__attribute__ ((__symver__ ("foo@@VERS_1"))) int
+foo_v1 (void)
+@{
+@}
+@end smallexample
+
+Will produce @code{.symver foo_v1, foo@@VERS_1} directive in the assembler
+output.
+
+
+
+@smallexample
+@end smallexample
+
 @item target_clones (@var{options})
 @cindex @code{target_clones} function attribute
 The @code{target_clones} attribute is used to specify that a function
Index: lto-cgraph.c
===================================================================
--- lto-cgraph.c	(revision 278220)
+++ lto-cgraph.c	(working copy)
@@ -526,6 +526,7 @@  lto_output_node (struct lto_simple_outpu
   bp_pack_value (&bp, node->alias, 1);
   bp_pack_value (&bp, node->transparent_alias, 1);
   bp_pack_value (&bp, node->weakref, 1);
+  bp_pack_value (&bp, node->symver, 1);
   bp_pack_value (&bp, node->frequency, 2);
   bp_pack_value (&bp, node->only_called_at_startup, 1);
   bp_pack_value (&bp, node->only_called_at_exit, 1);
@@ -606,6 +607,7 @@  lto_output_varpool_node (struct lto_simp
   bp_pack_value (&bp, node->alias, 1);
   bp_pack_value (&bp, node->transparent_alias, 1);
   bp_pack_value (&bp, node->weakref, 1);
+  bp_pack_value (&bp, node->symver, 1);
   bp_pack_value (&bp, node->analyzed && (!boundary_p || node->alias), 1);
   gcc_assert (node->definition || !node->analyzed);
   /* Constant pool initializers can be de-unified into individual ltrans units.
@@ -1170,6 +1172,7 @@  input_overwrite_node (struct lto_file_de
   node->alias = bp_unpack_value (bp, 1);
   node->transparent_alias = bp_unpack_value (bp, 1);
   node->weakref = bp_unpack_value (bp, 1);
+  node->symver = bp_unpack_value (bp, 1);
   node->frequency = (enum node_frequency)bp_unpack_value (bp, 2);
   node->only_called_at_startup = bp_unpack_value (bp, 1);
   node->only_called_at_exit = bp_unpack_value (bp, 1);
@@ -1363,6 +1366,7 @@  input_varpool_node (struct lto_file_decl
   node->alias = bp_unpack_value (&bp, 1);
   node->transparent_alias = bp_unpack_value (&bp, 1);
   node->weakref = bp_unpack_value (&bp, 1);
+  node->symver = bp_unpack_value (&bp, 1);
   node->analyzed = bp_unpack_value (&bp, 1);
   node->used_from_other_partition = bp_unpack_value (&bp, 1);
   node->in_other_partition = bp_unpack_value (&bp, 1);
Index: output.h
===================================================================
--- output.h	(revision 278220)
+++ output.h	(working copy)
@@ -167,6 +167,7 @@  extern int decode_reg_name (const char *
 extern int decode_reg_name_and_count (const char *, int *);
 
 extern void do_assemble_alias (tree, tree);
+extern void do_assemble_symver (tree, tree);
 
 extern void default_assemble_visibility (tree, int);
 
Index: params.opt
===================================================================
--- params.opt	(revision 278220)
+++ params.opt	(working copy)
@@ -483,7 +483,7 @@  Common Joined UInteger Var(param_max_inl
 The maximum number of instructions in a single function eligible for inlining with -O3 and -Ofast.
 
 -param=max-inline-insns-single-O2=
-Common Joined UInteger Var(param_max_inline_insns_single_o2) Init(30) Param
+Common Joined UInteger Var(param_max_inline_insns_single_o2) Init(70) Param
 The maximum number of instructions in a single function eligible for inlining.
 
 -param=max-inline-insns-size=
Index: symtab.c
===================================================================
--- symtab.c	(revision 278220)
+++ symtab.c	(working copy)
@@ -848,6 +848,8 @@  symtab_node::dump_base (FILE *f)
     fprintf (f, " transparent_alias");
   if (weakref)
     fprintf (f, " weakref");
+  if (symver)
+    fprintf (f, " symver");
   if (cpp_implicit_alias)
     fprintf (f, " cpp_implicit_alias");
   if (alias_target)
@@ -1145,6 +1147,11 @@  symtab_node::verify_base (void)
       error ("node is transparent_alias but not an alias");
       error_found = true;
     }
+  if (symver && !alias)
+    {
+      error ("node is symver but not alias");
+      error_found = true;
+    }
   if (same_comdat_group)
     {
       symtab_node *n = same_comdat_group;
Index: varasm.c
===================================================================
--- varasm.c	(revision 278220)
+++ varasm.c	(working copy)
@@ -5960,6 +5961,23 @@  do_assemble_alias (tree decl, tree targe
 #endif
 }
 
+/* Output .symver directive.  */
+
+void
+do_assemble_symver (tree decl, tree target)
+{
+  tree id = DECL_ASSEMBLER_NAME (decl);
+  ultimate_transparent_alias_target (&id);
+  ultimate_transparent_alias_target (&target);
+#ifdef ASM_OUTPUT_SYMVER_DIRECTIVE
+  ASM_OUTPUT_SYMVER_DIRECTIVE (asm_out_file,
+			       IDENTIFIER_POINTER (target),
+			       IDENTIFIER_POINTER (id));
+#else
+  error ("symver is only supported on ELF platforms");
+#endif
+}
+
 /* Emit an assembler directive to make the symbol for DECL an alias to
    the symbol for TARGET.  */
 
Index: varpool.c
===================================================================
--- varpool.c	(revision 278220)
+++ varpool.c	(working copy)
@@ -540,7 +540,10 @@  varpool_node::assemble_aliases (void)
   FOR_EACH_ALIAS (this, ref)
     {
       varpool_node *alias = dyn_cast <varpool_node *> (ref->referring);
-      if (!alias->transparent_alias)
+      if (alias->symver)
+        do_assemble_symver (alias->decl,
+		            DECL_ASSEMBLER_NAME (decl));
+      else if (!alias->transparent_alias)
 	do_assemble_alias (alias->decl,
 			   DECL_ASSEMBLER_NAME (decl));
       alias->assemble_aliases ();