Skip to content

allow global-dynamic on glibc - #181

Merged
dstogov merged 1 commit into
dstogov:masterfrom
henderkes:master
Aug 20, 2026
Merged

dstogov merged 1 commit into
dstogov:masterfrom
henderkes:master

Conversation

@henderkes

Copy link
Copy Markdown
Contributor

(planned downstream work of moving CG and EG into __thread storage)

@henderkes

Copy link
Copy Markdown
Contributor Author

php/php-src#23227

Comment thread ir_aarch64.dasc
|| code = 0xd53bd040 | reg; // TODO: hard-coded: mrs reg, tpidr_el0
| .long code
||# ifdef __FreeBSD__
||# ifndef __MUSL__

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be it's better to change this into #if defined(__FreeBSD__) || defined(something_else)

@ndossche what do you think? You should know this better than me.

Despite of this change, many years ago I tried moving more TSRM data into native __thread TLS.
That time I had troubles with PHP compiled as DSO Apache module.
The size of some TLS table couldn't grow above some limit defined in the main program.

Using "global-dynmic" will lead to worse code. So what is the benefit?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Despite of this change, many years ago I tried moving more TSRM data into native __thread TLS.
That time I had troubles with PHP compiled as DSO Apache module.
The size of some TLS table couldn't grow above some limit defined in the main program.

Yes, that's glibc's static TLS surplus. Musl doesn't have the concept and therefore (currently, I plan to change this) doesn't set an explicit model. Glibc has the explicit initial-exec optimization for PIC code. Moving EG and CG into __thread storage indeed surpasses the limit which will forces global-dynamic default, resulting in a degradation of the apache module at the benefit of improving performance for all other SAPIs.

For the apache module specifically, I have a --with-tsrm-tls-model flag which package maintainers such as Remi (or myself) can use to still use initial-exec on the apache module. This works because glibc exposes a per-process environment variable GLIBC_TUNABLES that can be set to glibc.rtld.optional_static_tls=8192 to increase the tls surplus. Then the apache module also benefits from saving a tls pointer load every time.

@ndossche ndossche Aug 20, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Long time not heard, hope everything is well.

@ndossche what do you think? You should know this better than me.

The official AArch64 ELF TLS ABI spec leaves the specific layout, and therefore the DTV offset, out of scope:

the details of TLS descriptors are beyond the scope of this specification

It references https://www.fsfla.org/~lxoliva/writeups/TLS/paper-lk2006.pdf for more specific implementation details. This in itself references Ulrich Drepper's document (cite [4]) w.r.t. layout.
On AArch64, all BSD variants seem to use variant 1 as described from Ulrich Drepper's document, they inherited that from a completely different platform: IA64. Variant 1 defines the DTV offset to be 0.

Double-checking common BSD variants:

  • FreeBSD sys/arm64/include/tls.h: TLS_DTV_OFFSET is 0
  • NetBSD sys/sys/tls.h (variant I: void **tcb_dtv; void *tcb_pthread;), and variant I is used on AArch64, i.e. offset 0
  • OpenBSD include/tib.h, sys/arch/arm64/include/tcb.h, again variant 1, { void *tib_dtv; void *tib_thread; }

This appears to be right.
MUSL is the exception where DTV is at offset -8.
But that said, it is safer to explicitly list the platforms rather than stating "everything not MUSL". I prefer explicitness.

@dstogov

dstogov commented Aug 20, 2026

Copy link
Copy Markdown
Owner

@henderkes
Could you please point me into AMD/GLIB/MUSL/FreeBSD docs or headers where the accessed TLS structures are defined?

@henderkes

Copy link
Copy Markdown
Contributor Author

@henderkes Could you please point me into AMD/GLIB/MUSL/FreeBSD docs or headers where the accessed TLS structures are defined?

Not yet. I'll have to look those up with my later musl plans, but for now I'm not changing anything about the branches. Glibc and FreeBSD and Musl all stay the same here, the only difference is that glibc global-dynamic now doesn't fail because the branch wasn't handled. I just assumed it would work the same as on FreeBSD and it indeed did.

@henderkes

henderkes commented Aug 20, 2026 •

Copy link
Copy Markdown
Contributor Author

Generally, the only differences here are having a constant offset (local-exec, initial-offset) or having to go through the DTV (global-dynamic) with the size details dealt with downstream, the only thing we really care about is what offset the DTV is from the thread pointer. That's +0 on freebsd/glibc and -8 on musl, trusting the current implementation. Which means we can actually fold quite a lot of code paths here.

Edit: changed +8 to -8.

That's for a later rework though, I'll get to it because I want to teach the JIT to get the address of a thread local without loading a pointer.

@dstogov

dstogov commented Aug 20, 2026 •

Copy link
Copy Markdown
Owner

According to Google FreeBSD, GLIB and MUSL use similar TLS layout.
TPIDR_EL0 points to 16-byte TCB with the first qword is a pointer to DTV.
See:

https://www.google.com/search?q=glibc+aarch64+thread+control+block+and+thread+local+storage+layout
https://www.google.com/search?q=freebsd+aarch64+thread+control+block+and+thread+local+storage+layout
https://www.google.com/search?q=musl+aarch64+thread+control+block+and+thread+local+storage+layout

I suppose the current FreeBSD part should work for all three libraries.
On MUSL we relay on struct pthread layout with TLS_ABOVE_TP.

https://www.google.com/search?q=musl+struct+pthread

I have no idea why we have to use DTV from struct pthread and not from TCB.

Anyway, this patch won't break anything, so I'm merging it.

@dstogov
dstogov merged commit 275d7e4 into dstogov:master Aug 20, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants