On Mon, 17 Aug 2026, Longjun Luo wrote:

> IPA ICF can create address-preserving wrappers during WPA.  Expanding
> such a wrapper resolves its implicit function-section name before LTO
> privatizes the symbol.  The symbol is subsequently renamed with an
> lto_priv suffix, but the section keeps the pre-privatization name.
> 
> Clear implicit section names on the renamed symbol and its aliases so
> that LTRANS regenerates them from the final assembler name.  Leave
> explicit user-specified section names unchanged.
> 
> Tested on x86_64-pc-linux-gnu.  The new test fails without the change and
> passes with it.  The complete gcc.dg/lto and g++.dg/lto test suites have no
> unexpected results.
> 
>       PR lto/126841
> 
> gcc/ChangeLog:
> 
>       * doc/invoke.texi (-ffunction-sections): Document implicitly generated
>       section names under LTO.
> 
> gcc/lto/ChangeLog:
> 
>       * lto-partition.cc (clear_implicit_section): New.
>       (privatize_symbol_name_1): Clear implicit section names after
>       renaming.
> 
> gcc/testsuite/ChangeLog:
> 
>       * gcc.dg/lto/pr126841_0.c: New test.
>       * gcc.dg/lto/pr126841_1.c: New test.
>       * gcc.dg/lto/pr126841_2.c: New test.
>       * gcc.dg/lto/pr126841_3.c: New test.
> 
> Signed-off-by: Longjun Luo <[email protected]>
> ---
> The change is intentionally kept in privatize_symbol_name_1 rather than
> symbol_table::change_decl_assembler_name.  LTO privatization is the path
> covered by the reproducer and regression test; other assembler-name changes
> have not been audited.
> 
>  gcc/doc/invoke.texi                   |  5 +++++
>  gcc/lto/lto-partition.cc              | 12 ++++++++++++
>  gcc/testsuite/gcc.dg/lto/pr126841_0.c | 22 ++++++++++++++++++++++
>  gcc/testsuite/gcc.dg/lto/pr126841_1.c |  7 +++++++
>  gcc/testsuite/gcc.dg/lto/pr126841_2.c |  7 +++++++
>  gcc/testsuite/gcc.dg/lto/pr126841_3.c |  5 +++++
>  6 files changed, 58 insertions(+)
>  create mode 100644 gcc/testsuite/gcc.dg/lto/pr126841_0.c
>  create mode 100644 gcc/testsuite/gcc.dg/lto/pr126841_1.c
>  create mode 100644 gcc/testsuite/gcc.dg/lto/pr126841_2.c
>  create mode 100644 gcc/testsuite/gcc.dg/lto/pr126841_3.c
> 
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 2e53a8c8a7e..e66cb895ae5 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -16927,6 +16927,11 @@ file if the target supports arbitrary sections.  The 
> name of the
>  function or the name of the data item determines the section's name
>  in the output file.
>  
> +With link-time optimization, an implicitly generated section name is derived
> +from the final assembler name, which may include a compiler-generated suffix
> +to distinguish identically named internal-linkage items from different
> +translation units.
> +

So this doesn't match the implementation which re-computes the section
only when a symbol is privatized?  To match the above it would work
if we'd simply not stream the section name / implicit_section flag
in lto_output_node (for implicit_section section names, that is)?
Saving on streaming size sounds like a good thing as well.

The question is of course what meets user expectation best here.

Richard.

>  Use these options on systems where the linker can perform optimizations to
>  improve locality of reference in the instruction space.  Most systems using 
> the
>  ELF object format have linkers with such optimizations.  On AIX, the linker
> diff --git a/gcc/lto/lto-partition.cc b/gcc/lto/lto-partition.cc
> index 5033ae3f97d..facb5d25907 100644
> --- a/gcc/lto/lto-partition.cc
> +++ b/gcc/lto/lto-partition.cc
> @@ -1797,6 +1797,17 @@ validize_symbol_for_target (symtab_node *node)
>  /* Maps symbol names to unique lto clone counters.  */
>  static hash_map<const char *, unsigned> *lto_clone_numbers;
>  
> +/* Clear compiler-generated section names after changing an assembler name,
> +   so they are regenerated from the final name.  */
> +
> +static bool
> +clear_implicit_section (symtab_node *node, void *)
> +{
> +  if (node->implicit_section)
> +    node->set_section_for_node (NULL);
> +  return false;
> +}
> +
>  /* Helper for privatize_symbol_name.  Mangle NODE symbol name
>     represented by DECL.  */
>  
> @@ -1813,6 +1824,7 @@ privatize_symbol_name_1 (symtab_node *node, tree decl)
>    symtab->change_decl_assembler_name (decl,
>                                     clone_function_name (
>                                         name, "lto_priv", clone_number));
> +  node->call_for_symbol_and_aliases (clear_implicit_section, NULL, true);
>    clone_number++;
>  
>    if (node->lto_file_data)
> diff --git a/gcc/testsuite/gcc.dg/lto/pr126841_0.c 
> b/gcc/testsuite/gcc.dg/lto/pr126841_0.c
> new file mode 100644
> index 00000000000..a0222d3336f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/lto/pr126841_0.c
> @@ -0,0 +1,22 @@
> +/* { dg-lto-do link } */
> +/* { dg-require-effective-target elf } */
> +/* { dg-require-effective-target named_sections } */
> +/* { dg-require-effective-target fpic } */
> +/* { dg-require-effective-target shared } */
> +/* { dg-require-linker-plugin "" } */
> +/* { dg-lto-options { { -O2 -flto -fPIC -shared -ffunction-sections 
> -save-temps } } } */
> +
> +static int
> +same_fn (int x)
> +{
> +  return x * 33 + 7;
> +}
> +
> +int (*a_callback) (int) = same_fn;
> +
> +/* The exported function keeps the unsuffixed section, and each privatized
> +   function must have its own section.  */
> +/* { dg-final { scan-lto-assembler {\.section[ \t]+\.text\.same_fn[, \t"]} } 
> } */
> +/* { dg-final { scan-lto-assembler {\.section[ 
> \t]+\.text\.same_fn\.lto_priv\.0[, \t"]} } } */
> +/* { dg-final { scan-lto-assembler {\.section[ 
> \t]+\.text\.same_fn\.lto_priv\.1[, \t"]} } } */
> +/* { dg-final { scan-lto-assembler {\.section[ 
> \t]+\.text\.same_fn\.lto_priv\.2[, \t"]} } } */
> diff --git a/gcc/testsuite/gcc.dg/lto/pr126841_1.c 
> b/gcc/testsuite/gcc.dg/lto/pr126841_1.c
> new file mode 100644
> index 00000000000..39356acba71
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/lto/pr126841_1.c
> @@ -0,0 +1,7 @@
> +static int
> +same_fn (int x)
> +{
> +  return x * 33 + 7;
> +}
> +
> +int (*b_callback) (int) = same_fn;
> diff --git a/gcc/testsuite/gcc.dg/lto/pr126841_2.c 
> b/gcc/testsuite/gcc.dg/lto/pr126841_2.c
> new file mode 100644
> index 00000000000..369eb1836a6
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/lto/pr126841_2.c
> @@ -0,0 +1,7 @@
> +static int
> +same_fn (int x)
> +{
> +  return x * 33 + 7;
> +}
> +
> +int (*c_callback) (int) = same_fn;
> diff --git a/gcc/testsuite/gcc.dg/lto/pr126841_3.c 
> b/gcc/testsuite/gcc.dg/lto/pr126841_3.c
> new file mode 100644
> index 00000000000..567eb29cda0
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/lto/pr126841_3.c
> @@ -0,0 +1,5 @@
> +int
> +same_fn (int x)
> +{
> +  return x - 1;
> +}
> 

-- 
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Jochen Jaser, Andrew McDonald, Abhinav Puri; (HRB 36809, AG Nuernberg)

Reply via email to