mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00

We use linker relocations to fetch the TLS index and offset of _tsrm_ls_cache. When building Opcache statically, linkers may attempt to optimize that into a more efficient code sequence (relaxing from "General Dynamic" to "Local Exec" model [1]). Unfortunately, linkers will fail, rather than ignore our relocations, when they don't recognize the exact code sequence they are expecting. This results in errors as reported by GH-15074: TLS transition from R_X86_64_TLSGD to R_X86_64_GOTTPOFF against `_tsrm_ls_cache' at 0x12fc3 in section `.text' failed" Here I take a different approach: * Emit the exact full code sequence expected by linkers * Extract the TLS index/offset by inspecting the linked ASM code, rather than executing it (execution would give us the thread-local address). * We detect when the code was relaxed, in which case we can extract the TCB offset instead. * This is done in a conservative way so that if the linker did something we didn't expect, we fallback to a safer (but slower) mechanism. One additional benefit of that is we are now able to use the Local Exec model in more cases, in JIT'ed code. This makes non-glibc builds faster in these cases. Closes GH-18939. Related RFC: https://wiki.php.net/rfc/make_opcache_required. [1] https://www.akkadia.org/drepper/tls.pdf
82 lines
2.3 KiB
C
82 lines
2.3 KiB
C
/*
|
|
* +----------------------------------------------------------------------+
|
|
* | Zend JIT |
|
|
* +----------------------------------------------------------------------+
|
|
* | Copyright (c) The PHP Group |
|
|
* +----------------------------------------------------------------------+
|
|
* | This source file is subject to version 3.01 of the PHP license, |
|
|
* | that is bundled with this package in the file LICENSE, and is |
|
|
* | available through the world-wide-web at the following url: |
|
|
* | https://www.php.net/license/3_01.txt |
|
|
* | If you did not receive a copy of the PHP license and are unable to |
|
|
* | obtain it through the world-wide-web, please send a note to |
|
|
* | license@php.net so we can mail you a copy immediately. |
|
|
* +----------------------------------------------------------------------+
|
|
* | Authors: Dmitry Stogov <dmitry@php.net> |
|
|
* +----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#include "Zend/zend_portability.h"
|
|
#include "Zend/zend_types.h"
|
|
#include "TSRM/TSRM.h"
|
|
#include "zend_accelerator_debug.h"
|
|
|
|
#include <stdint.h>
|
|
#include <unistd.h>
|
|
|
|
TSRMLS_CACHE_EXTERN();
|
|
|
|
zend_result zend_jit_resolve_tsrm_ls_cache_offsets(
|
|
size_t *tcb_offset,
|
|
size_t *module_index,
|
|
size_t *module_offset
|
|
) {
|
|
*tcb_offset = tsrm_get_ls_cache_tcb_offset();
|
|
if (*tcb_offset != 0) {
|
|
return SUCCESS;
|
|
}
|
|
|
|
#if defined(__x86_64__)
|
|
size_t *ti;
|
|
__asm__ __volatile__(
|
|
"leaq __tsrm_ls_cache(%%rip),%0"
|
|
: "=r" (ti));
|
|
*module_offset = ti[2];
|
|
*module_index = ti[1] * 8;
|
|
|
|
return SUCCESS;
|
|
#endif
|
|
|
|
return FAILURE;
|
|
}
|
|
|
|
/* Used for testing */
|
|
void *zend_jit_tsrm_ls_cache_address(
|
|
size_t tcb_offset,
|
|
size_t module_index,
|
|
size_t module_offset
|
|
) {
|
|
|
|
#if defined(__x86_64__)
|
|
if (tcb_offset) {
|
|
char *addr;
|
|
__asm__ __volatile__(
|
|
"movq %%gs:(%1), %0\n"
|
|
: "=r" (addr)
|
|
: "r" (tcb_offset)
|
|
);
|
|
return addr;
|
|
}
|
|
if (module_index != (size_t)-1 && module_offset != (size_t)-1) {
|
|
char *base;
|
|
__asm__ __volatile__(
|
|
"movq %%gs:(%1), %0\n"
|
|
: "=r" (base)
|
|
: "r" (module_index)
|
|
);
|
|
return base + module_offset;
|
|
}
|
|
#endif
|
|
|
|
return NULL;
|
|
}
|