From 7c906d68502d3f1f31e46754b85508f93856f9d6 Mon Sep 17 00:00:00 2001 From: Marc Date: Wed, 28 Oct 2026 18:21:35 +0100 Subject: [PATCH] JIT: recognize initial-exec TLS relaxation See php#23227 --- ext/opcache/jit/tls/testing/test.sh | 8 ++--- ext/opcache/jit/tls/testing/user.c | 2 +- ext/opcache/jit/tls/zend_jit_tls_aarch64.c | 39 ++++++++++++---------- ext/opcache/jit/tls/zend_jit_tls_x86_64.c | 20 +++++------ 4 files changed, 36 insertions(+), 33 deletions(-) diff --git a/ext/opcache/jit/tls/testing/test.sh b/ext/opcache/jit/tls/testing/test.sh index c6b003caafdd..c49e0439a1c3 100755 --- a/ext/opcache/jit/tls/testing/test.sh +++ b/ext/opcache/jit/tls/testing/test.sh @@ -136,8 +136,8 @@ dl_def_static_user_no_surplus() { rm -f main - $CC $CFLAGS -ggdb3 -fPIC -o tls.o -c $TLSC - $CC $CFLAGS -ggdb3 -fPIC -o user.o -c user.c + $CC $CFLAGS -DTSRM_TLS_MODEL_USE_DEFAULT -ggdb3 -fPIC -o tls.o -c $TLSC + $CC $CFLAGS -DTSRM_TLS_MODEL_USE_DEFAULT -ggdb3 -fPIC -o user.o -c user.c $CC $CFLAGS -DNO_SURPLUS -ggdb3 -fPIC -o def.o -c def.c $CC $CFLAGS $LDFLAGS -shared -o libdef.so def.o user.o tls.o @@ -151,8 +151,8 @@ dl_def_shared_user_no_surplus() { rm -f main - $CC $CFLAGS -ggdb3 -fPIC -o tls.o -c $TLSC - $CC $CFLAGS -ggdb3 -fPIC -o user.o -c user.c + $CC $CFLAGS -DTSRM_TLS_MODEL_USE_DEFAULT -ggdb3 -fPIC -o tls.o -c $TLSC + $CC $CFLAGS -DTSRM_TLS_MODEL_USE_DEFAULT -ggdb3 -fPIC -o user.o -c user.c $CC $CFLAGS $LDFLAGS -shared -o libuser.so user.o tls.o $CC $CFLAGS -DNO_SURPLUS -ggdb3 -fPIC -o def.o -c def.c diff --git a/ext/opcache/jit/tls/testing/user.c b/ext/opcache/jit/tls/testing/user.c index c27e608f3f4b..19e9f06c0806 100644 --- a/ext/opcache/jit/tls/testing/user.c +++ b/ext/opcache/jit/tls/testing/user.c @@ -3,7 +3,7 @@ #include "../zend_jit_tls.h" -extern __thread void* _tsrm_ls_cache; +TSRMLS_MAIN_CACHE_EXTERN() int test(void) { diff --git a/ext/opcache/jit/tls/zend_jit_tls_aarch64.c b/ext/opcache/jit/tls/zend_jit_tls_aarch64.c index 80d19090312f..d3f0467648c6 100644 --- a/ext/opcache/jit/tls/zend_jit_tls_aarch64.c +++ b/ext/opcache/jit/tls/zend_jit_tls_aarch64.c @@ -192,18 +192,6 @@ zend_result zend_jit_resolve_tsrm_ls_cache_offsets( /* Code was changed by the linker. Check if we recognize the updated code */ - // movz x0, #0, lsl #16 - if ((insn[0] & ~AARCH64_MOVZ_IMM_MASK) != 0xd2a00000) { - zend_accel_error(ACCEL_LOG_DEBUG, "movz insn does not match: 0x%08" PRIx32 "\n", insn[0]); - return FAILURE; - } - - // movk x0, #0x10 - if ((insn[1] & ~AARCH64_MOVK_IMM_MASK) != 0xf2800000) { - zend_accel_error(ACCEL_LOG_DEBUG, "movk insn does not match: 0x%08" PRIx32 "\n", insn[1]); - return FAILURE; - } - // nop for (int i = 0; i < 2; i++) { if (insn[2+i] != AARCH64_NOP) { @@ -212,12 +200,29 @@ zend_result zend_jit_resolve_tsrm_ls_cache_offsets( } } - /* Extract immediate values */ + if ((insn[0] & ~AARCH64_ADRP_IMM_MASK) == 0x90000000) { + /* initial-exec */ + // ldr x0, [x0, #any] + if ((insn[1] & ~AARCH64_LDR_UNSIGNED_IMM_MASK) != 0xf9400000) { + zend_accel_error(ACCEL_LOG_DEBUG, "ldr insn does not match: 0x%08" PRIx32 "\n", insn[1]); + return FAILURE; + } + } else { + /* local-exec */ + // movz x0, #0, lsl #16 + if ((insn[0] & ~AARCH64_MOVZ_IMM_MASK) != 0xd2a00000) { + zend_accel_error(ACCEL_LOG_DEBUG, "movz insn does not match: 0x%08" PRIx32 "\n", insn[0]); + return FAILURE; + } + + // movk x0, #0x10 + if ((insn[1] & ~AARCH64_MOVK_IMM_MASK) != 0xf2800000) { + zend_accel_error(ACCEL_LOG_DEBUG, "movk insn does not match: 0x%08" PRIx32 "\n", insn[1]); + return FAILURE; + } + } - uint64_t movz_imm = (insn[0] & AARCH64_MOVZ_IMM_MASK) >> 5; - uint64_t movz_shift = (((insn[0] & AARCH64_MOVZ_HW_MASK) >> 21) << 4); - uint64_t movk_imm = (insn[1] & AARCH64_MOVK_IMM_MASK) >> 5; - uint64_t offset = (movz_imm << movz_shift) | movk_imm; + uintptr_t offset = (uintptr_t)addr - (uintptr_t)thread_pointer; if ((uintptr_t)&_tsrm_ls_cache - (uintptr_t)thread_pointer == offset) { zend_accel_error(ACCEL_LOG_DEBUG, "static tls at offset %" PRIxPTR " from thread pointer (inferred from code)\n", offset); diff --git a/ext/opcache/jit/tls/zend_jit_tls_x86_64.c b/ext/opcache/jit/tls/zend_jit_tls_x86_64.c index f3495505c524..c67d72e33713 100644 --- a/ext/opcache/jit/tls/zend_jit_tls_x86_64.c +++ b/ext/opcache/jit/tls/zend_jit_tls_x86_64.c @@ -166,7 +166,9 @@ zend_result zend_jit_resolve_tsrm_ls_cache_offsets( /* * 64 48 8b 04 25 00 00 00 00 movq %fs:0x0,%rax - * 48 8d 80 f8 ff ff ff leaq -0x8(%rax),%rax + * 48 8d 80 f8 ff ff ff leaq -0x8(%rax),%rax (Local Exec) + * or + * 48 03 05 xx xx xx xx addq any(%rip),%rax (Initial Exec) */ // movq %fs:0x0,%rax @@ -177,20 +179,16 @@ zend_result zend_jit_resolve_tsrm_ls_cache_offsets( return FAILURE; } - // leaq any(%rax),$rax - if (memcmp(&code[9], "\x48\x8d\x80", 3) != 0) { + // leaq any(%rax),%rax or addq any(%rip),%rax + if (memcmp(&code[9], "\x48\x8d\x80", 3) != 0 + && memcmp(&code[9], "\x48\x03\x05", 3) != 0) { uint64_t bytes; - memcpy(&bytes, &code[10], 8); - zend_accel_error(ACCEL_LOG_DEBUG, "leaq insn does not match: 0x%016" PRIx64 "\n", bytes); + memcpy(&bytes, &code[9], 8); + zend_accel_error(ACCEL_LOG_DEBUG, "leaq/addq insn does not match: 0x%016" PRIx64 "\n", bytes); return FAILURE; } - /* Extract immediate values */ - - uintptr_t offset = (uintptr_t)(int32_t)(((uint32_t)code[15] << 24) - | ((uint32_t)code[14] << 16) - | ((uint32_t)code[13] << 8) - | ((uint32_t)code[12])); + uintptr_t offset = (uintptr_t)addr - (uintptr_t)thread_pointer; if ((uintptr_t)&_tsrm_ls_cache - (uintptr_t)thread_pointer == offset) { *tcb_offset = offset;