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>
  • [Bug target/126394] N... campbell+gcc-bugzilla at mumble dot net via Gcc-bugs

Reply via email to