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