@@ -427,3 +427,115 @@ index 6c91e2d292..86978f4671 100644
427427- -
4284282.41.0
429429
430+ From dccccf8b3910e69aa236ac1f47e7f16ad34a003d Mon Sep 17 00:00:00 2001
431+ 432+ Date: Sun, 14 Sep 2025 00:55:51 -0700
433+ Subject: [PATCH] tcg: new JIT workaround for iOS 26
434+
435+ We map the JIT region originally as RX and also mirror map it
436+ as RX. Then we use attached debugger to flag the mirror
437+ mapping as debugger owned. Finally, we change the original map
438+ to RW which should not invalidate code-signing as the mirror
439+ is debugger owned.
440+
441+ Thanks to @JJTech0130 for this workaround.
442+ ---
443+ tcg/region.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++--
444+ 1 file changed, 67 insertions(+), 2 deletions(-)
445+
446+ diff --git a/tcg/region.c b/tcg/region.c
447+ index 70996b5ab1..48def8311f 100644
448+ --- a/tcg/region.c
449+ +++ b/tcg/region.c
450+ @@ -623,14 +623,57 @@ extern kern_return_t mach_vm_remap(vm_map_t target_task,
451+ vm_prot_t *max_protection,
452+ vm_inherit_t inheritance);
453+
454+ + #include <TargetConditionals.h>
455+ + #if defined(TARGET_OS_IPHONE) && !defined(TARGET_OS_SIMULATOR)
456+ + #include <sys/types.h>
457+ + #include <sys/sysctl.h>
458+ + static int is_debugger_attached(void)
459+ + {
460+ + int mib[4];
461+ + struct kinfo_proc info;
462+ + size_t size;
463+ +
464+ + info.kp_proc.p_flag = 0;
465+ +
466+ + /* Initialize MIB for sysctl call */
467+ + mib[0] = CTL_KERN;
468+ + mib[1] = KERN_PROC;
469+ + mib[2] = KERN_PROC_PID;
470+ + mib[3] = getpid();
471+ +
472+ + size = sizeof(info);
473+ +
474+ + if (sysctl(mib, 4, &info, &size, NULL, 0) == -1) {
475+ + return 0; // sysctl failed, be conservative
476+ + }
477+ +
478+ + /* P_TRACED means the process is being debugged */
479+ + return (info.kp_proc.p_flag & P_TRACED) != 0;
480+ + }
481+ +
482+ + static void break_prepare_jit_region(mach_vm_address_t addr, size_t len)
483+ + {
484+ + asm ("mov x0, %0\n"
485+ + "mov x1, %1\n"
486+ + "brk #0x69" :: "r" (addr), "r" (len) : "x0", "x1");
487+ + }
488+ + #endif
489+ +
490+ static int alloc_code_gen_buffer_splitwx_vmremap(size_t size, Error **errp)
491+ {
492+ kern_return_t ret;
493+ mach_vm_address_t buf_rw, buf_rx;
494+ vm_prot_t cur_prot, max_prot;
495+ + int orig_prot = PROT_READ | PROT_WRITE;
496+
497+ - /* Map the read-write portion via normal anon memory. */
498+ - if (!alloc_code_gen_buffer_anon(size, PROT_READ | PROT_WRITE,
499+ + #if defined(TARGET_OS_IPHONE) && !defined(TARGET_OS_SIMULATOR)
500+ + /* iOS 26 with TXM requires new workaround*/
501+ + if (__builtin_available(iOS 26, visionOS 26, watchOS 26, tvOS 26, *)) {
502+ + orig_prot = PROT_READ | PROT_EXEC;
503+ + }
504+ + #endif
505+ +
506+ + if (!alloc_code_gen_buffer_anon(size, orig_prot,
507+ MAP_PRIVATE | MAP_ANONYMOUS, errp)) {
508+ return -1;
509+ }
510+ @@ -662,6 +705,28 @@ static int alloc_code_gen_buffer_splitwx_vmremap(size_t size, Error **errp)
511+ return -1;
512+ }
513+
514+ + #if defined(TARGET_OS_IPHONE) && !defined(TARGET_OS_SIMULATOR)
515+ + if (__builtin_available(iOS 26, visionOS 26, watchOS 26, tvOS 26, *)) {
516+ + if (!is_debugger_attached()) {
517+ + error_setg(errp, "debugger must be attached for jit workaround");
518+ + munmap((void *)buf_rx, size);
519+ + munmap((void *)buf_rw, size);
520+ + return -1;
521+ + }
522+ +
523+ + /* give let debugger modify the page permission */
524+ + break_prepare_jit_region(buf_rx, size);
525+ +
526+ + /* finally mark the read-write portion as RW */
527+ + if (mprotect((void *)buf_rw, size, PROT_READ | PROT_WRITE) != 0) {
528+ + error_setg_errno(errp, errno, "mprotect for jit splitwx (rw)");
529+ + munmap((void *)buf_rx, size);
530+ + munmap((void *)buf_rw, size);
531+ + return -1;
532+ + }
533+ + }
534+ + #endif
535+ +
536+ tcg_splitwx_diff = buf_rx - buf_rw;
537+ return PROT_READ | PROT_WRITE;
538+ }
539+ - -
540+ 2.41.0
541+
0 commit comments