Commit d7ddfbcb by Jan Hubicka Committed by Jan Hubicka

cgraph.h (symtab_node): Add symver flag.


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.

From-SVN: r278878
parent 65ef05d0
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.
2019-11-30 Richard Sandiford <richard.sandiford@arm.com>
* target.h (type_context_kind): New enum.
2019-11-30 Jan Hubicka <hubicka@ucw.cz>
* c-attribs.c (handle_symver_attribute): New function
(c_common_attributes): Add symver.
2019-11-30 Richard Sandiford <richard.sandiford@arm.com>
* c-common.c (pointer_int_sum): Use verify_type_context to check
......
......@@ -66,6 +66,7 @@ static tree handle_stack_protect_attribute (tree *, tree, tree, int, bool *);
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_attribute_table[] =
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 name,
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. */
......
......@@ -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;
......
......@@ -711,6 +711,89 @@ symbol_table::process_same_body_aliases (void)
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 *node, tree decl)
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 (void)
/* 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;
}
......
......@@ -248,6 +248,17 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
} \
while (0)
#define ASM_OUTPUT_SYMVER_DIRECTIVE(FILE, NAME, NAME2) \
do \
{ \
fputs ("\t.symver\t", (FILE)); \
assemble_name ((FILE), (NAME)); \
fputs (", ", (FILE)); \
assemble_name ((FILE), (NAME2)); \
fputc ('\n', (FILE)); \
} \
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
......
......@@ -3711,6 +3711,41 @@ Function Attributes}, @ref{PowerPC Function Attributes},
@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
......
......@@ -526,6 +526,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
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_simple_output_block *ob, varpool_node *node,
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_decl_data *file_data,
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_data *file_data,
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);
......
......@@ -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);
......
......@@ -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 *target, bool transparent)
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);
......
......@@ -5960,6 +5960,23 @@ do_assemble_alias (tree decl, tree target)
#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. */
......
......@@ -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 ();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment