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