> Would it be equivalent to:
> 1) output foo_v2 local
> 2) producing static alias with local name (.L1)
> 3) do .symver .L1,foo@@@VERS_2
> That is somewhat more systematic and would not lead to false
> visibilities.
I spent some time playing with this. An in order to
1) be able to handle foo_v2 according to the resolution info
(so it behaves like a regular symbol and can be called dirrectly,
localized and optimized)
2) get intended objdump -T relocations
3) do not polute global symbol tables
I ended up with the following codegen:
.type foo_v2, @function
foo_v2:
.LFB1:
.cfi_startproc
movl $2, %eax
ret
.cfi_endproc
.LFE1:
.size foo_v2, .-foo_v2
.globl .LSYMVER0
.set .LSYMVER0,foo_v2
.symver .LSYMVER0, foo@@@VERS_2
This uses @@@ symver version of gas which seems to have odd semantics of
requiring to be passed global symbol name which it then tkes away and
produces foo@@VERS_2.
So the nm outoutp of the ltrans unit is:
0000000000000000 T foo_v1
0000000000000010 t foo_v2
0000000000000000 T foo@VERS_1
0000000000000010 T foo@@VERS_2
So the difference to your patch is that foo_v2 is static which enables
normal optimizations.
Since additional symbol alias is produced this would also make it
possible to attach multiple symver attributes with @@ string.
Does somehting like this make sense to you? Modulo the obvious buffer
overflow issue?
Honza
Index: lto/lto-common.c
===================================================================
--- lto/lto-common.c (revision 279178)
+++ lto/lto-common.c (working copy)
@@ -2818,6 +2818,10 @@ read_cgraph_and_symbols (unsigned nfiles
IDENTIFIER_POINTER
(DECL_ASSEMBLER_NAME (snode->decl)));
}
+ /* Symbol versions are always used externally, but linker does not
+ report that correctly. */
+ else if (snode->symver && *res == LDPR_PREVAILING_DEF_IRONLY)
+ snode->resolution = LDPR_PREVAILING_DEF_IRONLY_EXP;
else
snode->resolution = *res;
}
Index: varasm.c
===================================================================
--- varasm.c (revision 279178)
+++ varasm.c (working copy)
@@ -5970,9 +5970,47 @@ do_assemble_symver (tree decl, tree targ
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));
+ if (TREE_PUBLIC (target) && DECL_VISIBILITY (target) == VISIBILITY_DEFAULT)
+ ASM_OUTPUT_SYMVER_DIRECTIVE (asm_out_file,
+ IDENTIFIER_POINTER
+ (DECL_ASSEMBLER_NAME (target)),
+ IDENTIFIER_POINTER (id));
+ else
+ {
+ int nameend;
+ for (nameend = 0; IDENTIFIER_POINTER (id)[nameend] != '@'; nameend++)
+ ;
+ if (IDENTIFIER_POINTER (id)[nameend + 1] != '@'
+ || IDENTIFIER_POINTER (id)[nameend + 2] == '@')
+ {
+ sorry_at (DECL_SOURCE_LOCATION (target),
+ "can not produce %<symver%> of a symbol that is "
+ "not exported with default visibility");
+ return;
+ }
+ tree tmpdecl = copy_node (decl);
+ char buf[256];
+ static int symver_labelno;
+ targetm.asm_out.generate_internal_label (buf,
+ "LSYMVER", symver_labelno++);
+ SET_DECL_ASSEMBLER_NAME (tmpdecl, get_identifier (buf));
+ globalize_decl (tmpdecl);
+#ifdef ASM_OUTPUT_DEF_FROM_DECLS
+ ASM_OUTPUT_DEF_FROM_DECLS (asm_out_file, tmpdecl,
+ DECL_ASSEMBLER_NAME (target));
+#else
+ ASM_OUTPUT_DEF (asm_out_file,
+ IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (tmpdecl)),
+ IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (target)));
+#endif
+ memcpy (buf, IDENTIFIER_POINTER (id), nameend + 2);
+ buf[nameend + 2] = '@';
+ strcpy (buf + nameend + 3, IDENTIFIER_POINTER (id) + nameend + 2);
+ ASM_OUTPUT_SYMVER_DIRECTIVE (asm_out_file,
+ IDENTIFIER_POINTER
+ (DECL_ASSEMBLER_NAME (tmpdecl)),
+ buf);
+ }
#else
error ("symver is only supported on ELF platforms");
#endif