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>