GNU bug report logs - #80153
libtool: 2.5.4 - gcc 16 --push-state --as-needed -latomic --pop-state vs. libtool

Previous Next

Package: libtool;

Reported by: Jakub Jelinek <jakub <at> redhat.com>

Date: Thu, 8 Jan 2026 15:14:01 UTC

Severity: normal

To reply to this bug, email your comments to 80153 AT debbugs.gnu.org.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-libtool <at> gnu.org:
bug#80153; Package libtool. (Thu, 08 Jan 2026 15:14:01 GMT) Full text and rfc822 format available.

Acknowledgement sent to Jakub Jelinek <jakub <at> redhat.com>:
New bug report received and forwarded. Copy sent to bug-libtool <at> gnu.org. (Thu, 08 Jan 2026 15:14:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Jakub Jelinek <jakub <at> redhat.com>
To: bug-libtool <at> gnu.org
Subject: libtool: 2.5.4 - gcc 16 --push-state --as-needed -latomic
 --pop-state vs. libtool
Date: Thu, 8 Jan 2026 12:25:41 +0100
Hi!

gcc 16 in https://gcc.gnu.org/r16-4315 https://gcc.gnu.org/PR81358 change
added --push-state --as-needed -latomic --pop-state to the collect2/ld
invocation from the gcc/g++ etc. drivers.

Unfortunately libtool.m4 in the loop starting with
  # Parse the compiler output and extract the necessary
  # objects, libraries and library flags.
grabs object files and libraries and -L/-R options from the compiler
driver invocation of the linker and grabs them without these
--push-state --as-needed / --pop-state wrapping options, which are needed
to only link the library in if it is actually needed.
I think on Solaris the pair is -z ignore / -z record instead, but
unfortunately in that case it is less clear if those options are meant to
affect just the single library and so are a property of that library, or
if they have been randomly added e.g. by the user or whatever and affect
instead what comes after it or multiple libraries etc.

Anyway, what we see in gcc, as mentioned in https://gcc.gnu.org/PR123396
is that several shared libraries linked with libtool are then uselessly
linked to libatomic.so:
for i in libstdc++-v3/src/.libs/libstdc++.so.6.*.* libsanitizer/*/.libs/lib*.so.*.* libgcobol/.libs/lib*.so.*.*; do echo $i; ldd -u $i; done
libstdc++-v3/src/.libs/libstdc++.so.6.0.35
Unused direct dependencies:
	/lib64/libatomic.so.1
libsanitizer/asan/.libs/libasan.so.8.0.0
Unused direct dependencies:
	/lib64/libatomic.so.1
libsanitizer/hwasan/.libs/libhwasan.so.0.0.0
Unused direct dependencies:
	/lib64/libm.so.6
	/lib64/libatomic.so.1
libsanitizer/lsan/.libs/liblsan.so.0.0.0
Unused direct dependencies:
	/lib64/libm.so.6
	/lib64/libatomic.so.1
libsanitizer/tsan/.libs/libtsan.so.2.0.0
Unused direct dependencies:
	/lib64/libatomic.so.1
libsanitizer/ubsan/.libs/libubsan.so.1.0.0
Unused direct dependencies:
	/lib64/libm.so.6
	/lib64/libatomic.so.1
libgcobol/.libs/libgcobol.so.2.0.0
Unused direct dependencies:
	/lib64/libatomic.so.1
E.g. for libstdc++-v3, libtool created by configure has
postdep_objects="/home/jakub/src/gcc/obj38/./gcc/crtendS.o /lib/../lib64/crtn.o"
postdeps=" -lgcc_s -latomic -lc -lgcc_s "

I see -latomic in postdeps or postdeps_CXX in other packags, e.g. when
gettext is built with gcc 16, but in that case I actually don't see any
shared library or binary linked uselessly against libatomic.so.1; not really
sure why though.

In https://gcc.gnu.org/pipermail/gcc-patches/2025-December/704644.html
the PR81358 patch author suggested to work around this by filtering
out -latomic from postdeps_CXX, though I think that just means the libraries
will never be linked against libatomic.so.1 rather than only linking against
it on architectures where e.g. some atomics aren't provided by inlined code
and need to fallback to libatomic.so.1.

So, I've been wondering if the libtool.m4
  # Parse the compiler output and extract the necessary
  # objects, libraries and library flags.
couldn't special case at least the --push-state --as-needed options before
-lXXX option and --pop-state after it and in that case put into postdeps_*
var instead of just -lXXX
$_LT_TAGVAR(lt_prog_compiler_wl, $1)--push-state $_LT_TAGVAR(lt_prog_compiler_wl, $1)--as-needed -lXXX $_LT_TAGVAR(lt_prog_compiler_wl, $1)
But I admit I haven't studied in detail in what exactly the postdeps var is
used.

	Jakub





Information forwarded to bug-libtool <at> gnu.org:
bug#80153; Package libtool. (Thu, 08 Jan 2026 17:12:02 GMT) Full text and rfc822 format available.

Message #8 received at 80153 <at> debbugs.gnu.org (full text, mbox):

From: Frederic Berat <fberat <at> redhat.com>
To: Jakub Jelinek <jakub <at> redhat.com>
Cc: 80153 <at> debbugs.gnu.org
Subject: Re: bug#80153: libtool: 2.5.4 - gcc 16 --push-state --as-needed
 -latomic --pop-state vs. libtool
Date: Thu, 8 Jan 2026 18:10:59 +0100
[Message part 1 (text/plain, inline)]
On Thu, Jan 8, 2026 at 4:14 PM Jakub Jelinek via bug-libtool via Bug
reports for the GNU libtool shared library maintenance tool <
bug-libtool <at> gnu.org> wrote:

> Hi!
>
> gcc 16 in https://gcc.gnu.org/r16-4315 https://gcc.gnu.org/PR81358 change
> added --push-state --as-needed -latomic --pop-state to the collect2/ld
> invocation from the gcc/g++ etc. drivers.
>
> Unfortunately libtool.m4 in the loop starting with
>   # Parse the compiler output and extract the necessary
>   # objects, libraries and library flags.
> grabs object files and libraries and -L/-R options from the compiler
> driver invocation of the linker and grabs them without these
> --push-state --as-needed / --pop-state wrapping options, which are needed
> to only link the library in if it is actually needed.
> I think on Solaris the pair is -z ignore / -z record instead, but
> unfortunately in that case it is less clear if those options are meant to
> affect just the single library and so are a property of that library, or
> if they have been randomly added e.g. by the user or whatever and affect
> instead what comes after it or multiple libraries etc.
>
> Anyway, what we see in gcc, as mentioned in https://gcc.gnu.org/PR123396
> is that several shared libraries linked with libtool are then uselessly
> linked to libatomic.so:
> for i in libstdc++-v3/src/.libs/libstdc++.so.6.*.*
> libsanitizer/*/.libs/lib*.so.*.* libgcobol/.libs/lib*.so.*.*; do echo $i;
> ldd -u $i; done
> libstdc++-v3/src/.libs/libstdc++.so.6.0.35
> Unused direct dependencies:
>         /lib64/libatomic.so.1
> libsanitizer/asan/.libs/libasan.so.8.0.0
> Unused direct dependencies:
>         /lib64/libatomic.so.1
> libsanitizer/hwasan/.libs/libhwasan.so.0.0.0
> Unused direct dependencies:
>         /lib64/libm.so.6
>         /lib64/libatomic.so.1
> libsanitizer/lsan/.libs/liblsan.so.0.0.0
> Unused direct dependencies:
>         /lib64/libm.so.6
>         /lib64/libatomic.so.1
> libsanitizer/tsan/.libs/libtsan.so.2.0.0
> Unused direct dependencies:
>         /lib64/libatomic.so.1
> libsanitizer/ubsan/.libs/libubsan.so.1.0.0
> Unused direct dependencies:
>         /lib64/libm.so.6
>         /lib64/libatomic.so.1
> libgcobol/.libs/libgcobol.so.2.0.0
> Unused direct dependencies:
>         /lib64/libatomic.so.1
> E.g. for libstdc++-v3, libtool created by configure has
> postdep_objects="/home/jakub/src/gcc/obj38/./gcc/crtendS.o
> /lib/../lib64/crtn.o"
> postdeps=" -lgcc_s -latomic -lc -lgcc_s "
>
> I see -latomic in postdeps or postdeps_CXX in other packags, e.g. when
> gettext is built with gcc 16, but in that case I actually don't see any
> shared library or binary linked uselessly against libatomic.so.1; not
> really
> sure why though.
>
> In https://gcc.gnu.org/pipermail/gcc-patches/2025-December/704644.html
> the PR81358 patch author suggested to work around this by filtering
> out -latomic from postdeps_CXX, though I think that just means the
> libraries
> will never be linked against libatomic.so.1 rather than only linking
> against
> it on architectures where e.g. some atomics aren't provided by inlined code
> and need to fallback to libatomic.so.1.
>
> So, I've been wondering if the libtool.m4
>   # Parse the compiler output and extract the necessary
>   # objects, libraries and library flags.
> couldn't special case at least the --push-state --as-needed options before
> -lXXX option and --pop-state after it and in that case put into postdeps_*
> var instead of just -lXXX
> $_LT_TAGVAR(lt_prog_compiler_wl, $1)--push-state
> $_LT_TAGVAR(lt_prog_compiler_wl, $1)--as-needed -lXXX
> $_LT_TAGVAR(lt_prog_compiler_wl, $1)
> But I admit I haven't studied in detail in what exactly the postdeps var is
> used.
>
>
I've attached a standalone reproduction script that I tested in a
fedora-rawhide environment with GCC16.
And a patch that I'm planning to apply on fedora's libtool 2.5.4 (I don't
have the master equivalent yet), although I'm not sure that I do what I
should there, so I'd be pleased to get feedback.

Without the patch, libtool generates the following command:

libtool: link: g++ -std=gnu++11  -fPIC -DPIC -shared -nostdlib
/usr/lib/gcc/x86_64-redhat-linux/16/../../../../lib64/crti.o
/usr/lib/gcc/x86_64-redhat-linux/16/crtbeginS.o  .libs/repro.o
-L/usr/lib/gcc/x86_64-redhat-linux/16
-L/usr/lib/gcc/x86_64-redhat-linux/16/../../../../lib64 -L/lib/../lib64
-L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/16/../../.. -L/lib
-L/usr/lib -lstdc++ -lm -lgcc_s -latomic -lc -lgcc_s
/usr/lib/gcc/x86_64-redhat-linux/16/crtendS.o
/usr/lib/gcc/x86_64-redhat-linux/16/../../../../lib64/crtn.o    -Wl,-soname
-Wl,librepro.so.0 -o .libs/librepro.so.0.0.0

The push-state/as-needed/pop-state gets stripped.

With the patch we get that one:

libtool: link: g++ -std=gnu++11  -fPIC -DPIC -shared -nostdlib
/usr/lib/gcc/x86_64-redhat-linux/16/../../../../lib64/crti.o
/usr/lib/gcc/x86_64-redhat-linux/16/crtbeginS.o  .libs/repro.o
-L/usr/lib/gcc/x86_64-redhat-linux/16
-L/usr/lib/gcc/x86_64-redhat-linux/16/../../../../lib64 -L/lib/../lib64
-L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/16/../../.. -L/lib
-L/usr/lib -lstdc++ -lm -lgcc_s -Wl,--push-state -Wl,--as-needed -latomic
-Wl,--pop-state -lc -lgcc_s /usr/lib/gcc/x86_64-redhat-linux/16/crtendS.o
/usr/lib/gcc/x86_64-redhat-linux/16/../../../../lib64/crtn.o    -Wl,-soname
-Wl,librepro.so.0 -o .libs/librepro.so.0.0.0

Fred.


>         Jakub
>
>
>
>
>
[Message part 2 (text/html, inline)]
[0001-Preserve-positional-linker-state-flags.patch (text/x-patch, attachment)]
[repro.sh (application/x-shellscript, attachment)]

Information forwarded to bug-libtool <at> gnu.org:
bug#80153; Package libtool. (Fri, 09 Jan 2026 15:59:02 GMT) Full text and rfc822 format available.

Message #11 received at 80153 <at> debbugs.gnu.org (full text, mbox):

From: Jakub Jelinek <jakub <at> redhat.com>
To: Frederic Berat <fberat <at> redhat.com>
Cc: 80153 <at> debbugs.gnu.org
Subject: Re: bug#80153: libtool: 2.5.4 - gcc 16 --push-state --as-needed
 -latomic --pop-state vs. libtool
Date: Fri, 9 Jan 2026 16:57:53 +0100
On Thu, Jan 08, 2026 at 06:10:59PM +0100, Frederic Berat wrote:
> I've attached a standalone reproduction script that I tested in a
> fedora-rawhide environment with GCC16.
> And a patch that I'm planning to apply on fedora's libtool 2.5.4 (I don't
> have the master equivalent yet), although I'm not sure that I do what I
> should there, so I'd be pleased to get feedback.

Thanks.

> Without the patch, libtool generates the following command:

For libtool.m4, I've been thinking more about something like below
(though this patch is for the much older libtool.m4 copy in gcc
instead of 2.5.4).
So that it doesn't copy random --push-state or --as-needed etc.
option, only the cases where it is exactly
--push-state --{,no-}as-needed -l* --pop-state
where there is a single -l* will have the wrappers and other cases
will not.  As those are the cases where we know for sure the
corresponding option is meant to override just that single library and
nothing else.
E.g.
--as-needed or --no-as-needed could come up on random other places of
the command line based on distro defaults or $CC used etc.

--- libtool.m4	2025-12-30 22:20:58.573130385 +0100
+++ libtool.m4	2026-01-09 16:51:35.393699435 +0100
@@ -6634,8 +6634,70 @@ if AC_TRY_EVAL(ac_compile); then
   # Sentinel used to keep track of whether or not we are before
   # the conftest object file.
   pre_test_object_deps_done=no
+  state_pre=
+  state_post=
+
+  for pp in `eval "$output_verbose_link_cmd"`; do
+    p=$pp
+    case $p in
+
+    --push-state)
+       # Handle --push-state --as-needed -lfoo --pop-state
+       state_pre=$p
+       continue
+       ;;
+
+    --as-needed|--no-as-needed)
+       if test x$state_pre == x--push-state; then
+	 state_pre="$state_pre $p "
+       else
+	 state_pre=
+       fi
+       continue
+       ;;
+
+    --pop-state)
+       case "$state_pre" in
+       "--push-state --"*)
+	  case "$prev" in
+	  -l*)
+	    state_post=" $p"
+	    p=$prev
+	    prev=
+	    ;;
+	  *)
+	    state_pre=
+	    ;;
+	  esac
+	  ;;
+       *)
+	  state_pre=
+	  ;;
+       esac
+       ;;
+ 
+    -l*)
+       case "$state_pre" in
+       "--push-state --"*)
+         if test -z "$prev"; then
+	   prev=$p
+	   continue
+         fi
+         p="${prev} ${p}"
+         state_pre=
+         ;;
+       *)
+         state_pre=
+         ;;
+       esac
+       ;;
+ 
+    *)
+       state_pre=
+       ;;
+
+    esac
 
-  for p in `eval "$output_verbose_link_cmd"`; do
     case $p in
 
     -L* | -R* | -l*)
@@ -6666,11 +6728,13 @@ if AC_TRY_EVAL(ac_compile); then
 	 esac
        else
 	 if test -z "$_LT_TAGVAR(postdeps, $1)"; then
-	   _LT_TAGVAR(postdeps, $1)="${prev}${p}"
+	   _LT_TAGVAR(postdeps, $1)="${state_pre}${prev}${p}${state_post}"
 	 else
-	   _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
+	   _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${state_pre}${prev}${p}${state_post}"
 	 fi
        fi
+       state_pre=
+       state_post=
        ;;
 
     *.$objext)

	Jakub





This bug report was last modified 2 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.