Skip to content

Commit 2fde1d5

Browse files
committed
JIT: recognize initial-exec TLS relaxation
Also resolve the Windows TLS slot by address instead of scanning for a matching value. See #23227
1 parent 0a98b97 commit 2fde1d5

5 files changed

Lines changed: 43 additions & 50 deletions

File tree

‎ext/opcache/jit/tls/testing/test.sh‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ dl_def_static_user_no_surplus() {
136136

137137
rm -f main
138138

139-
$CC $CFLAGS -ggdb3 -fPIC -o tls.o -c $TLSC
140-
$CC $CFLAGS -ggdb3 -fPIC -o user.o -c user.c
139+
$CC $CFLAGS -DTSRM_TLS_MODEL_USE_DEFAULT -ggdb3 -fPIC -o tls.o -c $TLSC
140+
$CC $CFLAGS -DTSRM_TLS_MODEL_USE_DEFAULT -ggdb3 -fPIC -o user.o -c user.c
141141
$CC $CFLAGS -DNO_SURPLUS -ggdb3 -fPIC -o def.o -c def.c
142142
$CC $CFLAGS $LDFLAGS -shared -o libdef.so def.o user.o tls.o
143143

@@ -151,8 +151,8 @@ dl_def_shared_user_no_surplus() {
151151

152152
rm -f main
153153

154-
$CC $CFLAGS -ggdb3 -fPIC -o tls.o -c $TLSC
155-
$CC $CFLAGS -ggdb3 -fPIC -o user.o -c user.c
154+
$CC $CFLAGS -DTSRM_TLS_MODEL_USE_DEFAULT -ggdb3 -fPIC -o tls.o -c $TLSC
155+
$CC $CFLAGS -DTSRM_TLS_MODEL_USE_DEFAULT -ggdb3 -fPIC -o user.o -c user.c
156156
$CC $CFLAGS $LDFLAGS -shared -o libuser.so user.o tls.o
157157

158158
$CC $CFLAGS -DNO_SURPLUS -ggdb3 -fPIC -o def.o -c def.c

‎ext/opcache/jit/tls/testing/user.c‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
#include "../zend_jit_tls.h"
55

6-
extern __thread void* _tsrm_ls_cache;
6+
TSRMLS_MAIN_CACHE_EXTERN()
77

88
int test(void)
99
{
@@ -12,7 +12,7 @@ int test(void)
1212
size_t module_offset = -1;
1313

1414
/* Ensure the slot is allocated */
15-
_tsrm_ls_cache = NULL;
15+
void *cache = &_tsrm_ls_cache;
1616

1717
zend_result result = zend_jit_resolve_tsrm_ls_cache_offsets(
1818
&tcb_offset, &module_index, &module_offset);
@@ -24,5 +24,5 @@ int test(void)
2424
return 0;
2525
}
2626

27-
return zend_jit_tsrm_ls_cache_address(tcb_offset, module_index, module_offset) == &_tsrm_ls_cache;
27+
return zend_jit_tsrm_ls_cache_address(tcb_offset, module_index, module_offset) == cache;
2828
}

‎ext/opcache/jit/tls/zend_jit_tls_aarch64.c‎

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -192,18 +192,6 @@ zend_result zend_jit_resolve_tsrm_ls_cache_offsets(
192192

193193
/* Code was changed by the linker. Check if we recognize the updated code */
194194

195-
// movz x0, #0, lsl #16
196-
if ((insn[0] & ~AARCH64_MOVZ_IMM_MASK) != 0xd2a00000) {
197-
zend_accel_error(ACCEL_LOG_DEBUG, "movz insn does not match: 0x%08" PRIx32 "\n", insn[0]);
198-
return FAILURE;
199-
}
200-
201-
// movk x0, #0x10
202-
if ((insn[1] & ~AARCH64_MOVK_IMM_MASK) != 0xf2800000) {
203-
zend_accel_error(ACCEL_LOG_DEBUG, "movk insn does not match: 0x%08" PRIx32 "\n", insn[1]);
204-
return FAILURE;
205-
}
206-
207195
// nop
208196
for (int i = 0; i < 2; i++) {
209197
if (insn[2+i] != AARCH64_NOP) {
@@ -212,12 +200,29 @@ zend_result zend_jit_resolve_tsrm_ls_cache_offsets(
212200
}
213201
}
214202

215-
/* Extract immediate values */
203+
if ((insn[0] & ~AARCH64_ADRP_IMM_MASK) == 0x90000000) {
204+
/* initial-exec */
205+
// ldr x0, [x0, #any]
206+
if ((insn[1] & ~AARCH64_LDR_UNSIGNED_IMM_MASK) != 0xf9400000) {
207+
zend_accel_error(ACCEL_LOG_DEBUG, "ldr insn does not match: 0x%08" PRIx32 "\n", insn[1]);
208+
return FAILURE;
209+
}
210+
} else {
211+
/* local-exec */
212+
// movz x0, #0, lsl #16
213+
if ((insn[0] & ~AARCH64_MOVZ_IMM_MASK) != 0xd2a00000) {
214+
zend_accel_error(ACCEL_LOG_DEBUG, "movz insn does not match: 0x%08" PRIx32 "\n", insn[0]);
215+
return FAILURE;
216+
}
217+
218+
// movk x0, #0x10
219+
if ((insn[1] & ~AARCH64_MOVK_IMM_MASK) != 0xf2800000) {
220+
zend_accel_error(ACCEL_LOG_DEBUG, "movk insn does not match: 0x%08" PRIx32 "\n", insn[1]);
221+
return FAILURE;
222+
}
223+
}
216224

217-
uint64_t movz_imm = (insn[0] & AARCH64_MOVZ_IMM_MASK) >> 5;
218-
uint64_t movz_shift = (((insn[0] & AARCH64_MOVZ_HW_MASK) >> 21) << 4);
219-
uint64_t movk_imm = (insn[1] & AARCH64_MOVK_IMM_MASK) >> 5;
220-
uint64_t offset = (movz_imm << movz_shift) | movk_imm;
225+
uintptr_t offset = (uintptr_t)addr - (uintptr_t)thread_pointer;
221226

222227
if ((uintptr_t)&_tsrm_ls_cache - (uintptr_t)thread_pointer == offset) {
223228
zend_accel_error(ACCEL_LOG_DEBUG, "static tls at offset %" PRIxPTR " from thread pointer (inferred from code)\n", offset);

‎ext/opcache/jit/tls/zend_jit_tls_win.c‎

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,30 +33,20 @@ zend_result zend_jit_resolve_tsrm_ls_cache_offsets(
3333
size_t *module_index,
3434
size_t *module_offset
3535
) {
36-
/* To find offset of "_tsrm_ls_cache" in TLS segment we perform a linear scan of local TLS memory */
37-
/* Probably, it might be better solution */
36+
/* Offset of _tsrm_ls_cache within this module's TLS block. */
3837
#ifdef _WIN64
3938
void ***tls_mem = ((void****)__readgsqword(0x58))[_tls_index];
4039
#else
4140
void ***tls_mem = ((void****)__readfsdword(0x2c))[_tls_index];
4241
#endif
43-
void *val = _tsrm_ls_cache;
44-
size_t offset = 0;
4542
size_t size = (char*)&_tls_end - (char*)&_tls_start;
46-
47-
while (offset < size) {
48-
if (*tls_mem == val) {
49-
*module_index = _tls_index * sizeof(void*);
50-
*module_offset = offset;
51-
return SUCCESS;
52-
}
53-
tls_mem++;
54-
offset += sizeof(void*);
55-
}
43+
size_t offset = (size_t)((char*)&_tsrm_ls_cache - (char*)tls_mem);
5644

5745
if (offset >= size) {
5846
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: offset >= size");
5947
}
6048

61-
return FAILURE;
49+
*module_index = _tls_index * sizeof(void*);
50+
*module_offset = offset;
51+
return SUCCESS;
6252
}

‎ext/opcache/jit/tls/zend_jit_tls_x86_64.c‎

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,9 @@ zend_result zend_jit_resolve_tsrm_ls_cache_offsets(
166166

167167
/*
168168
* 64 48 8b 04 25 00 00 00 00 movq %fs:0x0,%rax
169-
* 48 8d 80 f8 ff ff ff leaq -0x8(%rax),%rax
169+
* 48 8d 80 f8 ff ff ff leaq -0x8(%rax),%rax (Local Exec)
170+
* or
171+
* 48 03 05 xx xx xx xx addq any(%rip),%rax (Initial Exec)
170172
*/
171173

172174
// movq %fs:0x0,%rax
@@ -177,20 +179,16 @@ zend_result zend_jit_resolve_tsrm_ls_cache_offsets(
177179
return FAILURE;
178180
}
179181

180-
// leaq any(%rax),$rax
181-
if (memcmp(&code[9], "\x48\x8d\x80", 3) != 0) {
182+
// leaq any(%rax),%rax or addq any(%rip),%rax
183+
if (memcmp(&code[9], "\x48\x8d\x80", 3) != 0
184+
&& memcmp(&code[9], "\x48\x03\x05", 3) != 0) {
182185
uint64_t bytes;
183-
memcpy(&bytes, &code[10], 8);
184-
zend_accel_error(ACCEL_LOG_DEBUG, "leaq insn does not match: 0x%016" PRIx64 "\n", bytes);
186+
memcpy(&bytes, &code[9], 8);
187+
zend_accel_error(ACCEL_LOG_DEBUG, "leaq/addq insn does not match: 0x%016" PRIx64 "\n", bytes);
185188
return FAILURE;
186189
}
187190

188-
/* Extract immediate values */
189-
190-
uintptr_t offset = (uintptr_t)(int32_t)(((uint32_t)code[15] << 24)
191-
| ((uint32_t)code[14] << 16)
192-
| ((uint32_t)code[13] << 8)
193-
| ((uint32_t)code[12]));
191+
uintptr_t offset = (uintptr_t)addr - (uintptr_t)thread_pointer;
194192

195193
if ((uintptr_t)&_tsrm_ls_cache - (uintptr_t)thread_pointer == offset) {
196194
*tcb_offset = offset;

0 commit comments

Comments
 (0)