[PATCH] Fix symver attribute with LTO
Xi Ruoyao
xry111@mengyan1223.wang
Wed Dec 18 09:59:00 GMT 2019
On 2019-12-18 10:26 +0100, Jan Hubicka wrote:
> Hi,
> sorry I forgot to include cgraph and varpool changes in the patch.
>
> Index: varpool.c
> ===================================================================
> --- varpool.c (revision 279467)
> +++ varpool.c (working copy)
> @@ -539,8 +539,7 @@ varpool_node::assemble_aliases (void)
> {
> varpool_node *alias = dyn_cast <varpool_node *> (ref->referring);
> if (alias->symver)
> - do_assemble_symver (alias->decl,
> - DECL_ASSEMBLER_NAME (decl));
> + do_assemble_symver (alias->decl, decl);
> else if (!alias->transparent_alias)
> do_assemble_alias (alias->decl,
> DECL_ASSEMBLER_NAME (decl));
> Index: cgraphunit.c
> ===================================================================
> --- cgraphunit.c (revision 279467)
> +++ cgraphunit.c (working copy)
> @@ -2222,8 +2222,7 @@ cgraph_node::assemble_thunks_and_aliases
> of buffering it in same alias pairs. */
> TREE_ASM_WRITTEN (decl) = 1;
> if (alias->symver)
> - do_assemble_symver (alias->decl,
> - DECL_ASSEMBLER_NAME (decl));
> + do_assemble_symver (alias->decl, decl);
> else
> do_assemble_alias (alias->decl,
> DECL_ASSEMBLER_NAME (decl));
> Index: varasm.c
> ===================================================================
> --- varasm.c (revision 279467)
> +++ 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);
ICE here.
lto1: internal compiler error: tree check: expected identifier_node, have
function_decl in ultimate_transparent_alias_target, at varasm.c:1308
0x6f9cfe tree_check_failed(tree_node const*, char const*, int, char const*, ...)
../../gcc/gcc/tree.c:9685
0x714541 tree_check(tree_node*, char const*, int, char const*, tree_code)
../../gcc/gcc/tree.h:3273
0x714541 ultimate_transparent_alias_target
../../gcc/gcc/varasm.c:1308
0x714541 do_assemble_symver(tree_node*, tree_node*)
../../gcc/gcc/varasm.c:5971
> #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;
I think this does not make sense. Some library authors may export "foo@VER_1"
but not "foo_v1" to ensure the programmers using the library upgrade their code
to use new "correct" ABI, instead of an old one. This error makes it
impossible.
(Try to comment out "foo_v1" in version.map, in the testcase.)
> + }
> + 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);
We can't replace a single "@" with "@@@". So I think producing .LSYMVERx is not
an option for "old" versions like "foo@VER_1".
> + ASM_OUTPUT_SYMVER_DIRECTIVE (asm_out_file,
> + IDENTIFIER_POINTER
> + (DECL_ASSEMBLER_NAME (tmpdecl)),
> + buf);
> + }
> #else
> error ("symver is only supported on ELF platforms");
> #endif
> Index: lto/lto-common.c
> ===================================================================
> --- lto/lto-common.c (revision 279467)
> +++ 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;
This is absolutely correct.
> else
> snode->resolution = *res;
> }
I still believe we should consider symver targets to be externally visible in
cgraph_externally_visible_p. There is a comment saying "if linker counts on us,
we must preserve the function". That's true in our case.
And, I think
.globl .LSYMVER0
.set .LSYMVER0, foo_v2
.symver .LSYMVER0, foo@@VERS_2
is exactly same as
.globl foo_v2
.symver foo_v2, foo@@VERS_2
except there is an unnecessary ".LSYMVER0". Adding ".globl foo_v2" or ".globl
foo_v1" won't cause them to be "global" in the final DSO because the linker will
hide them according to the version script.
So if it's safe we can force a ".globl foo_v2" before ".symver foo_v2,
foo@@VERS_2". But I can't prove it's safe so I think it's better to consider
this case in cgraph_externally_visible_p.
--
Xi Ruoyao <xry111@mengyan1223.wang>
School of Aerospace Science and Technology, Xidian University
More information about the Gcc-patches
mailing list