[Bug target/126394] New: arm: stack misalignment when leaf procedures read tp via __aeabi_read_tp

campbell+gcc-bugzilla at mumble dot net via Gcc-bugs <[email protected]>
Newsgroups gmane.comp.gcc.bugs
Message-ID <[email protected]/bugzilla/>
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126394

            Bug ID: 126394
           Summary: arm: stack misalignment when leaf procedures read tp
                    via __aeabi_read_tp
           Product: gcc
           Version: 14.3.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: campbell+gcc-bugzilla at mumble dot net
  Target Milestone: ---

When

__thread int x = 0;
int *
get_x(void)
{
        return &x;
}

is compiled with -mtp=soft, as is the default on older Arm
architectures, gcc treats it as a leaf procedure whose use of
load_tp_soft clobbers lr, so it saves and restores _just lr_ but
generates a procedure call nevertheless to __aeabi_read_tp:

00000000 <get_x>:
get_x():
   0:   e52de004        push    {lr}            @ (str lr, [sp, #-4]!)
   4:   ebfffffe        bl      0 <__aeabi_read_tp>
                        4: R_ARM_CALL   __aeabi_read_tp
   8:   e59f3004        ldr     r3, [pc, #4]    @ 14 <get_x+0x14>
   c:   e0830000        add     r0, r3, r0
  10:   e49df004        pop     {pc}            @ (ldr pc, [sp], #4)
  14:   00000000        .word   0x00000000
                        14: R_ARM_TLS_LE32      .LANCHOR0

Even if __aeabi_read_tp doesn't care about the stack alignment, the
symbol may be resolved lazily by a detour through the dynamic linker
which does care about it.

In NetBSD, we're considering patching arm_compute_frame_layout to force
stack alignment even for leaf procedures if -mtp=soft in order to fix
this for earmv5 builds:

--- a/external/gpl3/gcc/dist/gcc/config/arm/arm.cc      Fri Jul 24 03:41:48
2026 +0000
+++ b/external/gpl3/gcc/dist/gcc/config/arm/arm.cc      Fri Jul 24 15:11:45
2026 +0000
@@ -23156,7 +23156,16 @@ arm_compute_frame_layout (void)
   if (crtl->is_leaf && frame_size == 0
       /* However if it calls alloca(), we have a dynamically allocated
         block of BIGGEST_ALIGNMENT on stack, so still do stack alignment.  */
-      && ! cfun->calls_alloca)
+      && ! cfun->calls_alloca
+      /* If queries to the thread pointer go through __aeabi_read_tp,
+        we must ensure the stack has correct alignment even though we
+        think of this as a leaf routine.  Even if __aeabi_read_tp
+        itself doesn't use the stack, resolving the symbol may take a
+        detour through a procedure call to the dynamic linker.  We
+        should really enforce alignment only if the procedure actually
+        uses __aeabi_read_tp (load_tp_soft*) but I don't know how to
+        query that here.  */
+      && !TARGET_SOFT_TP)
     {
       offsets->outgoing_args = offsets->soft_frame;
       offsets->locals_base = offsets->soft_frame;

However, ideally, we would do this only for leaf procedures that
actually use __aeabi_read_tp, and while that information should be easy
to evaluate in principle, it's not obvious how to conveniently detect
it in context.

Originally discovered as:

NetBSD PR lib/57638: thread local storage broken on evbarm (armv5)
<https://gnats.NetBSD.org/57638>
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.