> 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