Re: [PATCH] lto: Regenerate implicit section names after privatization [PR lto/126841]

Richard Biener <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
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)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.