@@ -170,6 +170,7 @@ ZEND_CHECK_STACK_DIRECTION
170170ZEND_CHECK_FLOAT_PRECISION
171171ZEND_DLSYM_CHECK
172172ZEND_CHECK_GLOBAL_REGISTER_VARIABLES
173+ ZEND_CHECK_PRESERVE_NONE
173174ZEND_CHECK_CPUID_COUNT
174175
175176AC_MSG_CHECKING ( [ whether to enable thread safety] )
@@ -464,3 +465,103 @@ AS_VAR_IF([ZEND_MAX_EXECUTION_TIMERS], [yes],
464465AC_MSG_CHECKING ( [ whether to enable Zend max execution timers] )
465466AC_MSG_RESULT ( [ $ZEND_MAX_EXECUTION_TIMERS] )
466467] )
468+
469+ dnl
470+ dnl ZEND_CHECK_PRESERVE_NONE
471+ dnl
472+ dnl Check if the preserve_none calling convention is supported and matches our
473+ dnl expectations.
474+ dnl
475+ AC_DEFUN ( [ ZEND_CHECK_PRESERVE_NONE] , [ dnl
476+ AC_CACHE_CHECK ( [ for preserve_none calling convention] ,
477+ [ php_cv_preverve_none] ,
478+ [ AC_RUN_IFELSE ( [ AC_LANG_SOURCE ( [ [
479+ #include <stdio.h>
480+ #include <stdint.h>
481+
482+ const char * const1 = "str1";
483+ const char * const2 = "str2";
484+ const char * const3 = "str3";
485+ uint64_t key = UINT64_C(0x9d7f71d2bd296364);
486+
487+ uintptr_t _a = 0;
488+ uintptr_t _b = 0;
489+
490+ uintptr_t __attribute__((preserve_none)) fun(uintptr_t a, uintptr_t b) {
491+ _a = a;
492+ _b = b;
493+ return (uintptr_t)const3;
494+ }
495+
496+ uintptr_t __attribute__((preserve_none)) test(void) {
497+ uintptr_t ret;
498+
499+ #if defined(__x86_64__)
500+ __asm__ __volatile__(
501+ /* XORing to make it unlikely the value exists in any other register */
502+ "movq %1, %%r12\n"
503+ "xorq %3, %%r12\n"
504+ "movq %2, %%r13\n"
505+ "xorq %3, %%r13\n"
506+ "xorq %%rax, %%rax\n"
507+ "call fun\n"
508+ : "=a" (ret)
509+ : "r" (const1), "r" (const2), "r" (key)
510+ : "r12", "r13"
511+ );
512+ #elif defined(__aarch64__)
513+ __asm__ __volatile__(
514+ /* XORing to make it unlikely the value exists in any other register */
515+ "eor x20, %1, %3\n"
516+ "eor x21, %2, %3\n"
517+ "eor x0, x0, x0\n"
518+ "bl fun\n"
519+ "mov %0, x0\n"
520+ : "=r" (ret)
521+ : "r" (const1), "r" (const2), "r" (key)
522+ : "x0", "x21", "x22", "x30"
523+ );
524+ #else
525+ # error
526+ #endif
527+
528+ return ret;
529+ }
530+
531+ int main(void) {
532+
533+ /* JIT is making the following expectations about preserve_none:
534+ * - The registers used for integer args 1 and 2
535+ * - The register used for a single integer return value
536+ *
537+ * We check these expectations here:
538+ */
539+
540+ uintptr_t ret = test();
541+
542+ if (_a != ((uintptr_t)const1 ^ key)) {
543+ fprintf(stderr, "arg1 mismatch\n");
544+ return 1;
545+ }
546+ if (_b != ((uintptr_t)const2 ^ key)) {
547+ fprintf(stderr, "arg2 mismatch\n");
548+ return 2;
549+ }
550+ if (ret != (uintptr_t)const3) {
551+ fprintf(stderr, "ret mismatch\n");
552+ return 3;
553+ }
554+
555+ fprintf(stderr, "OK\n");
556+
557+ return 0;
558+ }] ] ) ] ,
559+ [ php_cv_preserve_none=yes] ,
560+ [ php_cv_preserve_none=no] ,
561+ [ php_cv_preserve_none=no] )
562+ ] )
563+ AS_VAR_IF ( [ php_cv_preserve_none] , [ yes] , [
564+ AC_DEFINE ( [ HAVE_PRESERVE_NONE] , [ 1] ,
565+ [ Define to 1 if you have preserve_none support.] )
566+ ] )
567+ ] )
0 commit comments