[PATCH] arm: Prevent GCC from using VFP registers in code used during dynamic linking

Aurelien Jarno aurelien@aurel32.net
Tue May 12 18:56:46 GMT 2026


Hi Adhemerval,

On 2026-05-12 10:33, Adhemerval Zanella Netto wrote:
> 
> 
> On 11/05/26 18:50, Aurelien Jarno wrote:
> > On 2026-05-11 15:26, Adhemerval Zanella Netto wrote:
> >>
> >>
> >> On 11/05/26 13:51, Aurelien Jarno wrote:
> >>> On 2026-05-11 10:54, Adhemerval Zanella Netto wrote:
> >>>>
> >>>>
> >>>> On 10/05/26 19:00, Aurelien Jarno wrote:
> >>>>> Starting with GCC 15, VFP registers are used more aggressively on ARM,
> >>>>> including in ld.so code involved in runtime linking. For instance d7 is
> >>>>> used in _dl_lookup_symbol_, which clobbers the 8th floating point
> >>>>> argument of a function on its first call.
> >>>>
> >>>> We added the --with-rtld-early-cflags configure option for avoid such issue,
> >>>> couldn't this be used instead of specific flags to specific objects?
> >>>
> >>> This is a configure option, so do you mean changing the default value 
> >>> for arm?
> >>
> >> I think it should a decision on which ISA do you want to deploy glibc. 
> >> If you targetting armv7a system, runtime should be free to use any register
> >> on dynamic loader.
> > 
> > Yes, I am targetting a armv7a system, this is where the bug exists. I 
> > have opened bug libc/34144 with a small reproducer.
> > 
> >>> Anyway is doesn't work as it misses dl-lookup.os and dl-runtime.os, but 
> >>> works for dl-misc.os.
> >>>
> >>
> >> I think it would be better to add $(rtld-early-cflags) for such objects
> >> as well.
> >>
> >> What I want to avoid is having multiple configurations on how to build
> >> startup code. We already have the stack-protector, stack usage, ifunc
> >> redirections to be aware.
> > 
> > Ok, I confirm that this way works. Now I just need a way to 
> > automatically add -mgeneral-regs-only to rtld-early-cflags on armv7 
> > systems using the hard float ABI. It looks like other architectures are 
> > not using this mechanism to achieve that.
> > 
> 
> Thanks for the testcase, I missed that ARM does not have multiple
> _dl_runtime_resolve.  Other ABIs install different ISA-specific lazy
> resolvers to handle such cases, so I think it would be better to do something 
> similar instead of messing with compiler flags (it might become a rabbit hole,
> since we might eventually need to build a lot of objects with specific flags
> and adds extra maintainability in cases of refactor).

Thanks a lot for this patch, this is indeed a much better approach.

> I think it would be better to do something like 64c7e344289e ("arm: Update 
> _dl_tlsdesc_dynamic to preserve caller-saved registers (BZ 31372)") and
> save/restore the FP registers if chip and kernel supports VFP. It adds
> a small extra cost for lazy-binding, but I think bindnow is the standard
> now.
> 
> Does the following patch fix the issue?

Yes it does :) And I also tested it doesn't cause any regression in the 
testsuite. So:

Tested-by: Aurelien Jarno <aurelien@aurel32.net>

That said I still have a few questions / remarks.

> From b1442daacd0ba33166a05cdcccdd54d93376bea0 Mon Sep 17 00:00:00 2001
> From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
> Date: Tue, 12 May 2026 10:19:03 -0300
> Subject: [PATCH] arm: Save/restore VFP registers in _dl_runtime_resolve (BZ
>  34144)
> 
> The ARM _dl_runtime_resolve PLT trampoline only preserves the integer
> argument registers (r0-r3) around the call to _dl_fixup.  Recent GCC
> emits VFP instructions inside _dl_fixup and the resolvers it invokes,
> which clobbers the caller-saved VFP registers.  Under AAPCS-VFP
> (hardfp), d0-d7 are used to pass double arguments, so the first PLT
> call to a function taking floating-point arguments sees corrupted
> values.
> 
> Save and restore the VFP registers around the _dl_fixup call, gated on
> hwcap (HWCAP_ARM_VFP for softfp builds, HWCAP_ARM_VFPD32 for the upper
> bank d16-d31), mirroring the approach used by _dl_tlsdesc_dynamic in
> commit 64c7e344289e ("arm: Update _dl_tlsdesc_dynamic to preserve
> caller-saved registers (BZ 31372)").  Use .inst encodings for the VFP
> load/store multiple instructions so the file still assembles in
> non-VFP multilibs.  The fix is wrapped in #ifdef SHARED because
> _dl_runtime_resolve is only ever invoked from ld.so; the static libc
> copy is dead code.

I don't understand why this needs to be tested at runtime and can't be 
done at build time. In my understanding there are two possibilities:

- glibc (or rather ld.so) is built with VFP support. In that case 
  VFP registers must be saved and restored. There is no need to check 
  for HWCAP, as if VFP registers are used, the code won't run on 
  hardware without VFP support.

- glibc (or rather ld.so) is built without VFP support. In that case 
  there is no need to save and restore VFP registers, as they are not 
  clobbered.

The same reasoning can be done with VFP D16 vs VFP D32.

Therefore I think there is just a need to test support at build time. I 
guess checking for HAVE_ARM_PCS_VFP and HAVE_ARM_PCS_VFP_D32 is enough.

> A new test, tst-bz34144, follows the reproducer from the bug
> report: a shared-library function takes eight double arguments and
> verifies their values, while the main program issues the first
> (lazy-resolved) call.

Sounds good. I wonder if it should just be a generic test to catch 
(future) similar issues on other architectures.

Thanks
Aurelien

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                     http://aurel32.net


More information about the Libc-alpha mailing list