Skip to content

Commit 3abebf3

Browse files
committed
Fix JIT TLS on MacOS
The dynamic loader, starting around version 1284, patches the thunk emitted for thread local variables by the compiler, so that its format changes from struct Thunk { void *func; size_t module; size_t offset; } to struct Thunk_v2 { void *func; uint32_t module; uint32_t offset; // other fields } which has the same size, but not the same layout. This is mentionned in https://github.com/apple-oss-distributions/dyld/blob/9307719dd8dc9b385daa412b03cfceb897b2b398/libdyld/ThreadLocalVariables.h#L90 As a result, access to thread specific variables in JIT is broken. Fix by using the new layout when the new dynamic loader is in use. Closes GH-20121
1 parent c89f25b commit 3abebf3

File tree

3 files changed

+42
-4
lines changed

3 files changed

+42
-4
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ PHP NEWS
1818
- Opcache:
1919
. Fixed bug GH-20081 (access to uninitialized vars in preload_load()).
2020
(Arnaud)
21+
. Fixed bug GH-20121 (JIT broken in ZTS builds on MacOS 15).
22+
(Arnaud, Shivam Mathur)
2123

2224
- Phar:
2325
. Fix memory leak of argument in webPhar. (nielsdos)

ext/opcache/jit/zend_jit.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@
5151
#include <pthread.h>
5252
#endif
5353

54+
#if defined(__APPLE__) && defined(__x86_64__)
55+
# include <mach-o/dyld.h>
56+
#endif
57+
5458
#ifdef ZTS
5559
int jit_globals_id;
5660
#else

ext/opcache/jit/zend_jit_x86.dasc

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2826,6 +2826,25 @@ static zend_never_inline void zend_jit_set_sp_adj_vm(void)
28262826
}
28272827
#endif
28282828

2829+
#if defined(__APPLE__) && defined(__x86_64__)
2830+
/* Thunk format used since dydl 1284 (approx. MacOS 15)
2831+
* https://github.com/apple-oss-distributions/dyld/blob/9307719dd8dc9b385daa412b03cfceb897b2b398/libdyld/ThreadLocalVariables.h#L146 */
2832+
struct TLV_Thunkv2
2833+
{
2834+
void* func;
2835+
uint32_t key;
2836+
uint32_t offset;
2837+
};
2838+
2839+
/* Thunk format used in earlier versions */
2840+
struct TLV_Thunkv1
2841+
{
2842+
void* func;
2843+
size_t key;
2844+
size_t offset;
2845+
};
2846+
#endif
2847+
28292848
static int zend_jit_setup(void)
28302849
{
28312850
if (!zend_cpu_supports_sse2()) {
@@ -2889,12 +2908,25 @@ static int zend_jit_setup(void)
28892908
# elif defined(__APPLE__) && defined(__x86_64__)
28902909
tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
28912910
if (tsrm_ls_cache_tcb_offset == 0) {
2892-
size_t *ti;
2911+
struct TLV_Thunkv2 *thunk;
28932912
__asm__(
28942913
"leaq __tsrm_ls_cache(%%rip),%0"
2895-
: "=r" (ti));
2896-
tsrm_tls_offset = ti[2];
2897-
tsrm_tls_index = ti[1] * 8;
2914+
: "=r" (thunk));
2915+
2916+
/* Detect dyld 1284: With dyld 1284, thunk->func will be _tlv_get_addr.
2917+
* Unfortunately this symbol is private, but we can find it
2918+
* as _tlv_bootstrap+8: https://github.com/apple-oss-distributions/dyld/blob/9307719dd8dc9b385daa412b03cfceb897b2b398/libdyld/threadLocalHelpers.s#L54
2919+
* In earlier versions, thunk->func will be tlv_get_addr, which is not
2920+
* _tlv_bootstrap+8.
2921+
*/
2922+
if (thunk->func == (void*)((char*)_tlv_bootstrap + 8)) {
2923+
tsrm_tls_offset = thunk->offset;
2924+
tsrm_tls_index = (size_t)thunk->key * 8;
2925+
} else {
2926+
struct TLV_Thunkv1 *thunkv1 = (struct TLV_Thunkv1*) thunk;
2927+
tsrm_tls_offset = thunkv1->offset;
2928+
tsrm_tls_index = thunkv1->key * 8;
2929+
}
28982930
}
28992931
# elif defined(__GNUC__) && defined(__x86_64__)
29002932
tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();

0 commit comments

Comments
 (0)