All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/10] iOS and Apple Silicon host support
@ 2020-10-12 23:29 Joelle van Dyne
  2020-10-12 23:29 ` [PATCH 01/10] configure: option to disable host block devices Joelle van Dyne
                   ` (10 more replies)
  0 siblings, 11 replies; 47+ messages in thread
From: Joelle van Dyne @ 2020-10-12 23:29 UTC (permalink / raw)
  To: qemu-devel

These set of changes brings QEMU TCG to iOS devices and future Apple Silicon
devices. They were originally developed last year and have been working in the
UTM app. Recently, we ported the changes to master, re-wrote a lot of the build
script changes for meson, and broke up the patches into more distinct units.

A summary of the changes:

* `CONFIG_IOS` and `CONFIG_IOS_JIT` defined when building for iOS and
  iOS specific changes (as well as unsupported code) are gated behind it.
* slirp updated to support DNS resolving using libresolv; a separate patch will
  be submitted to the project. To allow for builds to succeed, the .gitmodule
  is temporarily changed. We're not entirely sure how cross-project patches
  should be handled here.
* A new dependency, libucontext is added since iOS does not have native ucontext
  and broken support for sigaltstack. libucontext is available as a new option
  for coroutine backend.
* On stock iOS devices, there is a workaround for running JIT code without
  any special entitlement. It requires the JIT region to be mirror mapped with
  one region RW and another one RX. To support this style of JIT, TCG is changed
  to support writing to a different code_ptr. These changes are gated by the
  `CONFIG_IOS_JIT`.
* For (recent) jailbroken iOS devices as well as upcoming Apple Silicon devices,
  there are new rules for applications supporting JIT (with the proper
  entitlement). These rules are implemented as well.
* An option to build QEMU as a shared library is added because iOS does not
  support fork().

These patches are also on Github:
  https://github.com/utmapp/qemu/tree/ios-support-master

-j

osy (10):
  configure: option to disable host block devices
  configure: cross-compiling without cross_prefix
  qemu: add support for iOS host
  meson: option to build as shared library
  slirp: update for iOS resolv fix
  coroutine: add libucontext as external library
  tcg: implement bulletproof JIT
  tcg: mirror mapping RWX pages for iOS optional
  tcg: support JIT on Apple Silicon
  block: check availablity for preadv/pwritev on mac

 .gitmodules                  |   5 +-
 accel/tcg/cpu-exec-common.c  |   2 +
 accel/tcg/cpu-exec.c         |   9 +-
 accel/tcg/tcg-all.c          |  27 +++++-
 accel/tcg/translate-all.c    | 169 ++++++++++++++++++++++++++++++++---
 block.c                      |   2 +-
 block/file-posix.c           |  50 ++++++++---
 bsd-user/main.c              |   2 +-
 configure                    | 118 ++++++++++++++++++++++--
 docs/devel/ios.rst           |  40 +++++++++
 include/exec/exec-all.h      |  10 +++
 include/sysemu/tcg.h         |   2 +-
 include/tcg/tcg-apple-jit.h  |  85 ++++++++++++++++++
 include/tcg/tcg.h            |  21 ++++-
 libucontext                  |   1 +
 linux-user/main.c            |   2 +-
 meson.build                  |  74 +++++++++++++--
 meson_options.txt            |   4 +
 net/slirp.c                  |  16 ++--
 qemu-options.hx              |  11 +++
 qga/commands-posix.c         |   6 ++
 slirp                        |   2 +-
 target/arm/arm-semi.c        |   2 +
 target/m68k/m68k-semi.c      |   2 +
 target/nios2/nios2-semi.c    |   2 +
 tcg/aarch64/tcg-target.c.inc |  48 ++++++----
 tcg/aarch64/tcg-target.h     |  23 ++++-
 tcg/arm/tcg-target.c.inc     |  33 ++++---
 tcg/arm/tcg-target.h         |   9 +-
 tcg/i386/tcg-target.c.inc    |  28 +++---
 tcg/i386/tcg-target.h        |  24 ++++-
 tcg/mips/tcg-target.c.inc    |  64 +++++++------
 tcg/mips/tcg-target.h        |   8 +-
 tcg/ppc/tcg-target.c.inc     |  55 +++++++-----
 tcg/ppc/tcg-target.h         |   8 +-
 tcg/riscv/tcg-target.c.inc   |  51 ++++++-----
 tcg/riscv/tcg-target.h       |   9 +-
 tcg/s390/tcg-target.c.inc    |  25 +++---
 tcg/s390/tcg-target.h        |  13 ++-
 tcg/sparc/tcg-target.c.inc   |  33 ++++---
 tcg/sparc/tcg-target.h       |   8 +-
 tcg/tcg-ldst.c.inc           |   2 +-
 tcg/tcg-pool.c.inc           |   9 +-
 tcg/tcg.c                    |  64 ++++++++-----
 tcg/tci/tcg-target.c.inc     |   8 +-
 tcg/tci/tcg-target.h         |   9 +-
 tests/qtest/meson.build      |   7 +-
 util/coroutine-ucontext.c    |   9 ++
 48 files changed, 965 insertions(+), 246 deletions(-)
 create mode 100644 docs/devel/ios.rst
 create mode 100644 include/tcg/tcg-apple-jit.h
 create mode 160000 libucontext

-- 
2.24.3 (Apple Git-128)



^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH 01/10] configure: option to disable host block devices
  2020-10-12 23:29 [PATCH 00/10] iOS and Apple Silicon host support Joelle van Dyne
@ 2020-10-12 23:29 ` Joelle van Dyne
  2020-10-12 23:29 ` [PATCH 02/10] configure: cross-compiling without cross_prefix Joelle van Dyne
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 47+ messages in thread
From: Joelle van Dyne @ 2020-10-12 23:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Joelle van Dyne, open list:raw, Max Reitz

From: osy <osy86@users.noreply.github.com>

Some hosts (iOS) have a sandboxed filesystem and do not provide low-level
APIs for interfacing with host block devices.

Signed-off-by: Joelle van Dyne <j@getutm.app>
---
 block/file-posix.c | 8 +++++++-
 configure          | 4 ++++
 meson.build        | 1 +
 3 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/block/file-posix.c b/block/file-posix.c
index c63926d592..52f7c20525 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -41,7 +41,7 @@
 #include "scsi/pr-manager.h"
 #include "scsi/constants.h"
 
-#if defined(__APPLE__) && (__MACH__)
+#if defined(CONFIG_HOST_BLOCK_DEVICE) && defined(__APPLE__) && (__MACH__)
 #include <paths.h>
 #include <sys/param.h>
 #include <IOKit/IOKitLib.h>
@@ -3247,6 +3247,8 @@ BlockDriver bdrv_file = {
 /***********************************************/
 /* host device */
 
+#if defined(CONFIG_HOST_BLOCK_DEVICE)
+
 #if defined(__APPLE__) && defined(__MACH__)
 static kern_return_t GetBSDPath(io_iterator_t mediaIterator, char *bsdPath,
                                 CFIndex maxPathSize, int flags);
@@ -3872,6 +3874,8 @@ static BlockDriver bdrv_host_cdrom = {
 };
 #endif /* __FreeBSD__ */
 
+#endif /* CONFIG_HOST_BLOCK_DEVICE */
+
 static void bdrv_file_init(void)
 {
     /*
@@ -3879,6 +3883,7 @@ static void bdrv_file_init(void)
      * registered last will get probed first.
      */
     bdrv_register(&bdrv_file);
+#if defined(CONFIG_HOST_BLOCK_DEVICE)
     bdrv_register(&bdrv_host_device);
 #ifdef __linux__
     bdrv_register(&bdrv_host_cdrom);
@@ -3886,6 +3891,7 @@ static void bdrv_file_init(void)
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
     bdrv_register(&bdrv_host_cdrom);
 #endif
+#endif /* CONFIG_HOST_BLOCK_DEVICE */
 }
 
 block_init(bdrv_file_init);
diff --git a/configure b/configure
index b553288c5e..3c63879750 100755
--- a/configure
+++ b/configure
@@ -446,6 +446,7 @@ meson=""
 ninja=""
 skip_meson=no
 gettext=""
+host_block_device_support="yes"
 
 bogus_os="no"
 malloc_trim="auto"
@@ -6098,6 +6099,9 @@ if test "$default_devices" = "yes" ; then
 else
   echo "CONFIG_MINIKCONF_MODE=--allnoconfig" >> $config_host_mak
 fi
+if test "$host_block_device_support" = "yes" ; then
+  echo "CONFIG_HOST_BLOCK_DEVICE=y" >> $config_host_mak
+fi
 if test "$debug_tcg" = "yes" ; then
   echo "CONFIG_DEBUG_TCG=y" >> $config_host_mak
 fi
diff --git a/meson.build b/meson.build
index 17c89c87c6..5d3a47784b 100644
--- a/meson.build
+++ b/meson.build
@@ -1947,6 +1947,7 @@ summary_info += {'vvfat support':     config_host.has_key('CONFIG_VVFAT')}
 summary_info += {'qed support':       config_host.has_key('CONFIG_QED')}
 summary_info += {'parallels support': config_host.has_key('CONFIG_PARALLELS')}
 summary_info += {'sheepdog support':  config_host.has_key('CONFIG_SHEEPDOG')}
+summary_info += {'host block dev support': config_host.has_key('CONFIG_HOST_BLOCK_DEVICE')}
 summary_info += {'capstone':          capstone_opt == 'disabled' ? false : capstone_opt}
 summary_info += {'libpmem support':   config_host.has_key('CONFIG_LIBPMEM')}
 summary_info += {'libdaxctl support': config_host.has_key('CONFIG_LIBDAXCTL')}
-- 
2.24.3 (Apple Git-128)



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 02/10] configure: cross-compiling without cross_prefix
  2020-10-12 23:29 [PATCH 00/10] iOS and Apple Silicon host support Joelle van Dyne
  2020-10-12 23:29 ` [PATCH 01/10] configure: option to disable host block devices Joelle van Dyne
@ 2020-10-12 23:29 ` Joelle van Dyne
  2020-10-12 23:29 ` [PATCH 03/10] qemu: add support for iOS host Joelle van Dyne
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 47+ messages in thread
From: Joelle van Dyne @ 2020-10-12 23:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: Joelle van Dyne

From: osy <osy86@users.noreply.github.com>

The iOS toolchain does not use the host prefix naming convention. We add a
new option `--enable-cross-compile` that forces cross-compile even without
a cross_prefix.

Signed-off-by: Joelle van Dyne <j@getutm.app>
---
 configure | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/configure b/configure
index 3c63879750..46d5db63e8 100755
--- a/configure
+++ b/configure
@@ -234,6 +234,7 @@ cpu=""
 iasl="iasl"
 interp_prefix="/usr/gnemul/qemu-%M"
 static="no"
+cross_compile="no"
 cross_prefix=""
 audio_drv_list=""
 block_drv_rw_whitelist=""
@@ -456,6 +457,11 @@ for opt do
   optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)')
   case "$opt" in
   --cross-prefix=*) cross_prefix="$optarg"
+                    cross_compile="yes"
+  ;;
+  --enable-cross-compile) cross_compile="yes"
+  ;;
+  --disable-cross-compile) cross_compile="no"
   ;;
   --cc=*) CC="$optarg"
   ;;
@@ -878,6 +884,10 @@ for opt do
   ;;
   --cross-prefix=*)
   ;;
+  --enable-cross-compile)
+  ;;
+  --disable-cross-compile)
+  ;;
   --cc=*)
   ;;
   --host-cc=*) host_cc="$optarg"
@@ -1687,6 +1697,7 @@ Advanced options (experts only):
   --efi-aarch64=PATH       PATH of efi file to use for aarch64 VMs.
   --with-suffix=SUFFIX     suffix for QEMU data inside datadir/libdir/sysconfdir/docdir [$qemu_suffix]
   --with-pkgversion=VERS   use specified string as sub-version of the package
+  --enable-cross-compile   enable cross compiling (set automatically if $cross_prefix is set)
   --enable-debug           enable common debug build options
   --enable-sanitizers      enable default sanitizers
   --enable-tsan            enable thread sanitizer
@@ -7164,7 +7175,7 @@ if has $sdl2_config; then
 fi
 echo "strip = [$(meson_quote $strip)]" >> $cross
 echo "windres = [$(meson_quote $windres)]" >> $cross
-if test -n "$cross_prefix"; then
+if test "$cross_compile" = "yes"; then
     cross_arg="--cross-file config-meson.cross"
     echo "[host_machine]" >> $cross
     if test "$mingw32" = "yes" ; then
-- 
2.24.3 (Apple Git-128)



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 03/10] qemu: add support for iOS host
  2020-10-12 23:29 [PATCH 00/10] iOS and Apple Silicon host support Joelle van Dyne
  2020-10-12 23:29 ` [PATCH 01/10] configure: option to disable host block devices Joelle van Dyne
  2020-10-12 23:29 ` [PATCH 02/10] configure: cross-compiling without cross_prefix Joelle van Dyne
@ 2020-10-12 23:29 ` Joelle van Dyne
  2020-10-12 23:29 ` [PATCH 04/10] meson: option to build as shared library Joelle van Dyne
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 47+ messages in thread
From: Joelle van Dyne @ 2020-10-12 23:29 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Peter Maydell, Thomas Huth, Marek Vasut,
	open list:Block layer core, Jason Wang, Chris Wulff,
	Richard Henderson, Michael Roth, Max Reitz,
	open list:ARM TCG CPUs, Joelle van Dyne, Paolo Bonzini,
	Samuel Thibault, Laurent Vivier

From: osy <osy86@users.noreply.github.com>

This introduces support for building for iOS hosts. When the correct Xcode
toolchain is used, iOS host will be detected automatically.

block: disable features not supported by iOS sandbox
slirp: disable SMB features for iOS
target: disable system() calls for iOS
tcg: use sys_icache_invalidate() instead of GCC builtin for iOS
tests: disable tests on iOS which uses system()
Signed-off-by: Joelle van Dyne <j@getutm.app>
---
 block.c                   |  2 +-
 block/file-posix.c        | 30 ++++++++++++++++-----------
 configure                 | 43 ++++++++++++++++++++++++++++++++++++++-
 meson.build               |  2 +-
 net/slirp.c               | 16 +++++++--------
 qga/commands-posix.c      |  6 ++++++
 target/arm/arm-semi.c     |  2 ++
 target/m68k/m68k-semi.c   |  2 ++
 target/nios2/nios2-semi.c |  2 ++
 tcg/aarch64/tcg-target.h  | 10 +++++++++
 tests/qtest/meson.build   |  7 +++----
 11 files changed, 95 insertions(+), 27 deletions(-)

diff --git a/block.c b/block.c
index 430edf79bb..5d49869d02 100644
--- a/block.c
+++ b/block.c
@@ -53,7 +53,7 @@
 #ifdef CONFIG_BSD
 #include <sys/ioctl.h>
 #include <sys/queue.h>
-#ifndef __DragonFly__
+#if !defined(__DragonFly__) && !defined(CONFIG_IOS)
 #include <sys/disk.h>
 #endif
 #endif
diff --git a/block/file-posix.c b/block/file-posix.c
index 52f7c20525..cdc73b5f1d 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -181,7 +181,16 @@ typedef struct BDRVRawReopenState {
     bool check_cache_dropped;
 } BDRVRawReopenState;
 
-static int fd_open(BlockDriverState *bs);
+static int fd_open(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+
+    /* this is just to ensure s->fd is sane (its called by io ops) */
+    if (s->fd >= 0)
+        return 0;
+    return -EIO;
+}
+
 static int64_t raw_getlength(BlockDriverState *bs);
 
 typedef struct RawPosixAIOData {
@@ -252,6 +261,12 @@ static int raw_normalize_devicepath(const char **filename, Error **errp)
 }
 #endif
 
+#if defined(CONFIG_IOS)
+static int probe_logical_blocksize(int fd, unsigned int *sector_size_p)
+{
+    return -ENOTSUP; /* not supported on iOS */
+}
+#else /* CONFIG_IOS */
 /*
  * Get logical block size via ioctl. On success store it in @sector_size_p.
  */
@@ -284,6 +299,7 @@ static int probe_logical_blocksize(int fd, unsigned int *sector_size_p)
 
     return success ? 0 : -errno;
 }
+#endif /* !CONFIG_IOS */
 
 /**
  * Get physical block size of @fd.
@@ -2306,7 +2322,7 @@ again:
         }
         if (size == 0)
 #endif
-#if defined(__APPLE__) && defined(__MACH__)
+#if !defined(CONFIG_IOS) && defined(__APPLE__) && defined(__MACH__)
         {
             uint64_t sectors = 0;
             uint32_t sector_size = 0;
@@ -3541,16 +3557,6 @@ hdev_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
 }
 #endif /* linux */
 
-static int fd_open(BlockDriverState *bs)
-{
-    BDRVRawState *s = bs->opaque;
-
-    /* this is just to ensure s->fd is sane (its called by io ops) */
-    if (s->fd >= 0)
-        return 0;
-    return -EIO;
-}
-
 static coroutine_fn int
 hdev_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes)
 {
diff --git a/configure b/configure
index 46d5db63e8..c474d7c221 100755
--- a/configure
+++ b/configure
@@ -561,6 +561,19 @@ EOF
   compile_object
 }
 
+check_ios() {
+  cat > $TMPC <<EOF
+#ifdef __APPLE__
+#import "TargetConditionals.h"
+#if !TARGET_OS_IPHONE
+#error TARGET_OS_IPHONE not true
+#endif
+#endif
+int main(void) { return 0; }
+EOF
+  compile_object
+}
+
 check_include() {
 cat > $TMPC <<EOF
 #include <$1>
@@ -603,7 +616,11 @@ elif check_define __DragonFly__ ; then
 elif check_define __NetBSD__; then
   targetos='NetBSD'
 elif check_define __APPLE__; then
-  targetos='Darwin'
+  if check_ios ; then
+    targetos='iOS'
+  else
+    targetos='Darwin'
+  fi
 else
   # This is a fatal error, but don't report it yet, because we
   # might be going to just print the --help text, or it might
@@ -780,6 +797,22 @@ Darwin)
   # won't work when we're compiling with gcc as a C compiler.
   QEMU_CFLAGS="-DOS_OBJECT_USE_OBJC=0 $QEMU_CFLAGS"
 ;;
+iOS)
+  bsd="yes"
+  darwin="yes"
+  ios="yes"
+  if [ "$cpu" = "x86_64" ] ; then
+    QEMU_CFLAGS="-arch x86_64 $QEMU_CFLAGS"
+    QEMU_LDFLAGS="-arch x86_64 $QEMU_LDFLAGS"
+  fi
+  host_block_device_support="no"
+  audio_drv_list=""
+  audio_possible_drivers=""
+  QEMU_LDFLAGS="-framework CoreFoundation $QEMU_LDFLAGS"
+  # Disable attempts to use ObjectiveC features in os/object.h since they
+  # won't work when we're compiling with gcc as a C compiler.
+  QEMU_CFLAGS="-DOS_OBJECT_USE_OBJC=0 $QEMU_CFLAGS"
+;;
 SunOS)
   solaris="yes"
   make="${MAKE-gmake}"
@@ -6162,6 +6195,10 @@ if test "$darwin" = "yes" ; then
   echo "CONFIG_DARWIN=y" >> $config_host_mak
 fi
 
+if test "$ios" = "yes" ; then
+  echo "CONFIG_IOS=y" >> $config_host_mak
+fi
+
 if test "$solaris" = "yes" ; then
   echo "CONFIG_SOLARIS=y" >> $config_host_mak
 fi
@@ -7166,6 +7203,7 @@ echo "cpp_link_args = [${LDFLAGS:+$(meson_quote $LDFLAGS)}]" >> $cross
 echo "[binaries]" >> $cross
 echo "c = [$(meson_quote $cc)]" >> $cross
 test -n "$cxx" && echo "cpp = [$(meson_quote $cxx)]" >> $cross
+test -n "$objcc" && echo "objc = [$(meson_quote $objcc)]" >> $cross
 echo "ar = [$(meson_quote $ar)]" >> $cross
 echo "nm = [$(meson_quote $nm)]" >> $cross
 echo "pkgconfig = [$(meson_quote $pkg_config_exe)]" >> $cross
@@ -7184,6 +7222,9 @@ if test "$cross_compile" = "yes"; then
     if test "$linux" = "yes" ; then
         echo "system = 'linux'" >> $cross
     fi
+    if test "$darwin" = "yes" ; then
+        echo "system = 'darwin'" >> $cross
+    fi
     case "$ARCH" in
         i386|x86_64)
             echo "cpu_family = 'x86'" >> $cross
diff --git a/meson.build b/meson.build
index 5d3a47784b..69a3c00cce 100644
--- a/meson.build
+++ b/meson.build
@@ -140,7 +140,7 @@ if targetos == 'windows'
                                       include_directories: include_directories('.'))
 elif targetos == 'darwin'
   coref = dependency('appleframeworks', modules: 'CoreFoundation')
-  iokit = dependency('appleframeworks', modules: 'IOKit')
+  iokit = dependency('appleframeworks', modules: 'IOKit', required: 'CONFIG_IOS' not in config_host)
   cocoa = dependency('appleframeworks', modules: 'Cocoa', required: get_option('cocoa'))
 elif targetos == 'sunos'
   socket = [cc.find_library('socket'),
diff --git a/net/slirp.c b/net/slirp.c
index 77042e6df7..8413042c09 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -27,7 +27,7 @@
 #include "net/slirp.h"
 
 
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(CONFIG_IOS)
 #include <pwd.h>
 #include <sys/wait.h>
 #endif
@@ -90,7 +90,7 @@ typedef struct SlirpState {
     Slirp *slirp;
     Notifier poll_notifier;
     Notifier exit_notifier;
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(CONFIG_IOS)
     gchar *smb_dir;
 #endif
     GSList *fwd;
@@ -103,7 +103,7 @@ static QTAILQ_HEAD(, SlirpState) slirp_stacks =
 static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp);
 static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp);
 
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(CONFIG_IOS)
 static int slirp_smb(SlirpState *s, const char *exported_dir,
                      struct in_addr vserver_addr, Error **errp);
 static void slirp_smb_cleanup(SlirpState *s);
@@ -368,7 +368,7 @@ static int net_slirp_init(NetClientState *peer, const char *model,
     struct in6_addr ip6_prefix;
     struct in6_addr ip6_host;
     struct in6_addr ip6_dns;
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(CONFIG_IOS)
     struct in_addr smbsrv = { .s_addr = 0 };
 #endif
     NetClientState *nc;
@@ -478,7 +478,7 @@ static int net_slirp_init(NetClientState *peer, const char *model,
         return -1;
     }
 
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(CONFIG_IOS)
     if (vsmbserver && !inet_aton(vsmbserver, &smbsrv)) {
         error_setg(errp, "Failed to parse SMB address");
         return -1;
@@ -593,7 +593,7 @@ static int net_slirp_init(NetClientState *peer, const char *model,
             }
         }
     }
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(CONFIG_IOS)
     if (smb_export) {
         if (slirp_smb(s, smb_export, smbsrv, errp) < 0) {
             goto error;
@@ -785,7 +785,7 @@ void hmp_hostfwd_add(Monitor *mon, const QDict *qdict)
 
 }
 
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(CONFIG_IOS)
 
 /* automatic user mode samba server configuration */
 static void slirp_smb_cleanup(SlirpState *s)
@@ -900,7 +900,7 @@ static int slirp_smb(SlirpState* s, const char *exported_dir,
     return 0;
 }
 
-#endif /* !defined(_WIN32) */
+#endif /* !defined(_WIN32) && !defined(CONFIG_IOS) */
 
 static int guestfwd_can_read(void *opaque)
 {
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 3bffee99d4..ebb63b2188 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -34,6 +34,12 @@
 
 #ifndef CONFIG_HAS_ENVIRON
 #ifdef __APPLE__
+#include "TargetConditionals.h"
+#if !TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
+#define APPLE_USE_CRT_EXTERNS
+#endif
+#endif
+#ifdef APPLE_USE_CRT_EXTERNS
 #include <crt_externs.h>
 #define environ (*_NSGetEnviron())
 #else
diff --git a/target/arm/arm-semi.c b/target/arm/arm-semi.c
index 8718fd0194..3704f19df6 100644
--- a/target/arm/arm-semi.c
+++ b/target/arm/arm-semi.c
@@ -891,6 +891,7 @@ target_ulong do_arm_semihosting(CPUARMState *env)
         return clock() / (CLOCKS_PER_SEC / 100);
     case TARGET_SYS_TIME:
         return set_swi_errno(env, time(NULL));
+#if !defined(CONFIG_IOS) /* iOS does not have system() */
     case TARGET_SYS_SYSTEM:
         GET_ARG(0);
         GET_ARG(1);
@@ -907,6 +908,7 @@ target_ulong do_arm_semihosting(CPUARMState *env)
             unlock_user(s, arg0, 0);
             return ret;
         }
+#endif /* CONFIG_IOS */
     case TARGET_SYS_ERRNO:
         return get_swi_errno(env);
     case TARGET_SYS_GET_CMDLINE:
diff --git a/target/m68k/m68k-semi.c b/target/m68k/m68k-semi.c
index 8e5fbfc8fa..6b8941839e 100644
--- a/target/m68k/m68k-semi.c
+++ b/target/m68k/m68k-semi.c
@@ -402,6 +402,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
             result = isatty(arg0);
         }
         break;
+#if !defined(CONFIG_IOS) /* iOS does not have system() */
     case HOSTED_SYSTEM:
         GET_ARG(0);
         GET_ARG(1);
@@ -420,6 +421,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
             }
         }
         break;
+#endif /* CONFIG_IOS */
     case HOSTED_INIT_SIM:
 #if defined(CONFIG_USER_ONLY)
         {
diff --git a/target/nios2/nios2-semi.c b/target/nios2/nios2-semi.c
index d7a80dd303..bb029070d3 100644
--- a/target/nios2/nios2-semi.c
+++ b/target/nios2/nios2-semi.c
@@ -426,6 +426,7 @@ void do_nios2_semihosting(CPUNios2State *env)
             result = isatty(arg0);
         }
         break;
+#if !defined(CONFIG_IOS) /* iOS does not have system() */
     case HOSTED_SYSTEM:
         GET_ARG(0);
         GET_ARG(1);
@@ -444,6 +445,7 @@ void do_nios2_semihosting(CPUNios2State *env)
             }
         }
         break;
+#endif
     default:
         qemu_log_mask(LOG_GUEST_ERROR, "nios2-semihosting: unsupported "
                       "semihosting syscall %d\n", nr);
diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h
index 663dd0b95e..a2b22b4305 100644
--- a/tcg/aarch64/tcg-target.h
+++ b/tcg/aarch64/tcg-target.h
@@ -148,9 +148,19 @@ typedef enum {
 #define TCG_TARGET_DEFAULT_MO (0)
 #define TCG_TARGET_HAS_MEMORY_BSWAP     1
 
+#if defined(__APPLE__)
+void sys_icache_invalidate(void *start, size_t len);
+#endif
+
 static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
 {
+#if defined(__APPLE__)
+    sys_icache_invalidate((char *)start, stop - start);
+#elif defined(__GNUC__)
     __builtin___clear_cache((char *)start, (char *)stop);
+#else
+#error "Missing builtin to flush instruction cache"
+#endif
 }
 
 void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 0f32ca0895..7184edcafa 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -46,12 +46,11 @@ qtests_i386 = \
   (config_all_devices.has_key('CONFIG_TPM_TIS_ISA') ? ['tpm-tis-test'] : []) +              \
   (config_all_devices.has_key('CONFIG_TPM_TIS_ISA') ? ['tpm-tis-swtpm-test'] : []) +        \
   (config_all_devices.has_key('CONFIG_RTL8139_PCI') ? ['rtl8139-test'] : []) +              \
+  (not config_host.has_key('CONFIG_IOS') ? ['bios-tables-test', 'hd-geo-test'] : []) +      \
   qtests_pci +                                                                              \
   ['fdc-test',
    'ide-test',
-   'hd-geo-test',
    'boot-order-test',
-   'bios-tables-test',
    'rtc-test',
    'i440fx-test',
    'fw_cfg-test',
@@ -141,9 +140,9 @@ qtests_arm = \
    'boot-serial-test',
    'hexloader-test']
 
-# TODO: once aarch64 TCG is fixed on ARM 32 bit host, make bios-tables-test unconditional
+# TODO: once aarch64 TCG is fixed on ARM 32 bit host, make bios-tables-test unconditional (except on iOS)
 qtests_aarch64 = \
-  (cpu != 'arm' ? ['bios-tables-test'] : []) +                                                  \
+  (cpu != 'arm' and not config_host.has_key('CONFIG_IOS') ? ['bios-tables-test'] : []) +        \
   (config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-test'] : []) +        \
   (config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-swtpm-test'] : []) +  \
   ['arm-cpu-features',
-- 
2.24.3 (Apple Git-128)



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 04/10] meson: option to build as shared library
  2020-10-12 23:29 [PATCH 00/10] iOS and Apple Silicon host support Joelle van Dyne
                   ` (2 preceding siblings ...)
  2020-10-12 23:29 ` [PATCH 03/10] qemu: add support for iOS host Joelle van Dyne
@ 2020-10-12 23:29 ` Joelle van Dyne
  2020-10-13  7:51   ` Daniel P. Berrangé
  2020-10-12 23:29 ` [PATCH 05/10] slirp: update for iOS resolv fix Joelle van Dyne
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 47+ messages in thread
From: Joelle van Dyne @ 2020-10-12 23:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: Joelle van Dyne

From: osy <osy86@users.noreply.github.com>

On iOS, we cannot fork() new processes, so the best way to load QEMU into an
app is through a shared library. We add a new configure option
`--enable-shared-lib` that will build the bulk of QEMU into a shared lib.
The usual executables will then link to the library.

Signed-off-by: Joelle van Dyne <j@getutm.app>
---
 configure         | 14 ++++++++++++--
 meson.build       | 40 ++++++++++++++++++++++++++++++++++------
 meson_options.txt |  2 ++
 3 files changed, 48 insertions(+), 8 deletions(-)

diff --git a/configure b/configure
index c474d7c221..37b27d9e35 100755
--- a/configure
+++ b/configure
@@ -448,6 +448,7 @@ ninja=""
 skip_meson=no
 gettext=""
 host_block_device_support="yes"
+shared_lib="false"
 
 bogus_os="no"
 malloc_trim="auto"
@@ -1563,6 +1564,10 @@ for opt do
   ;;
   --disable-libdaxctl) libdaxctl=no
   ;;
+  --enable-shared-lib) shared_lib=true
+  ;;
+  --disable-shared-lib) shared_lib=false
+  ;;
   *)
       echo "ERROR: unknown option $opt"
       echo "Try '$0 --help' for more information"
@@ -1770,6 +1775,7 @@ Advanced options (experts only):
                            enable plugins via shared library loading
   --disable-containers     don't use containers for cross-building
   --gdb=GDB-path           gdb to use for gdbstub tests [$gdb_bin]
+  --enable-shared-lib      build QEMU as a shared library
 
 Optional features, enabled with --enable-FEATURE and
 disabled with --disable-FEATURE, default is enabled if available:
@@ -7211,7 +7217,11 @@ echo "ranlib = [$(meson_quote $ranlib)]" >> $cross
 if has $sdl2_config; then
   echo "sdl2-config = [$(meson_quote $sdl2_config)]" >> $cross
 fi
-echo "strip = [$(meson_quote $strip)]" >> $cross
+if test "$shared_lib" = "true"; then
+  echo "strip = [$(meson_quote $strip), '-x']" >> $cross
+else
+  echo "strip = [$(meson_quote $strip)]" >> $cross
+fi
 echo "windres = [$(meson_quote $windres)]" >> $cross
 if test "$cross_compile" = "yes"; then
     cross_arg="--cross-file config-meson.cross"
@@ -7273,7 +7283,7 @@ NINJA=${ninja:-$PWD/ninjatool} $meson setup \
 	-Dcocoa=$cocoa -Dmpath=$mpath -Dsdl=$sdl -Dsdl_image=$sdl_image \
 	-Dvnc=$vnc -Dvnc_sasl=$vnc_sasl -Dvnc_jpeg=$vnc_jpeg -Dvnc_png=$vnc_png \
 	-Dgettext=$gettext -Dxkbcommon=$xkbcommon -Du2f=$u2f \
-	-Dcapstone=$capstone -Dslirp=$slirp -Dfdt=$fdt \
+	-Dcapstone=$capstone -Dslirp=$slirp -Dfdt=$fdt -Dshared-lib=$shared_lib \
         $cross_arg \
         "$PWD" "$source_path"
 
diff --git a/meson.build b/meson.build
index 69a3c00cce..32cf08619f 100644
--- a/meson.build
+++ b/meson.build
@@ -1565,14 +1565,31 @@ foreach target : target_dirs
   arch_srcs += target_specific.sources()
   arch_deps += target_specific.dependencies()
 
-  lib = static_library('qemu-' + target,
+  if get_option('shared-lib')
+    build_lib_args = {
+      'target_type': 'shared_library',
+      'install': true,
+      'dependencies': arch_deps + deps,
+      'link_language': link_language,
+      'link_depends': [block_syms, qemu_syms],
+      'link_args': link_args + cc.get_supported_link_arguments(['-Wl,-U,_qemu_main'])
+    }
+  else
+    build_lib_args = {
+      'target_type': 'static_library',
+      'install': false,
+      'dependencies': arch_deps,
+      'name_suffix': 'fa'
+    }
+  endif
+
+  lib = build_target('qemu-' + target,
                  sources: arch_srcs + genh,
-                 dependencies: arch_deps,
                  objects: objects,
                  include_directories: target_inc,
                  c_args: c_args,
                  build_by_default: false,
-                 name_suffix: 'fa')
+                 kwargs: build_lib_args)
 
   if target.endswith('-softmmu')
     execs = [{
@@ -1606,17 +1623,27 @@ foreach target : target_dirs
       'dependencies': []
     }]
   endif
+  if get_option('shared-lib')
+    build_exe_args = {
+      'link_with': lib,
+      'link_args': link_args + cc.get_supported_link_arguments(['-Wl,--exclude-libs,ALL'])
+    }
+  else
+    build_exe_args = {
+      'objects': lib.extract_all_objects(recursive: true),
+      'link_args': link_args
+    }
+  endif
   foreach exe: execs
     emulators += {exe['name']:
          executable(exe['name'], exe['sources'],
                install: true,
                c_args: c_args,
                dependencies: arch_deps + deps + exe['dependencies'],
-               objects: lib.extract_all_objects(recursive: true),
                link_language: link_language,
                link_depends: [block_syms, qemu_syms] + exe.get('link_depends', []),
-               link_args: link_args,
-               gui_app: exe['gui'])
+               gui_app: exe['gui'],
+               kwargs: build_exe_args)
     }
 
     if 'CONFIG_TRACE_SYSTEMTAP' in config_host
@@ -1758,6 +1785,7 @@ endif
 summary_info += {'Doc directory':     get_option('docdir')}
 summary_info += {'Build directory':   meson.current_build_dir()}
 summary_info += {'Source path':       meson.current_source_dir()}
+summary_info += {'build shared lib':  get_option('shared-lib')}
 summary_info += {'GIT binary':        config_host['GIT']}
 summary_info += {'GIT submodules':    config_host['GIT_SUBMODULES']}
 summary_info += {'C compiler':        meson.get_compiler('c').cmd_array()[0]}
diff --git a/meson_options.txt b/meson_options.txt
index 1d3c94840a..bcecbd5e12 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -2,6 +2,8 @@ option('qemu_suffix', type : 'string', value: 'qemu',
        description: 'Suffix for QEMU data/modules/config directories (can be empty)')
 option('docdir', type : 'string', value : 'doc',
        description: 'Base directory for documentation installation (can be empty)')
+option('shared-lib', type : 'boolean', value : false,
+       description: 'build QEMU as a shared library')
 
 option('gettext', type : 'boolean', value : true,
        description: 'Localization of the GTK+ user interface')
-- 
2.24.3 (Apple Git-128)



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 05/10] slirp: update for iOS resolv fix
  2020-10-12 23:29 [PATCH 00/10] iOS and Apple Silicon host support Joelle van Dyne
                   ` (3 preceding siblings ...)
  2020-10-12 23:29 ` [PATCH 04/10] meson: option to build as shared library Joelle van Dyne
@ 2020-10-12 23:29 ` Joelle van Dyne
  2020-10-13 13:32   ` Philippe Mathieu-Daudé
  2020-10-12 23:29 ` [PATCH 06/10] coroutine: add libucontext as external library Joelle van Dyne
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 47+ messages in thread
From: Joelle van Dyne @ 2020-10-12 23:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: Joelle van Dyne

From: osy <osy86@users.noreply.github.com>

We cannot access /etc/resolv.conf on iOS so libslirp is modified to use
libresolv instead.

Signed-off-by: Joelle van Dyne <j@getutm.app>
---
 .gitmodules | 2 +-
 meson.build | 2 ++
 slirp       | 2 +-
 3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/.gitmodules b/.gitmodules
index 2bdeeacef8..f23e859210 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -51,7 +51,7 @@
 	url = https://git.qemu.org/git/edk2.git
 [submodule "slirp"]
 	path = slirp
-	url = https://git.qemu.org/git/libslirp.git
+	url = https://github.com/utmapp/libslirp.git
 [submodule "roms/opensbi"]
 	path = roms/opensbi
 	url = 	https://git.qemu.org/git/opensbi.git
diff --git a/meson.build b/meson.build
index 32cf08619f..da96e296e0 100644
--- a/meson.build
+++ b/meson.build
@@ -996,6 +996,8 @@ if have_system
     slirp_deps = []
     if targetos == 'windows'
       slirp_deps = cc.find_library('iphlpapi')
+    elif targetos == 'darwin'
+      slirp_deps = cc.find_library('resolv')
     endif
     slirp_conf = configuration_data()
     slirp_conf.set('SLIRP_MAJOR_VERSION', meson.project_version().split('.')[0])
diff --git a/slirp b/slirp
index ce94eba204..452c389d82 160000
--- a/slirp
+++ b/slirp
@@ -1 +1 @@
-Subproject commit ce94eba2042d52a0ba3d9e252ebce86715e94275
+Subproject commit 452c389d8288f81ec9d59d983a047d4e54f3194e
-- 
2.24.3 (Apple Git-128)



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 06/10] coroutine: add libucontext as external library
  2020-10-12 23:29 [PATCH 00/10] iOS and Apple Silicon host support Joelle van Dyne
                   ` (4 preceding siblings ...)
  2020-10-12 23:29 ` [PATCH 05/10] slirp: update for iOS resolv fix Joelle van Dyne
@ 2020-10-12 23:29 ` Joelle van Dyne
  2020-10-13 13:31   ` Stefan Hajnoczi
  2020-10-12 23:29   ` Joelle van Dyne
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 47+ messages in thread
From: Joelle van Dyne @ 2020-10-12 23:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Joelle van Dyne, Stefan Hajnoczi

From: osy <osy86@users.noreply.github.com>

iOS does not support ucontext natively for aarch64 and the sigaltstack is
also unsupported (even worse, it fails silently, see:
https://openradar.appspot.com/13002712 )

As a workaround we include a library implementation of ucontext and add it
as a build option.

Signed-off-by: Joelle van Dyne <j@getutm.app>
---
 .gitmodules               |  3 +++
 configure                 | 23 ++++++++++++++++++++---
 libucontext               |  1 +
 meson.build               | 29 ++++++++++++++++++++++++++++-
 meson_options.txt         |  2 ++
 util/coroutine-ucontext.c |  9 +++++++++
 6 files changed, 63 insertions(+), 4 deletions(-)
 create mode 160000 libucontext

diff --git a/.gitmodules b/.gitmodules
index f23e859210..f5a1dc3c5a 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -64,3 +64,6 @@
 [submodule "roms/vbootrom"]
 	path = roms/vbootrom
 	url = https://git.qemu.org/git/vbootrom.git
+[submodule "libucontext"]
+	path = libucontext
+	url = https://github.com/utmapp/libucontext.git
diff --git a/configure b/configure
index 37b27d9e35..16c66b437c 100755
--- a/configure
+++ b/configure
@@ -1761,7 +1761,7 @@ Advanced options (experts only):
   --oss-lib                path to OSS library
   --cpu=CPU                Build for host CPU [$cpu]
   --with-coroutine=BACKEND coroutine backend. Supported options:
-                           ucontext, sigaltstack, windows
+                           ucontext, libucontext, sigaltstack, windows
   --enable-gcov            enable test coverage analysis with gcov
   --disable-blobs          disable installing provided firmware blobs
   --with-vss-sdk=SDK-path  enable Windows VSS support in QEMU Guest Agent
@@ -5064,6 +5064,8 @@ if test "$coroutine" = ""; then
     coroutine=win32
   elif test "$ucontext_works" = "yes"; then
     coroutine=ucontext
+  elif test "$ios" = "yes"; then
+    coroutine=libucontext
   else
     coroutine=sigaltstack
   fi
@@ -5087,12 +5089,27 @@ else
       error_exit "only the 'windows' coroutine backend is valid for Windows"
     fi
     ;;
+  libucontext)
+  ;;
   *)
     error_exit "unknown coroutine backend $coroutine"
     ;;
   esac
 fi
 
+case $coroutine in
+libucontext)
+  git_submodules="${git_submodules} libucontext"
+  mkdir -p libucontext
+  coroutine_impl=ucontext
+  libucontext="enabled"
+  ;;
+*)
+  coroutine_impl=$coroutine
+  libucontext="disabled"
+  ;;
+esac
+
 if test "$coroutine_pool" = ""; then
   coroutine_pool=yes
 fi
@@ -6682,7 +6699,7 @@ if test "$rbd" = "yes" ; then
   echo "RBD_LIBS=$rbd_libs" >> $config_host_mak
 fi
 
-echo "CONFIG_COROUTINE_BACKEND=$coroutine" >> $config_host_mak
+echo "CONFIG_COROUTINE_BACKEND=$coroutine_impl" >> $config_host_mak
 if test "$coroutine_pool" = "yes" ; then
   echo "CONFIG_COROUTINE_POOL=1" >> $config_host_mak
 else
@@ -7282,7 +7299,7 @@ NINJA=${ninja:-$PWD/ninjatool} $meson setup \
 	-Dxen=$xen -Dxen_pci_passthrough=$xen_pci_passthrough -Dtcg=$tcg \
 	-Dcocoa=$cocoa -Dmpath=$mpath -Dsdl=$sdl -Dsdl_image=$sdl_image \
 	-Dvnc=$vnc -Dvnc_sasl=$vnc_sasl -Dvnc_jpeg=$vnc_jpeg -Dvnc_png=$vnc_png \
-	-Dgettext=$gettext -Dxkbcommon=$xkbcommon -Du2f=$u2f \
+	-Dgettext=$gettext -Dxkbcommon=$xkbcommon -Du2f=$u2f -Ducontext=$libucontext \
 	-Dcapstone=$capstone -Dslirp=$slirp -Dfdt=$fdt -Dshared-lib=$shared_lib \
         $cross_arg \
         "$PWD" "$source_path"
diff --git a/libucontext b/libucontext
new file mode 160000
index 0000000000..7094e4c427
--- /dev/null
+++ b/libucontext
@@ -0,0 +1 @@
+Subproject commit 7094e4c42723b6178a4e2b60d4631d8a88f40719
diff --git a/meson.build b/meson.build
index da96e296e0..118276edb7 100644
--- a/meson.build
+++ b/meson.build
@@ -1101,9 +1101,35 @@ if not fdt.found() and fdt_required.length() > 0
   error('fdt not available but required by targets ' + ', '.join(fdt_required))
 endif
 
+ucontext = not_found
+slirp_opt = 'disabled'
+if get_option('ucontext').enabled()
+  if not fs.is_dir(meson.current_source_dir() / 'libucontext/arch' / cpu)
+    error('libucontext is wanted but not implemented for host ' + cpu)
+  endif
+  arch = host_machine.cpu()
+  ucontext_cargs = ['-DG_LOG_DOMAIN="ucontext"', '-DCUSTOM_IMPL']
+  ucontext_files = [
+    'libucontext/arch' / arch / 'getcontext.S',
+    'libucontext/arch' / arch / 'setcontext.S',
+    'libucontext/arch' / arch / 'makecontext.c',
+    'libucontext/arch' / arch / 'startcontext.S',
+    'libucontext/arch' / arch / 'swapcontext.S',
+  ]
+
+  ucontext_inc = include_directories('libucontext/include')
+  libucontext = static_library('ucontext',
+                               sources: ucontext_files,
+                               c_args: ucontext_cargs,
+                               include_directories: ucontext_inc)
+  ucontext = declare_dependency(link_with: libucontext,
+                                include_directories: ucontext_inc)
+endif
+
 config_host_data.set('CONFIG_CAPSTONE', capstone.found())
 config_host_data.set('CONFIG_FDT', fdt.found())
 config_host_data.set('CONFIG_SLIRP', slirp.found())
+config_host_data.set('CONFIG_LIBUCONTEXT', ucontext.found())
 
 genh += configure_file(output: 'config-host.h', configuration: config_host_data)
 
@@ -1323,7 +1349,7 @@ util_ss.add_all(trace_ss)
 util_ss = util_ss.apply(config_all, strict: false)
 libqemuutil = static_library('qemuutil',
                              sources: util_ss.sources() + stub_ss.sources() + genh,
-                             dependencies: [util_ss.dependencies(), m, glib, socket, malloc])
+                             dependencies: [util_ss.dependencies(), m, glib, socket, malloc, ucontext])
 qemuutil = declare_dependency(link_with: libqemuutil,
                               sources: genh + version_res)
 
@@ -1946,6 +1972,7 @@ if targetos == 'windows'
   summary_info += {'QGA MSI support':   config_host.has_key('CONFIG_QGA_MSI')}
 endif
 summary_info += {'seccomp support':   config_host.has_key('CONFIG_SECCOMP')}
+summary_info += {'libucontext support': ucontext.found()}
 summary_info += {'coroutine backend': config_host['CONFIG_COROUTINE_BACKEND']}
 summary_info += {'coroutine pool':    config_host['CONFIG_COROUTINE_POOL'] == '1'}
 summary_info += {'debug stack usage': config_host.has_key('CONFIG_DEBUG_STACK_USAGE')}
diff --git a/meson_options.txt b/meson_options.txt
index bcecbd5e12..acd989dfa2 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -50,6 +50,8 @@ option('vnc_sasl', type : 'feature', value : 'auto',
        description: 'SASL authentication for VNC server')
 option('xkbcommon', type : 'feature', value : 'auto',
        description: 'xkbcommon support')
+option('ucontext', type : 'feature', value : 'disabled',
+       description: 'libucontext support')
 
 option('capstone', type: 'combo', value: 'auto',
        choices: ['disabled', 'enabled', 'auto', 'system', 'internal'],
diff --git a/util/coroutine-ucontext.c b/util/coroutine-ucontext.c
index 904b375192..1e1dd43512 100644
--- a/util/coroutine-ucontext.c
+++ b/util/coroutine-ucontext.c
@@ -23,7 +23,16 @@
 #undef _FORTIFY_SOURCE
 #endif
 #include "qemu/osdep.h"
+#if defined(CONFIG_LIBUCONTEXT)
+#include <libucontext.h>
+#define ucontext_t libucontext_ucontext_t
+#define getcontext libucontext_getcontext
+#define setcontext libucontext_setcontext
+#define swapcontext libucontext_swapcontext
+#define makecontext libucontext_makecontext
+#else
 #include <ucontext.h>
+#endif
 #include "qemu/coroutine_int.h"
 
 #ifdef CONFIG_VALGRIND_H
-- 
2.24.3 (Apple Git-128)



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 07/10] tcg: implement bulletproof JIT
  2020-10-12 23:29 [PATCH 00/10] iOS and Apple Silicon host support Joelle van Dyne
@ 2020-10-12 23:29   ` Joelle van Dyne
  2020-10-12 23:29 ` [PATCH 02/10] configure: cross-compiling without cross_prefix Joelle van Dyne
                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 47+ messages in thread
From: Joelle van Dyne @ 2020-10-12 23:29 UTC (permalink / raw)
  To: qemu-devel
  Cc: Aleksandar Rikalo, open list:RISC-V TCG target, Stefan Weil,
	open list:S390 TCG target, Aleksandar Markovic,
	open list:AArch64 TCG target, Palmer Dabbelt, Joelle van Dyne,
	Huacai Chen, Paolo Bonzini, Alistair Francis, Aurelien Jarno,
	Richard Henderson

From: osy <osy86@users.noreply.github.com>

On iOS, we cannot allocate RWX pages without special entitlements. As a
workaround, we can a RX region and then mirror map it to a separate RX
region. Then we can write to one region and execute from the other one.

To better keep track of pointers to RW/RX memory, we mark any tcg_insn_unit
pointers as `const` if they will never be written to. We also define a new
macro `TCG_CODE_PTR_RW` that returns a pointer to RW memory. Only the
difference between the two regions is stored in the TCG context.

To ensure cache coherency, we flush the data cache in the RW mapping and
then invalidate the instruction cache in the RX mapping (where applicable).
Because data cache flush is OS defined on some architectures, we do not
provide implementations for non iOS platforms (ARM/x86).

Signed-off-by: Joelle van Dyne <j@getutm.app>
---
 accel/tcg/cpu-exec.c         |  7 +++-
 accel/tcg/translate-all.c    | 78 ++++++++++++++++++++++++++++++++++--
 configure                    |  1 +
 docs/devel/ios.rst           | 40 ++++++++++++++++++
 include/exec/exec-all.h      |  8 ++++
 include/tcg/tcg.h            | 18 +++++++--
 tcg/aarch64/tcg-target.c.inc | 48 +++++++++++++---------
 tcg/aarch64/tcg-target.h     | 13 +++++-
 tcg/arm/tcg-target.c.inc     | 33 ++++++++-------
 tcg/arm/tcg-target.h         |  9 ++++-
 tcg/i386/tcg-target.c.inc    | 28 ++++++-------
 tcg/i386/tcg-target.h        | 24 ++++++++++-
 tcg/mips/tcg-target.c.inc    | 64 +++++++++++++++++------------
 tcg/mips/tcg-target.h        |  8 +++-
 tcg/ppc/tcg-target.c.inc     | 55 ++++++++++++++++---------
 tcg/ppc/tcg-target.h         |  8 +++-
 tcg/riscv/tcg-target.c.inc   | 51 +++++++++++++----------
 tcg/riscv/tcg-target.h       |  9 ++++-
 tcg/s390/tcg-target.c.inc    | 25 ++++++------
 tcg/s390/tcg-target.h        | 13 +++++-
 tcg/sparc/tcg-target.c.inc   | 33 +++++++++------
 tcg/sparc/tcg-target.h       |  8 +++-
 tcg/tcg-ldst.c.inc           |  2 +-
 tcg/tcg-pool.c.inc           |  9 +++--
 tcg/tcg.c                    | 60 +++++++++++++++++----------
 tcg/tci/tcg-target.c.inc     |  8 ++--
 tcg/tci/tcg-target.h         |  9 ++++-
 27 files changed, 481 insertions(+), 188 deletions(-)
 create mode 100644 docs/devel/ios.rst

diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index 58aea605d8..821aefdea2 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -354,7 +354,12 @@ void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr)
     if (TCG_TARGET_HAS_direct_jump) {
         uintptr_t offset = tb->jmp_target_arg[n];
         uintptr_t tc_ptr = (uintptr_t)tb->tc.ptr;
-        tb_target_set_jmp_target(tc_ptr, tc_ptr + offset, addr);
+#if defined(CONFIG_IOS_JIT)
+        uintptr_t wr_addr = tc_ptr + offset + tb->code_rw_mirror_diff;
+#else
+        uintptr_t wr_addr = tc_ptr + offset;
+#endif
+        tb_target_set_jmp_target(tc_ptr, tc_ptr + offset, addr, wr_addr);
     } else {
         tb->jmp_target_arg[n] = addr;
     }
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index d76097296d..76d8dc3d7b 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -60,6 +60,22 @@
 #include "sysemu/cpu-timers.h"
 #include "sysemu/tcg.h"
 
+#if defined(CONFIG_IOS_JIT)
+#include <mach/mach.h>
+extern kern_return_t mach_vm_remap(vm_map_t target_task,
+                                   mach_vm_address_t *target_address,
+                                   mach_vm_size_t size,
+                                   mach_vm_offset_t mask,
+                                   int flags,
+                                   vm_map_t src_task,
+                                   mach_vm_address_t src_address,
+                                   boolean_t copy,
+                                   vm_prot_t *cur_protection,
+                                   vm_prot_t *max_protection,
+                                   vm_inherit_t inheritance
+                                  );
+#endif
+
 /* #define DEBUG_TB_INVALIDATE */
 /* #define DEBUG_TB_FLUSH */
 /* make various TB consistency checks */
@@ -302,10 +318,13 @@ static target_long decode_sleb128(uint8_t **pp)
 
 static int encode_search(TranslationBlock *tb, uint8_t *block)
 {
-    uint8_t *highwater = tcg_ctx->code_gen_highwater;
-    uint8_t *p = block;
+    uint8_t *highwater;
+    uint8_t *p;
     int i, j, n;
 
+    highwater = (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx,
+                                           tcg_ctx->code_gen_highwater);
+    p = (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx, block);
     for (i = 0, n = tb->icount; i < n; ++i) {
         target_ulong prev;
 
@@ -329,7 +348,7 @@ static int encode_search(TranslationBlock *tb, uint8_t *block)
         }
     }
 
-    return p - block;
+    return p - (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx, block);
 }
 
 /* The cpu state corresponding to 'searched_pc' is restored.
@@ -1067,7 +1086,11 @@ static inline void *alloc_code_gen_buffer(void)
 #else
 static inline void *alloc_code_gen_buffer(void)
 {
+#if defined(CONFIG_IOS_JIT)
+    int prot = PROT_READ | PROT_EXEC;
+#else
     int prot = PROT_WRITE | PROT_READ | PROT_EXEC;
+#endif
     int flags = MAP_PRIVATE | MAP_ANONYMOUS;
     size_t size = tcg_ctx->code_gen_buffer_size;
     void *buf;
@@ -1118,6 +1141,39 @@ static inline void *alloc_code_gen_buffer(void)
 }
 #endif /* USE_STATIC_CODE_GEN_BUFFER, WIN32, POSIX */
 
+#if defined(CONFIG_IOS_JIT)
+static inline void *alloc_jit_rw_mirror(void *base, size_t size)
+{
+    kern_return_t ret;
+    mach_vm_address_t mirror;
+    vm_prot_t cur_prot, max_prot;
+
+    mirror = 0;
+    ret = mach_vm_remap(mach_task_self(),
+                        &mirror,
+                        size,
+                        0,
+                        VM_FLAGS_ANYWHERE | VM_FLAGS_RANDOM_ADDR,
+                        mach_task_self(),
+                        (mach_vm_address_t)base,
+                        false,
+                        &cur_prot,
+                        &max_prot,
+                        VM_INHERIT_NONE
+                       );
+    if (ret != KERN_SUCCESS) {
+        return NULL;
+    }
+
+    if (mprotect((void *)mirror, size, PROT_READ | PROT_WRITE) != 0) {
+        munmap((void *)mirror, size);
+        return NULL;
+    }
+
+    return (void *)mirror;
+}
+#endif /* CONFIG_IOS_JIT */
+
 static inline void code_gen_alloc(size_t tb_size)
 {
     tcg_ctx->code_gen_buffer_size = size_code_gen_buffer(tb_size);
@@ -1126,6 +1182,19 @@ static inline void code_gen_alloc(size_t tb_size)
         fprintf(stderr, "Could not allocate dynamic translator buffer\n");
         exit(1);
     }
+#if defined(CONFIG_IOS_JIT)
+    void *mirror;
+
+    /* For iOS JIT we need a mirror mapping for code execution */
+    mirror = alloc_jit_rw_mirror(tcg_ctx->code_gen_buffer,
+                                 tcg_ctx->code_gen_buffer_size
+                                );
+    if (mirror == NULL) {
+        fprintf(stderr, "Could not remap code buffer mirror\n");
+        exit(1);
+    }
+    tcg_ctx->code_rw_mirror_diff = mirror - tcg_ctx->code_gen_buffer;
+#endif /* CONFIG_IOS_JIT */
 }
 
 static bool tb_cmp(const void *ap, const void *bp)
@@ -1721,6 +1790,9 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
         cpu_loop_exit(cpu);
     }
 
+#if defined(CONFIG_IOS_JIT)
+    tb->code_rw_mirror_diff = tcg_ctx->code_rw_mirror_diff;
+#endif
     gen_code_buf = tcg_ctx->code_gen_ptr;
     tb->tc.ptr = gen_code_buf;
     tb->pc = pc;
diff --git a/configure b/configure
index 16c66b437c..c5a6584683 100755
--- a/configure
+++ b/configure
@@ -6220,6 +6220,7 @@ fi
 
 if test "$ios" = "yes" ; then
   echo "CONFIG_IOS=y" >> $config_host_mak
+  echo "CONFIG_IOS_JIT=y" >> $config_host_mak
 fi
 
 if test "$solaris" = "yes" ; then
diff --git a/docs/devel/ios.rst b/docs/devel/ios.rst
new file mode 100644
index 0000000000..dba9fdd868
--- /dev/null
+++ b/docs/devel/ios.rst
@@ -0,0 +1,40 @@
+===========
+iOS Support
+===========
+
+To run qemu on the iOS platform, some modifications were required. Most of the
+modifications are conditioned on the ``CONFIG_IOS`` and ``CONFIG_IOS_JIT``
+configuration variables.
+
+Build support
+-------------
+
+For the code to compile, certain changes in the block driver and the slirp
+driver had to be made. There is no ``system()`` call, so code requiring it had
+to be disabled.
+
+``ucontext`` support is broken on iOS. The implementation from ``libucontext``
+is used instead.
+
+Because ``fork()`` is not allowed on iOS apps, the option to build qemu and the
+utilities as shared libraries is added. Note that because qemu does not perform
+resource cleanup in most cases (open files, allocated memory, etc), it is
+advisable that the user implements a proxy layer for syscalls so resources can
+be kept track by the app that uses qemu as a shared library.
+
+JIT support
+-----------
+
+On iOS, allocating RWX pages require special entitlements not usually granted to
+apps. However, it is possible to use `bulletproof JIT`_ with a development
+certificate. This means that we need to allocate one chunk of memory with RX
+permissions and then mirror map the same memory with RW permissions. We generate
+code to the mirror mapping and execute the original mapping.
+
+With ``CONFIG_IOS_JIT`` defined, we store inside the TCG context the difference
+between the two mappings. Then, we make sure that any writes to JIT memory is
+done to the pointer + the difference (in order to get a pointer to the mirror
+mapped space). Additionally, we make sure to flush the data cache before we
+invalidate the instruction cache so the changes are seen in both mappings.
+
+.. _bulletproof JIT: https://www.blackhat.com/docs/us-16/materials/us-16-Krstic.pdf
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 66f9b4cca6..2db155a772 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -483,6 +483,14 @@ struct TranslationBlock {
     uintptr_t jmp_list_head;
     uintptr_t jmp_list_next[2];
     uintptr_t jmp_dest[2];
+
+#if defined(CONFIG_IOS_JIT)
+    /*
+     * Store difference to writable mirror
+     * We need this when patching the jump instructions
+     */
+    ptrdiff_t code_rw_mirror_diff;
+#endif
 };
 
 extern bool parallel_cpus;
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
index 8804a8c4a2..40d1a7a85e 100644
--- a/include/tcg/tcg.h
+++ b/include/tcg/tcg.h
@@ -261,7 +261,7 @@ struct TCGLabel {
     unsigned refs : 16;
     union {
         uintptr_t value;
-        tcg_insn_unit *value_ptr;
+        const tcg_insn_unit *value_ptr;
     } u;
     QSIMPLEQ_HEAD(, TCGRelocation) relocs;
     QSIMPLEQ_ENTRY(TCGLabel) next;
@@ -593,7 +593,7 @@ struct TCGContext {
     int nb_ops;
 
     /* goto_tb support */
-    tcg_insn_unit *code_buf;
+    const tcg_insn_unit *code_buf;
     uint16_t *tb_jmp_reset_offset; /* tb->jmp_reset_offset */
     uintptr_t *tb_jmp_insn_offset; /* tb->jmp_target_arg if direct_jump */
     uintptr_t *tb_jmp_target_addr; /* tb->jmp_target_arg if !direct_jump */
@@ -627,6 +627,9 @@ struct TCGContext {
     size_t code_gen_buffer_size;
     void *code_gen_ptr;
     void *data_gen_ptr;
+#if defined(CONFIG_IOS_JIT)
+    ptrdiff_t code_rw_mirror_diff;
+#endif
 
     /* Threshold to flush the translated code buffer.  */
     void *code_gen_highwater;
@@ -677,6 +680,13 @@ struct TCGContext {
     target_ulong gen_insn_data[TCG_MAX_INSNS][TARGET_INSN_START_WORDS];
 };
 
+#if defined(CONFIG_IOS_JIT)
+# define TCG_CODE_PTR_RW(s, code_ptr) \
+    (tcg_insn_unit *)((uintptr_t)(code_ptr) + (s)->code_rw_mirror_diff)
+#else
+# define TCG_CODE_PTR_RW(s, code_ptr) (code_ptr)
+#endif
+
 extern TCGContext tcg_init_ctx;
 extern __thread TCGContext *tcg_ctx;
 extern TCGv_env cpu_env;
@@ -1099,7 +1109,7 @@ static inline TCGLabel *arg_label(TCGArg i)
  * correct result.
  */
 
-static inline ptrdiff_t tcg_ptr_byte_diff(void *a, void *b)
+static inline ptrdiff_t tcg_ptr_byte_diff(const void *a, const void *b)
 {
     return a - b;
 }
@@ -1113,7 +1123,7 @@ static inline ptrdiff_t tcg_ptr_byte_diff(void *a, void *b)
  * to the destination address.
  */
 
-static inline ptrdiff_t tcg_pcrel_diff(TCGContext *s, void *target)
+static inline ptrdiff_t tcg_pcrel_diff(TCGContext *s, const void *target)
 {
     return tcg_ptr_byte_diff(target, s->code_ptr);
 }
diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc
index 26f71cb599..9cfa2703b3 100644
--- a/tcg/aarch64/tcg-target.c.inc
+++ b/tcg/aarch64/tcg-target.c.inc
@@ -78,38 +78,44 @@ static const int tcg_target_call_oarg_regs[1] = {
 #define TCG_REG_GUEST_BASE TCG_REG_X28
 #endif
 
-static inline bool reloc_pc26(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
+static inline bool reloc_pc26(TCGContext *s,
+                              tcg_insn_unit *code_ptr,
+                              const tcg_insn_unit *target)
 {
     ptrdiff_t offset = target - code_ptr;
     if (offset == sextract64(offset, 0, 26)) {
         /* read instruction, mask away previous PC_REL26 parameter contents,
            set the proper offset, then write back the instruction. */
-        *code_ptr = deposit32(*code_ptr, 0, 26, offset);
+        *TCG_CODE_PTR_RW(s, code_ptr) =
+            deposit32(*TCG_CODE_PTR_RW(s, code_ptr), 0, 26, offset);
         return true;
     }
     return false;
 }
 
-static inline bool reloc_pc19(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
+static inline bool reloc_pc19(TCGContext *s,
+                              tcg_insn_unit *code_ptr,
+                              const tcg_insn_unit *target)
 {
     ptrdiff_t offset = target - code_ptr;
     if (offset == sextract64(offset, 0, 19)) {
-        *code_ptr = deposit32(*code_ptr, 5, 19, offset);
+        *TCG_CODE_PTR_RW(s, code_ptr) =
+            deposit32(*TCG_CODE_PTR_RW(s, code_ptr), 5, 19, offset);
         return true;
     }
     return false;
 }
 
-static inline bool patch_reloc(tcg_insn_unit *code_ptr, int type,
+static inline bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
                                intptr_t value, intptr_t addend)
 {
     tcg_debug_assert(addend == 0);
     switch (type) {
     case R_AARCH64_JUMP26:
     case R_AARCH64_CALL26:
-        return reloc_pc26(code_ptr, (tcg_insn_unit *)value);
+        return reloc_pc26(s, code_ptr, (tcg_insn_unit *)value);
     case R_AARCH64_CONDBR19:
-        return reloc_pc19(code_ptr, (tcg_insn_unit *)value);
+        return reloc_pc19(s, code_ptr, (tcg_insn_unit *)value);
     default:
         g_assert_not_reached();
     }
@@ -1306,14 +1312,14 @@ static void tcg_out_cmp(TCGContext *s, TCGType ext, TCGReg a,
     }
 }
 
-static inline void tcg_out_goto(TCGContext *s, tcg_insn_unit *target)
+static inline void tcg_out_goto(TCGContext *s, const tcg_insn_unit *target)
 {
     ptrdiff_t offset = target - s->code_ptr;
     tcg_debug_assert(offset == sextract64(offset, 0, 26));
     tcg_out_insn(s, 3206, B, offset);
 }
 
-static inline void tcg_out_goto_long(TCGContext *s, tcg_insn_unit *target)
+static inline void tcg_out_goto_long(TCGContext *s, const tcg_insn_unit *target)
 {
     ptrdiff_t offset = target - s->code_ptr;
     if (offset == sextract64(offset, 0, 26)) {
@@ -1329,7 +1335,7 @@ static inline void tcg_out_callr(TCGContext *s, TCGReg reg)
     tcg_out_insn(s, 3207, BLR, reg);
 }
 
-static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *target)
+static inline void tcg_out_call(TCGContext *s, const tcg_insn_unit *target)
 {
     ptrdiff_t offset = target - s->code_ptr;
     if (offset == sextract64(offset, 0, 26)) {
@@ -1341,7 +1347,7 @@ static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *target)
 }
 
 void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
-                              uintptr_t addr)
+                              uintptr_t addr, uintptr_t wr_addr)
 {
     tcg_insn_unit i1, i2;
     TCGType rt = TCG_TYPE_I64;
@@ -1362,7 +1368,10 @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
         i2 = I3401_ADDI | rt << 31 | (addr & 0xfff) << 10 | rd << 5 | rd;
     }
     pair = (uint64_t)i2 << 32 | i1;
-    qatomic_set((uint64_t *)jmp_addr, pair);
+    qatomic_set((uint64_t *)wr_addr, pair);
+#if defined(CONFIG_IOS_JIT)
+    flush_dcache_range(wr_addr, wr_addr + 8);
+#endif
     flush_icache_range(jmp_addr, jmp_addr + 8);
 }
 
@@ -1568,7 +1577,7 @@ static void * const qemu_st_helpers[16] = {
     [MO_BEQ]  = helper_be_stq_mmu,
 };
 
-static inline void tcg_out_adr(TCGContext *s, TCGReg rd, void *target)
+static inline void tcg_out_adr(TCGContext *s, TCGReg rd, const void *target)
 {
     ptrdiff_t offset = tcg_pcrel_diff(s, target);
     tcg_debug_assert(offset == sextract64(offset, 0, 21));
@@ -1581,7 +1590,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
     MemOp opc = get_memop(oi);
     MemOp size = opc & MO_SIZE;
 
-    if (!reloc_pc19(lb->label_ptr[0], s->code_ptr)) {
+    if (!reloc_pc19(s, lb->label_ptr[0], s->code_ptr)) {
         return false;
     }
 
@@ -1606,7 +1615,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
     MemOp opc = get_memop(oi);
     MemOp size = opc & MO_SIZE;
 
-    if (!reloc_pc19(lb->label_ptr[0], s->code_ptr)) {
+    if (!reloc_pc19(s, lb->label_ptr[0], s->code_ptr)) {
         return false;
     }
 
@@ -1622,7 +1631,8 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
 
 static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
                                 TCGType ext, TCGReg data_reg, TCGReg addr_reg,
-                                tcg_insn_unit *raddr, tcg_insn_unit *label_ptr)
+                                const tcg_insn_unit *raddr,
+                                tcg_insn_unit *label_ptr)
 {
     TCGLabelQemuLdst *label = new_ldst_label(s);
 
@@ -1849,7 +1859,7 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg,
 #endif /* CONFIG_SOFTMMU */
 }
 
-static tcg_insn_unit *tb_ret_addr;
+static const tcg_insn_unit *tb_ret_addr;
 
 static void tcg_out_op(TCGContext *s, TCGOpcode opc,
                        const TCGArg args[TCG_MAX_OP_ARGS],
@@ -2916,11 +2926,11 @@ static void tcg_target_qemu_prologue(TCGContext *s)
     tcg_out_insn(s, 3207, RET, TCG_REG_LR);
 }
 
-static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
+static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
 {
     int i;
     for (i = 0; i < count; ++i) {
-        p[i] = NOP;
+        (TCG_CODE_PTR_RW(s, p))[i] = NOP;
     }
 }
 
diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h
index a2b22b4305..78c97460a1 100644
--- a/tcg/aarch64/tcg-target.h
+++ b/tcg/aarch64/tcg-target.h
@@ -150,6 +150,7 @@ typedef enum {
 
 #if defined(__APPLE__)
 void sys_icache_invalidate(void *start, size_t len);
+void sys_dcache_flush(void *start, size_t len);
 #endif
 
 static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
@@ -163,7 +164,17 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
 #endif
 }
 
-void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
+void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+#if defined(CONFIG_IOS_JIT)
+static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
+{
+#if defined(__APPLE__)
+    sys_dcache_flush((char *)start, stop - start);
+#else
+#error "Missing function to flush data cache"
+#endif
+}
+#endif
 
 #ifdef CONFIG_SOFTMMU
 #define TCG_TARGET_NEED_LDST_LABELS
diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc
index 62c37a954b..d27ad851b5 100644
--- a/tcg/arm/tcg-target.c.inc
+++ b/tcg/arm/tcg-target.c.inc
@@ -187,17 +187,22 @@ static const uint8_t tcg_cond_to_arm_cond[] = {
     [TCG_COND_GTU] = COND_HI,
 };
 
-static inline bool reloc_pc24(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
+static inline bool reloc_pc24(TCGContext *s,
+                              tcg_insn_unit *code_ptr,
+                              const tcg_insn_unit *target)
 {
     ptrdiff_t offset = (tcg_ptr_byte_diff(target, code_ptr) - 8) >> 2;
     if (offset == sextract32(offset, 0, 24)) {
-        *code_ptr = (*code_ptr & ~0xffffff) | (offset & 0xffffff);
+        *TCG_CODE_PTR_RW(s, code_ptr) =
+            (*TCG_CODE_PTR_RW(s, code_ptr) & ~0xffffff) | (offset & 0xffffff);
         return true;
     }
     return false;
 }
 
-static inline bool reloc_pc13(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
+static inline bool reloc_pc13(TCGContext *s,
+                              tcg_insn_unit *code_ptr,
+                              const tcg_insn_unit *target)
 {
     ptrdiff_t offset = tcg_ptr_byte_diff(target, code_ptr) - 8;
 
@@ -209,21 +214,21 @@ static inline bool reloc_pc13(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
         }
         insn = deposit32(insn, 23, 1, u);
         insn = deposit32(insn, 0, 12, offset);
-        *code_ptr = insn;
+        *TCG_CODE_PTR_RW(s, code_ptr) = insn;
         return true;
     }
     return false;
 }
 
-static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
                         intptr_t value, intptr_t addend)
 {
     tcg_debug_assert(addend == 0);
 
     if (type == R_ARM_PC24) {
-        return reloc_pc24(code_ptr, (tcg_insn_unit *)value);
+        return reloc_pc24(s, code_ptr, (tcg_insn_unit *)value);
     } else if (type == R_ARM_PC13) {
-        return reloc_pc13(code_ptr, (tcg_insn_unit *)value);
+        return reloc_pc13(s, code_ptr, (tcg_insn_unit *)value);
     } else {
         g_assert_not_reached();
     }
@@ -1019,7 +1024,7 @@ static inline void tcg_out_st8(TCGContext *s, int cond,
  * with the code buffer limited to 16MB we wouldn't need the long case.
  * But we also use it for the tail-call to the qemu_ld/st helpers, which does.
  */
-static void tcg_out_goto(TCGContext *s, int cond, tcg_insn_unit *addr)
+static void tcg_out_goto(TCGContext *s, int cond, const tcg_insn_unit *addr)
 {
     intptr_t addri = (intptr_t)addr;
     ptrdiff_t disp = tcg_pcrel_diff(s, addr);
@@ -1033,7 +1038,7 @@ static void tcg_out_goto(TCGContext *s, int cond, tcg_insn_unit *addr)
 
 /* The call case is mostly used for helpers - so it's not unreasonable
  * for them to be beyond branch range */
-static void tcg_out_call(TCGContext *s, tcg_insn_unit *addr)
+static void tcg_out_call(TCGContext *s, const tcg_insn_unit *addr)
 {
     intptr_t addri = (intptr_t)addr;
     ptrdiff_t disp = tcg_pcrel_diff(s, addr);
@@ -1326,7 +1331,7 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addrlo, TCGReg addrhi,
    helper code.  */
 static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
                                 TCGReg datalo, TCGReg datahi, TCGReg addrlo,
-                                TCGReg addrhi, tcg_insn_unit *raddr,
+                                TCGReg addrhi, const tcg_insn_unit *raddr,
                                 tcg_insn_unit *label_ptr)
 {
     TCGLabelQemuLdst *label = new_ldst_label(s);
@@ -1348,7 +1353,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
     MemOp opc = get_memop(oi);
     void *func;
 
-    if (!reloc_pc24(lb->label_ptr[0], s->code_ptr)) {
+    if (!reloc_pc24(s, lb->label_ptr[0], s->code_ptr)) {
         return false;
     }
 
@@ -1411,7 +1416,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
     TCGMemOpIdx oi = lb->oi;
     MemOp opc = get_memop(oi);
 
-    if (!reloc_pc24(lb->label_ptr[0], s->code_ptr)) {
+    if (!reloc_pc24(s, lb->label_ptr[0], s->code_ptr)) {
         return false;
     }
 
@@ -2255,11 +2260,11 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type,
     tcg_out_movi32(s, COND_AL, ret, arg);
 }
 
-static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
+static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
 {
     int i;
     for (i = 0; i < count; ++i) {
-        p[i] = INSN_NOP;
+        (TCG_CODE_PTR_RW(s, p))[i] = INSN_NOP;
     }
 }
 
diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
index 17e771374d..d8d7e7e239 100644
--- a/tcg/arm/tcg-target.h
+++ b/tcg/arm/tcg-target.h
@@ -139,8 +139,15 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
     __builtin___clear_cache((char *) start, (char *) stop);
 }
 
+#if defined(CONFIG_IOS_JIT)
+static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
+{
+#error "Unimplemented dcache flush function"
+}
+#endif
+
 /* not defined -- call should be eliminated at compile time */
-void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
+void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
 
 #ifdef CONFIG_SOFTMMU
 #define TCG_TARGET_NEED_LDST_LABELS
diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc
index d8797ed398..e9c128d9e7 100644
--- a/tcg/i386/tcg-target.c.inc
+++ b/tcg/i386/tcg-target.c.inc
@@ -165,9 +165,9 @@ static bool have_lzcnt;
 # define have_lzcnt 0
 #endif
 
-static tcg_insn_unit *tb_ret_addr;
+static const tcg_insn_unit *tb_ret_addr;
 
-static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
                         intptr_t value, intptr_t addend)
 {
     value += addend;
@@ -179,14 +179,14 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
         }
         /* FALLTHRU */
     case R_386_32:
-        tcg_patch32(code_ptr, value);
+        tcg_patch32(s, code_ptr, value);
         break;
     case R_386_PC8:
         value -= (uintptr_t)code_ptr;
         if (value != (int8_t)value) {
             return false;
         }
-        tcg_patch8(code_ptr, value);
+        tcg_patch8(s, code_ptr, value);
         break;
     default:
         tcg_abort();
@@ -1591,7 +1591,7 @@ static void tcg_out_clz(TCGContext *s, int rexw, TCGReg dest, TCGReg arg1,
     }
 }
 
-static void tcg_out_branch(TCGContext *s, int call, tcg_insn_unit *dest)
+static void tcg_out_branch(TCGContext *s, int call, const tcg_insn_unit *dest)
 {
     intptr_t disp = tcg_pcrel_diff(s, dest) - 5;
 
@@ -1610,12 +1610,12 @@ static void tcg_out_branch(TCGContext *s, int call, tcg_insn_unit *dest)
     }
 }
 
-static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *dest)
+static inline void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest)
 {
     tcg_out_branch(s, 1, dest);
 }
 
-static void tcg_out_jmp(TCGContext *s, tcg_insn_unit *dest)
+static void tcg_out_jmp(TCGContext *s, const tcg_insn_unit *dest)
 {
     tcg_out_branch(s, 0, dest);
 }
@@ -1774,7 +1774,7 @@ static void add_qemu_ldst_label(TCGContext *s, bool is_ld, bool is_64,
                                 TCGMemOpIdx oi,
                                 TCGReg datalo, TCGReg datahi,
                                 TCGReg addrlo, TCGReg addrhi,
-                                tcg_insn_unit *raddr,
+                                const tcg_insn_unit *raddr,
                                 tcg_insn_unit **label_ptr)
 {
     TCGLabelQemuLdst *label = new_ldst_label(s);
@@ -1805,9 +1805,9 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
     int rexw = (l->type == TCG_TYPE_I64 ? P_REXW : 0);
 
     /* resolve label address */
-    tcg_patch32(label_ptr[0], s->code_ptr - label_ptr[0] - 4);
+    tcg_patch32(s, label_ptr[0], s->code_ptr - label_ptr[0] - 4);
     if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
-        tcg_patch32(label_ptr[1], s->code_ptr - label_ptr[1] - 4);
+        tcg_patch32(s, label_ptr[1], s->code_ptr - label_ptr[1] - 4);
     }
 
     if (TCG_TARGET_REG_BITS == 32) {
@@ -1890,9 +1890,9 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
     TCGReg retaddr;
 
     /* resolve label address */
-    tcg_patch32(label_ptr[0], s->code_ptr - label_ptr[0] - 4);
+    tcg_patch32(s, label_ptr[0], s->code_ptr - label_ptr[0] - 4);
     if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
-        tcg_patch32(label_ptr[1], s->code_ptr - label_ptr[1] - 4);
+        tcg_patch32(s, label_ptr[1], s->code_ptr - label_ptr[1] - 4);
     }
 
     if (TCG_TARGET_REG_BITS == 32) {
@@ -3842,9 +3842,9 @@ static void tcg_target_qemu_prologue(TCGContext *s)
     tcg_out_opc(s, OPC_RET, 0, 0, 0);
 }
 
-static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
+static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
 {
-    memset(p, 0x90, count);
+    memset(TCG_CODE_PTR_RW(s, p), 0x90, count);
 }
 
 static void tcg_target_init(TCGContext *s)
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
index abd4ac7fc0..cdc440ce36 100644
--- a/tcg/i386/tcg-target.h
+++ b/tcg/i386/tcg-target.h
@@ -206,16 +206,36 @@ extern bool have_avx2;
 #define TCG_TARGET_extract_i64_valid(ofs, len) \
     (((ofs) == 8 && (len) == 8) || ((ofs) + (len)) == 32)
 
+#ifdef __APPLE__
+void sys_dcache_flush(void *start, size_t len);
+#endif
+
 static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
 {
 }
 
+#if defined(CONFIG_IOS_JIT)
+static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
+{
+#if defined(__APPLE__)
+    sys_dcache_flush((char *)start, stop - start);
+#else
+#error "Missing function to flush data cache"
+#endif
+}
+#endif
+
 static inline void tb_target_set_jmp_target(uintptr_t tc_ptr,
-                                            uintptr_t jmp_addr, uintptr_t addr)
+                                            uintptr_t jmp_addr, uintptr_t addr,
+                                            uintptr_t wr_addr)
 {
     /* patch the branch destination */
-    qatomic_set((int32_t *)jmp_addr, addr - (jmp_addr + 4));
+    qatomic_set((int32_t *)wr_addr, addr - (jmp_addr + 4));
     /* no need to flush icache explicitly */
+#if defined(CONFIG_IOS_JIT)
+    /* we do need to flush mirror dcache */
+    flush_dcache_range(wr_addr, wr_addr + 4);
+#endif
 }
 
 /* This defines the natural memory order supported by this
diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc
index 41be574e89..e798527437 100644
--- a/tcg/mips/tcg-target.c.inc
+++ b/tcg/mips/tcg-target.c.inc
@@ -139,12 +139,13 @@ static const TCGReg tcg_target_call_oarg_regs[2] = {
     TCG_REG_V1
 };
 
-static tcg_insn_unit *tb_ret_addr;
-static tcg_insn_unit *bswap32_addr;
-static tcg_insn_unit *bswap32u_addr;
-static tcg_insn_unit *bswap64_addr;
+static const tcg_insn_unit *tb_ret_addr;
+static const tcg_insn_unit *bswap32_addr;
+static const tcg_insn_unit *bswap32u_addr;
+static const tcg_insn_unit *bswap64_addr;
 
-static inline uint32_t reloc_pc16_val(tcg_insn_unit *pc, tcg_insn_unit *target)
+static inline uint32_t reloc_pc16_val(const tcg_insn_unit *pc,
+                                      const tcg_insn_unit *target)
 {
     /* Let the compiler perform the right-shift as part of the arithmetic.  */
     ptrdiff_t disp = target - (pc + 1);
@@ -152,28 +153,35 @@ static inline uint32_t reloc_pc16_val(tcg_insn_unit *pc, tcg_insn_unit *target)
     return disp & 0xffff;
 }
 
-static inline void reloc_pc16(tcg_insn_unit *pc, tcg_insn_unit *target)
+static inline void reloc_pc16(TCGContext *s,
+                              tcg_insn_unit *pc,
+                              const tcg_insn_unit *target)
 {
-    *pc = deposit32(*pc, 0, 16, reloc_pc16_val(pc, target));
+    *TCG_CODE_PTR_RW(s, pc) =
+        deposit32(*TCG_CODE_PTR_RW(s, pc), 0, 16, reloc_pc16_val(pc, target));
 }
 
-static inline uint32_t reloc_26_val(tcg_insn_unit *pc, tcg_insn_unit *target)
+static inline uint32_t reloc_26_val(const tcg_insn_unit *pc,
+                                    const tcg_insn_unit *target)
 {
     tcg_debug_assert((((uintptr_t)pc ^ (uintptr_t)target) & 0xf0000000) == 0);
     return ((uintptr_t)target >> 2) & 0x3ffffff;
 }
 
-static inline void reloc_26(tcg_insn_unit *pc, tcg_insn_unit *target)
+static inline void reloc_26(TCGContext *s,
+                            tcg_insn_unit *pc,
+                            const tcg_insn_unit *target)
 {
-    *pc = deposit32(*pc, 0, 26, reloc_26_val(pc, target));
+    *TCG_CODE_PTR_RW(s, pc) =
+        deposit32(*TCG_CODE_PTR_RW(s, pc), 0, 26, reloc_26_val(pc, target));
 }
 
-static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
                         intptr_t value, intptr_t addend)
 {
     tcg_debug_assert(type == R_MIPS_PC16);
     tcg_debug_assert(addend == 0);
-    reloc_pc16(code_ptr, (tcg_insn_unit *)value);
+    reloc_pc16(s, code_ptr, (tcg_insn_unit *)value);
     return true;
 }
 
@@ -516,7 +524,7 @@ static void tcg_out_opc_sa64(TCGContext *s, MIPSInsn opc1, MIPSInsn opc2,
  * Type jump.
  * Returns true if the branch was in range and the insn was emitted.
  */
-static bool tcg_out_opc_jmp(TCGContext *s, MIPSInsn opc, void *target)
+static bool tcg_out_opc_jmp(TCGContext *s, MIPSInsn opc, const void *target)
 {
     uintptr_t dest = (uintptr_t)target;
     uintptr_t from = (uintptr_t)s->code_ptr + 4;
@@ -631,7 +639,7 @@ static inline void tcg_out_bswap16s(TCGContext *s, TCGReg ret, TCGReg arg)
     }
 }
 
-static void tcg_out_bswap_subr(TCGContext *s, tcg_insn_unit *sub)
+static void tcg_out_bswap_subr(TCGContext *s, const tcg_insn_unit *sub)
 {
     bool ok = tcg_out_opc_jmp(s, OPC_JAL, sub);
     tcg_debug_assert(ok);
@@ -925,7 +933,7 @@ static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1,
 
     tcg_out_opc_br(s, b_opc, arg1, arg2);
     if (l->has_value) {
-        reloc_pc16(s->code_ptr - 1, l->u.value_ptr);
+        reloc_pc16(s, s->code_ptr - 1, l->u.value_ptr);
     } else {
         tcg_out_reloc(s, s->code_ptr - 1, R_MIPS_PC16, l, 0);
     }
@@ -1079,7 +1087,7 @@ static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret,
     }
 }
 
-static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
+static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail)
 {
     /* Note that the ABI requires the called function's address to be
        loaded into T9, even if a direct branch is in range.  */
@@ -1097,7 +1105,7 @@ static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
     }
 }
 
-static void tcg_out_call(TCGContext *s, tcg_insn_unit *arg)
+static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg)
 {
     tcg_out_call_int(s, arg, false);
     tcg_out_nop(s);
@@ -1289,7 +1297,8 @@ static void add_qemu_ldst_label(TCGContext *s, int is_ld, TCGMemOpIdx oi,
                                 TCGType ext,
                                 TCGReg datalo, TCGReg datahi,
                                 TCGReg addrlo, TCGReg addrhi,
-                                void *raddr, tcg_insn_unit *label_ptr[2])
+                                const tcg_insn_unit *raddr,
+                                tcg_insn_unit *label_ptr[2])
 {
     TCGLabelQemuLdst *label = new_ldst_label(s);
 
@@ -1315,9 +1324,9 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
     int i;
 
     /* resolve label address */
-    reloc_pc16(l->label_ptr[0], s->code_ptr);
+    reloc_pc16(s, l->label_ptr[0], s->code_ptr);
     if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) {
-        reloc_pc16(l->label_ptr[1], s->code_ptr);
+        reloc_pc16(s, l->label_ptr[1], s->code_ptr);
     }
 
     i = 1;
@@ -1345,7 +1354,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
     }
 
     tcg_out_opc_br(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO);
-    reloc_pc16(s->code_ptr - 1, l->raddr);
+    reloc_pc16(s, s->code_ptr - 1, l->raddr);
 
     /* delay slot */
     if (TCG_TARGET_REG_BITS == 64 && l->type == TCG_TYPE_I32) {
@@ -1365,9 +1374,9 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
     int i;
 
     /* resolve label address */
-    reloc_pc16(l->label_ptr[0], s->code_ptr);
+    reloc_pc16(s, l->label_ptr[0], s->code_ptr);
     if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) {
-        reloc_pc16(l->label_ptr[1], s->code_ptr);
+        reloc_pc16(s, l->label_ptr[1], s->code_ptr);
     }
 
     i = 1;
@@ -2430,7 +2439,7 @@ static void tcg_target_detect_isa(void)
     sigaction(SIGILL, &sa_old, NULL);
 }
 
-static tcg_insn_unit *align_code_ptr(TCGContext *s)
+static const tcg_insn_unit *align_code_ptr(TCGContext *s)
 {
     uintptr_t p = (uintptr_t)s->code_ptr;
     if (p & 15) {
@@ -2657,9 +2666,12 @@ static void tcg_target_init(TCGContext *s)
 }
 
 void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
-                              uintptr_t addr)
+                              uintptr_t addr, uintptr_t wr_addr)
 {
-    qatomic_set((uint32_t *)jmp_addr, deposit32(OPC_J, 0, 26, addr >> 2));
+    qatomic_set((uint32_t *)wr_addr, deposit32(OPC_J, 0, 26, addr >> 2));
+#if defined(CONFIG_IOS_JIT)
+    flush_dcache_range(wr_addr, wr_addr + 4);
+#endif
     flush_icache_range(jmp_addr, jmp_addr + 4);
 }
 
diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
index c6b091d849..80dcba5358 100644
--- a/tcg/mips/tcg-target.h
+++ b/tcg/mips/tcg-target.h
@@ -212,7 +212,13 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
     cacheflush ((void *)start, stop-start, ICACHE);
 }
 
-void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
+void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+#if defined(CONFIG_IOS_JIT)
+static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
+{
+#error "Unimplemented dcache flush function"
+}
+#endif
 
 #ifdef CONFIG_SOFTMMU
 #define TCG_TARGET_NEED_LDST_LABELS
diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc
index 18ee989f95..f5a44e9852 100644
--- a/tcg/ppc/tcg-target.c.inc
+++ b/tcg/ppc/tcg-target.c.inc
@@ -62,7 +62,7 @@
 #define TCG_CT_CONST_MONE 0x2000
 #define TCG_CT_CONST_WSZ  0x4000
 
-static tcg_insn_unit *tb_ret_addr;
+static const tcg_insn_unit *tb_ret_addr;
 
 TCGPowerISA have_isa;
 static bool have_isel;
@@ -184,35 +184,43 @@ static inline bool in_range_b(tcg_target_long target)
     return target == sextract64(target, 0, 26);
 }
 
-static uint32_t reloc_pc24_val(tcg_insn_unit *pc, tcg_insn_unit *target)
+static uint32_t reloc_pc24_val(const tcg_insn_unit *pc,
+                               const tcg_insn_unit *target)
 {
     ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
     tcg_debug_assert(in_range_b(disp));
     return disp & 0x3fffffc;
 }
 
-static bool reloc_pc24(tcg_insn_unit *pc, tcg_insn_unit *target)
+static bool reloc_pc24(TCGContext *s,
+                       tcg_insn_unit *pc,
+                       const tcg_insn_unit *target)
 {
     ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
     if (in_range_b(disp)) {
-        *pc = (*pc & ~0x3fffffc) | (disp & 0x3fffffc);
+        *TCG_CODE_PTR_RW(s, pc) =
+            (*TCG_CODE_PTR_RW(s, pc) & ~0x3fffffc) | (disp & 0x3fffffc);
         return true;
     }
     return false;
 }
 
-static uint16_t reloc_pc14_val(tcg_insn_unit *pc, tcg_insn_unit *target)
+static uint16_t reloc_pc14_val(const tcg_insn_unit *pc,
+                               const tcg_insn_unit *target)
 {
     ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
     tcg_debug_assert(disp == (int16_t) disp);
     return disp & 0xfffc;
 }
 
-static bool reloc_pc14(tcg_insn_unit *pc, tcg_insn_unit *target)
+static bool reloc_pc14(TCGContext *s,
+                       tcg_insn_unit *pc,
+                       const tcg_insn_unit *target)
 {
     ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
     if (disp == (int16_t) disp) {
-        *pc = (*pc & ~0xfffc) | (disp & 0xfffc);
+        *TCG_CODE_PTR_RW(s, pc) =
+            (*TCG_CODE_PTR_RW(s, pc) & ~0xfffc) | (disp & 0xfffc);
         return true;
     }
     return false;
@@ -670,7 +678,7 @@ static const uint32_t tcg_to_isel[] = {
     [TCG_COND_GTU] = ISEL | BC_(7, CR_GT),
 };
 
-static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
                         intptr_t value, intptr_t addend)
 {
     tcg_insn_unit *target;
@@ -682,9 +690,9 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
 
     switch (type) {
     case R_PPC_REL14:
-        return reloc_pc14(code_ptr, target);
+        return reloc_pc14(s, code_ptr, target);
     case R_PPC_REL24:
-        return reloc_pc24(code_ptr, target);
+        return reloc_pc24(s, code_ptr, target);
     case R_PPC_ADDR16:
         /*
          * We are (slightly) abusing this relocation type.  In particular,
@@ -1106,7 +1114,7 @@ static void tcg_out_xori32(TCGContext *s, TCGReg dst, TCGReg src, uint32_t c)
     tcg_out_zori32(s, dst, src, c, XORI, XORIS);
 }
 
-static void tcg_out_b(TCGContext *s, int mask, tcg_insn_unit *target)
+static void tcg_out_b(TCGContext *s, int mask, const tcg_insn_unit *target)
 {
     ptrdiff_t disp = tcg_pcrel_diff(s, target);
     if (in_range_b(disp)) {
@@ -1723,7 +1731,7 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0)
 }
 
 void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
-                              uintptr_t addr)
+                              uintptr_t addr, uintptr_t wr_addr)
 {
     if (TCG_TARGET_REG_BITS == 64) {
         tcg_insn_unit i1, i2;
@@ -1752,17 +1760,23 @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
 
         /* As per the enclosing if, this is ppc64.  Avoid the _Static_assert
            within qatomic_set that would fail to build a ppc32 host.  */
-        qatomic_set__nocheck((uint64_t *)jmp_addr, pair);
+        qatomic_set__nocheck((uint64_t *)wr_addr, pair);
+#if defined(CONFIG_IOS_JIT)
+        flush_dcache_range(wr_addr, wr_addr + 8);
+#endif
         flush_icache_range(jmp_addr, jmp_addr + 8);
     } else {
         intptr_t diff = addr - jmp_addr;
         tcg_debug_assert(in_range_b(diff));
-        qatomic_set((uint32_t *)jmp_addr, B | (diff & 0x3fffffc));
+        qatomic_set((uint32_t *)wr_addr, B | (diff & 0x3fffffc));
+#if defined(CONFIG_IOS_JIT)
+        flush_dcache_range(wr_addr, wr_addr + 8);
+#endif
         flush_icache_range(jmp_addr, jmp_addr + 4);
     }
 }
 
-static void tcg_out_call(TCGContext *s, tcg_insn_unit *target)
+static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target)
 {
 #ifdef _CALL_AIX
     /* Look through the descriptor.  If the branch is in range, and we
@@ -1987,7 +2001,8 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, MemOp opc,
 static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
                                 TCGReg datalo_reg, TCGReg datahi_reg,
                                 TCGReg addrlo_reg, TCGReg addrhi_reg,
-                                tcg_insn_unit *raddr, tcg_insn_unit *lptr)
+                                const tcg_insn_unit *raddr,
+                                tcg_insn_unit *lptr)
 {
     TCGLabelQemuLdst *label = new_ldst_label(s);
 
@@ -2007,7 +2022,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
     MemOp opc = get_memop(oi);
     TCGReg hi, lo, arg = TCG_REG_R3;
 
-    if (!reloc_pc14(lb->label_ptr[0], s->code_ptr)) {
+    if (!reloc_pc14(s, lb->label_ptr[0], s->code_ptr)) {
         return false;
     }
 
@@ -2055,7 +2070,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
     MemOp s_bits = opc & MO_SIZE;
     TCGReg hi, lo, arg = TCG_REG_R3;
 
-    if (!reloc_pc14(lb->label_ptr[0], s->code_ptr)) {
+    if (!reloc_pc14(s, lb->label_ptr[0], s->code_ptr)) {
         return false;
     }
 
@@ -2252,11 +2267,11 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
 #endif
 }
 
-static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
+static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
 {
     int i;
     for (i = 0; i < count; ++i) {
-        p[i] = NOP;
+        (TCG_CODE_PTR_RW(s, p))[i] = NOP;
     }
 }
 
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
index be10363956..23d7a337c9 100644
--- a/tcg/ppc/tcg-target.h
+++ b/tcg/ppc/tcg-target.h
@@ -176,7 +176,13 @@ extern bool have_vsx;
 #define TCG_TARGET_HAS_cmpsel_vec       0
 
 void flush_icache_range(uintptr_t start, uintptr_t stop);
-void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
+void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+#if defined(CONFIG_IOS_JIT)
+static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
+{
+#error "Unimplemented dcache flush function"
+}
+#endif
 
 #define TCG_TARGET_DEFAULT_MO (0)
 #define TCG_TARGET_HAS_MEMORY_BSWAP     1
diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc
index d536f3ccc1..2d96c83c4b 100644
--- a/tcg/riscv/tcg-target.c.inc
+++ b/tcg/riscv/tcg-target.c.inc
@@ -413,11 +413,11 @@ static void tcg_out_opc_jump(TCGContext *s, RISCVInsn opc,
     tcg_out32(s, encode_uj(opc, rd, imm));
 }
 
-static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
+static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
 {
     int i;
     for (i = 0; i < count; ++i) {
-        p[i] = encode_i(OPC_ADDI, TCG_REG_ZERO, TCG_REG_ZERO, 0);
+        (TCG_CODE_PTR_RW(s, p))[i] = encode_i(OPC_ADDI, TCG_REG_ZERO, TCG_REG_ZERO, 0);
     }
 }
 
@@ -425,46 +425,52 @@ static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
  * Relocations
  */
 
-static bool reloc_sbimm12(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
+static bool reloc_sbimm12(TCGContext *s,
+                          tcg_insn_unit *code_ptr,
+                          const tcg_insn_unit *target)
 {
     intptr_t offset = (intptr_t)target - (intptr_t)code_ptr;
 
     if (offset == sextreg(offset, 1, 12) << 1) {
-        code_ptr[0] |= encode_sbimm12(offset);
+        (TCG_CODE_PTR_RW(s, code_ptr))[0] |= encode_sbimm12(offset);
         return true;
     }
 
     return false;
 }
 
-static bool reloc_jimm20(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
+static bool reloc_jimm20(TCGContext *s,
+                         tcg_insn_unit *code_ptr,
+                         const tcg_insn_unit *target)
 {
     intptr_t offset = (intptr_t)target - (intptr_t)code_ptr;
 
     if (offset == sextreg(offset, 1, 20) << 1) {
-        code_ptr[0] |= encode_ujimm20(offset);
+        (TCG_CODE_PTR_RW(s, code_ptr))[0] |= encode_ujimm20(offset);
         return true;
     }
 
     return false;
 }
 
-static bool reloc_call(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
+static bool reloc_call(TCGContext *s,
+                       tcg_insn_unit *code_ptr,
+                       const tcg_insn_unit *target)
 {
     intptr_t offset = (intptr_t)target - (intptr_t)code_ptr;
     int32_t lo = sextreg(offset, 0, 12);
     int32_t hi = offset - lo;
 
     if (offset == hi + lo) {
-        code_ptr[0] |= encode_uimm20(hi);
-        code_ptr[1] |= encode_imm12(lo);
+        (TCG_CODE_PTR_RW(s, code_ptr))[0] |= encode_uimm20(hi);
+        (TCG_CODE_PTR_RW(s, code_ptr))[1] |= encode_imm12(lo);
         return true;
     }
 
     return false;
 }
 
-static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
                         intptr_t value, intptr_t addend)
 {
     uint32_t insn = *code_ptr;
@@ -478,7 +484,7 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
         diff = value - (uintptr_t)code_ptr;
         short_jmp = diff == sextreg(diff, 0, 12);
         if (short_jmp) {
-            return reloc_sbimm12(code_ptr, (tcg_insn_unit *)value);
+            return reloc_sbimm12(s, code_ptr, (tcg_insn_unit *)value);
         } else {
             /* Invert the condition */
             insn = insn ^ (1 << 12);
@@ -499,9 +505,9 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
         }
         break;
     case R_RISCV_JAL:
-        return reloc_jimm20(code_ptr, (tcg_insn_unit *)value);
+        return reloc_jimm20(s, code_ptr, (tcg_insn_unit *)value);
     case R_RISCV_CALL:
-        return reloc_call(code_ptr, (tcg_insn_unit *)value);
+        return reloc_call(s, code_ptr, (tcg_insn_unit *)value);
     default:
         tcg_abort();
     }
@@ -557,7 +563,7 @@ static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd,
     if (tmp == (int32_t)tmp) {
         tcg_out_opc_upper(s, OPC_AUIPC, rd, 0);
         tcg_out_opc_imm(s, OPC_ADDI, rd, rd, 0);
-        ret = reloc_call(s->code_ptr - 2, (tcg_insn_unit *)val);
+        ret = reloc_call(s, s->code_ptr - 2, (tcg_insn_unit *)val);
         tcg_debug_assert(ret == true);
         return;
     }
@@ -854,14 +860,14 @@ static void tcg_out_setcond2(TCGContext *s, TCGCond cond, TCGReg ret,
     g_assert_not_reached();
 }
 
-static inline void tcg_out_goto(TCGContext *s, tcg_insn_unit *target)
+static inline void tcg_out_goto(TCGContext *s, const tcg_insn_unit *target)
 {
     ptrdiff_t offset = tcg_pcrel_diff(s, target);
     tcg_debug_assert(offset == sextreg(offset, 1, 20) << 1);
     tcg_out_opc_jump(s, OPC_JAL, TCG_REG_ZERO, offset);
 }
 
-static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
+static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail)
 {
     TCGReg link = tail ? TCG_REG_ZERO : TCG_REG_RA;
     ptrdiff_t offset = tcg_pcrel_diff(s, arg);
@@ -875,7 +881,7 @@ static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
         /* long jump: -2147483646 to 2147483648 */
         tcg_out_opc_upper(s, OPC_AUIPC, TCG_REG_TMP0, 0);
         tcg_out_opc_imm(s, OPC_JALR, link, TCG_REG_TMP0, 0);
-        ret = reloc_call(s->code_ptr - 2, arg);\
+        ret = reloc_call(s, s->code_ptr - 2, arg);\
         tcg_debug_assert(ret == true);
     } else if (TCG_TARGET_REG_BITS == 64) {
         /* far jump: 64-bit */
@@ -888,7 +894,7 @@ static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
     }
 }
 
-static void tcg_out_call(TCGContext *s, tcg_insn_unit *arg)
+static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg)
 {
     tcg_out_call_int(s, arg, false);
 }
@@ -1022,7 +1028,8 @@ static void add_qemu_ldst_label(TCGContext *s, int is_ld, TCGMemOpIdx oi,
                                 TCGType ext,
                                 TCGReg datalo, TCGReg datahi,
                                 TCGReg addrlo, TCGReg addrhi,
-                                void *raddr, tcg_insn_unit **label_ptr)
+                                const tcg_insn_unit *raddr,
+                                tcg_insn_unit **label_ptr)
 {
     TCGLabelQemuLdst *label = new_ldst_label(s);
 
@@ -1052,7 +1059,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
     }
 
     /* resolve label address */
-    if (!patch_reloc(l->label_ptr[0], R_RISCV_BRANCH,
+    if (!patch_reloc(s, l->label_ptr[0], R_RISCV_BRANCH,
                      (intptr_t) s->code_ptr, 0)) {
         return false;
     }
@@ -1087,7 +1094,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
     }
 
     /* resolve label address */
-    if (!patch_reloc(l->label_ptr[0], R_RISCV_BRANCH,
+    if (!patch_reloc(s, l->label_ptr[0], R_RISCV_BRANCH,
                      (intptr_t) s->code_ptr, 0)) {
         return false;
     }
@@ -1274,7 +1281,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
 #endif
 }
 
-static tcg_insn_unit *tb_ret_addr;
+static const tcg_insn_unit *tb_ret_addr;
 
 static void tcg_out_op(TCGContext *s, TCGOpcode opc,
                        const TCGArg *args, const int *const_args)
diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h
index 032439d806..d42b361991 100644
--- a/tcg/riscv/tcg-target.h
+++ b/tcg/riscv/tcg-target.h
@@ -164,8 +164,15 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
     __builtin___clear_cache((char *)start, (char *)stop);
 }
 
+#if defined(CONFIG_IOS_JIT)
+static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
+{
+#error "Unimplemented dcache flush function"
+}
+#endif
+
 /* not defined -- call should be eliminated at compile time */
-void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
+void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
 
 #define TCG_TARGET_DEFAULT_MO (0)
 
diff --git a/tcg/s390/tcg-target.c.inc b/tcg/s390/tcg-target.c.inc
index c5e096449b..49a96ca15f 100644
--- a/tcg/s390/tcg-target.c.inc
+++ b/tcg/s390/tcg-target.c.inc
@@ -363,10 +363,10 @@ static void * const qemu_st_helpers[16] = {
 };
 #endif
 
-static tcg_insn_unit *tb_ret_addr;
+static const tcg_insn_unit *tb_ret_addr;
 uint64_t s390_facilities;
 
-static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
                         intptr_t value, intptr_t addend)
 {
     intptr_t pcrel2;
@@ -378,13 +378,13 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
     switch (type) {
     case R_390_PC16DBL:
         if (pcrel2 == (int16_t)pcrel2) {
-            tcg_patch16(code_ptr, pcrel2);
+            tcg_patch16(s, code_ptr, pcrel2);
             return true;
         }
         break;
     case R_390_PC32DBL:
         if (pcrel2 == (int32_t)pcrel2) {
-            tcg_patch32(code_ptr, pcrel2);
+            tcg_patch32(s, code_ptr, pcrel2);
             return true;
         }
         break;
@@ -392,7 +392,7 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
         if (value == sextract64(value, 0, 20)) {
             old = *(uint32_t *)code_ptr & 0xf00000ff;
             old |= ((value & 0xfff) << 16) | ((value & 0xff000) >> 4);
-            tcg_patch32(code_ptr, old);
+            tcg_patch32(s, code_ptr, old);
             return true;
         }
         break;
@@ -1302,7 +1302,7 @@ static void tgen_extract(TCGContext *s, TCGReg dest, TCGReg src,
     tcg_out_risbg(s, dest, src, 64 - len, 63, 64 - ofs, 1);
 }
 
-static void tgen_gotoi(TCGContext *s, int cc, tcg_insn_unit *dest)
+static void tgen_gotoi(TCGContext *s, int cc, const tcg_insn_unit *dest)
 {
     ptrdiff_t off = dest - s->code_ptr;
     if (off == (int16_t)off) {
@@ -1415,7 +1415,7 @@ static void tgen_brcond(TCGContext *s, TCGType type, TCGCond c,
     tgen_branch(s, cc, l);
 }
 
-static void tcg_out_call(TCGContext *s, tcg_insn_unit *dest)
+static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest)
 {
     ptrdiff_t off = dest - s->code_ptr;
     if (off == (int32_t)off) {
@@ -1593,7 +1593,8 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, MemOp opc,
 
 static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
                                 TCGReg data, TCGReg addr,
-                                tcg_insn_unit *raddr, tcg_insn_unit *label_ptr)
+                                const tcg_insn_unit *raddr,
+                                tcg_insn_unit *label_ptr)
 {
     TCGLabelQemuLdst *label = new_ldst_label(s);
 
@@ -1612,7 +1613,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
     TCGMemOpIdx oi = lb->oi;
     MemOp opc = get_memop(oi);
 
-    if (!patch_reloc(lb->label_ptr[0], R_390_PC16DBL,
+    if (!patch_reloc(s, lb->label_ptr[0], R_390_PC16DBL,
                      (intptr_t)s->code_ptr, 2)) {
         return false;
     }
@@ -1637,7 +1638,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
     TCGMemOpIdx oi = lb->oi;
     MemOp opc = get_memop(oi);
 
-    if (!patch_reloc(lb->label_ptr[0], R_390_PC16DBL,
+    if (!patch_reloc(s, lb->label_ptr[0], R_390_PC16DBL,
                      (intptr_t)s->code_ptr, 2)) {
         return false;
     }
@@ -2575,9 +2576,9 @@ static void tcg_target_qemu_prologue(TCGContext *s)
     tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_REG_R14);
 }
 
-static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
+static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
 {
-    memset(p, 0x07, count * sizeof(tcg_insn_unit));
+    memset(TCG_CODE_PTR_RW(s, p), 0x07, count * sizeof(tcg_insn_unit));
 }
 
 typedef struct {
diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h
index 63c8797bd3..d67632512d 100644
--- a/tcg/s390/tcg-target.h
+++ b/tcg/s390/tcg-target.h
@@ -149,13 +149,24 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
 {
 }
 
+#if defined(CONFIG_IOS_JIT)
+static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
+{
+#error "Unimplemented dcache flush function"
+}
+#endif
+
 static inline void tb_target_set_jmp_target(uintptr_t tc_ptr,
-                                            uintptr_t jmp_addr, uintptr_t addr)
+                                            uintptr_t jmp_addr, uintptr_t addr,
+                                            uintptr_t wr_addr)
 {
     /* patch the branch destination */
     intptr_t disp = addr - (jmp_addr - 2);
     qatomic_set((int32_t *)jmp_addr, disp / 2);
     /* no need to flush icache explicitly */
+#if defined(CONFIG_IOS_JIT)
+    flush_dcache_range(wr_addr, wr_addr + 4);
+#endif
 }
 
 #ifdef CONFIG_SOFTMMU
diff --git a/tcg/sparc/tcg-target.c.inc b/tcg/sparc/tcg-target.c.inc
index 6775bd30fc..af97cbdeef 100644
--- a/tcg/sparc/tcg-target.c.inc
+++ b/tcg/sparc/tcg-target.c.inc
@@ -291,14 +291,14 @@ static inline int check_fit_i32(int32_t val, unsigned int bits)
 # define check_fit_ptr  check_fit_i32
 #endif
 
-static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
                         intptr_t value, intptr_t addend)
 {
     uint32_t insn = *code_ptr;
     intptr_t pcrel;
 
     value += addend;
-    pcrel = tcg_ptr_byte_diff((tcg_insn_unit *)value, code_ptr);
+    pcrel = tcg_ptr_byte_diff((const tcg_insn_unit *)value, code_ptr);
 
     switch (type) {
     case R_SPARC_WDISP16:
@@ -840,7 +840,7 @@ static void tcg_out_addsub2_i64(TCGContext *s, TCGReg rl, TCGReg rh,
     tcg_out_mov(s, TCG_TYPE_I64, rl, tmp);
 }
 
-static void tcg_out_call_nodelay(TCGContext *s, tcg_insn_unit *dest,
+static void tcg_out_call_nodelay(TCGContext *s, const tcg_insn_unit *dest,
                                  bool in_prologue)
 {
     ptrdiff_t disp = tcg_pcrel_diff(s, dest);
@@ -855,7 +855,7 @@ static void tcg_out_call_nodelay(TCGContext *s, tcg_insn_unit *dest,
     }
 }
 
-static void tcg_out_call(TCGContext *s, tcg_insn_unit *dest)
+static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest)
 {
     tcg_out_call_nodelay(s, dest, false);
     tcg_out_nop(s);
@@ -868,8 +868,8 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0)
 }
 
 #ifdef CONFIG_SOFTMMU
-static tcg_insn_unit *qemu_ld_trampoline[16];
-static tcg_insn_unit *qemu_st_trampoline[16];
+static const tcg_insn_unit *qemu_ld_trampoline[16];
+static const tcg_insn_unit *qemu_st_trampoline[16];
 
 static void emit_extend(TCGContext *s, TCGReg r, int op)
 {
@@ -1048,11 +1048,11 @@ static void tcg_target_qemu_prologue(TCGContext *s)
 #endif
 }
 
-static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
+static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
 {
     int i;
     for (i = 0; i < count; ++i) {
-        p[i] = NOP;
+        (TCG_CODE_PTR_RW(s, p))[i] = NOP;
     }
 }
 
@@ -1163,7 +1163,7 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr,
 #ifdef CONFIG_SOFTMMU
     unsigned memi = get_mmuidx(oi);
     TCGReg addrz, param;
-    tcg_insn_unit *func;
+    const tcg_insn_unit *func;
     tcg_insn_unit *label_ptr;
 
     addrz = tcg_out_tlb_load(s, addr, memi, memop,
@@ -1226,7 +1226,8 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr,
         }
     }
 
-    *label_ptr |= INSN_OFF19(tcg_ptr_byte_diff(s->code_ptr, label_ptr));
+    *TCG_CODE_PTR_RW(s, label_ptr) |=
+        INSN_OFF19(tcg_ptr_byte_diff(s->code_ptr, label_ptr));
 #else
     if (SPARC64 && TARGET_LONG_BITS == 32) {
         tcg_out_arithi(s, TCG_REG_T1, addr, 0, SHIFT_SRL);
@@ -1822,7 +1823,7 @@ void tcg_register_jit(void *buf, size_t buf_size)
 }
 
 void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
-                              uintptr_t addr)
+                              uintptr_t addr, uintptr_t wr_addr)
 {
     intptr_t tb_disp = addr - tc_ptr;
     intptr_t br_disp = addr - jmp_addr;
@@ -1834,8 +1835,11 @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
     tcg_debug_assert(br_disp == (int32_t)br_disp);
 
     if (!USE_REG_TB) {
-        qatomic_set((uint32_t *)jmp_addr,
+        qatomic_set((uint32_t *)wr_addr,
 		    deposit32(CALL, 0, 30, br_disp >> 2));
+#if defined(CONFIG_IOS_JIT)
+        flush_dcache_range(wr_addr, wr_addr + 4);
+#endif
         flush_icache_range(jmp_addr, jmp_addr + 4);
         return;
     }
@@ -1859,6 +1863,9 @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
               | INSN_IMM13((tb_disp & 0x3ff) | -0x400));
     }
 
-    qatomic_set((uint64_t *)jmp_addr, deposit64(i2, 32, 32, i1));
+    qatomic_set((uint64_t *)wr_addr, deposit64(i2, 32, 32, i1));
+#if defined(CONFIG_IOS_JIT)
+    flush_dcache_range(wr_addr, wr_addr + 8);
+#endif
     flush_icache_range(jmp_addr, jmp_addr + 8);
 }
diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h
index 633841ebf2..d102e13692 100644
--- a/tcg/sparc/tcg-target.h
+++ b/tcg/sparc/tcg-target.h
@@ -176,7 +176,13 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
     }
 }
 
-void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
+void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+#if defined(CONFIG_IOS_JIT)
+static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
+{
+#error "Unimplemented dcache flush function"
+}
+#endif
 
 #define TCG_TARGET_NEED_POOL_LABELS
 
diff --git a/tcg/tcg-ldst.c.inc b/tcg/tcg-ldst.c.inc
index 05f9b3ccd6..eaba08700e 100644
--- a/tcg/tcg-ldst.c.inc
+++ b/tcg/tcg-ldst.c.inc
@@ -28,7 +28,7 @@ typedef struct TCGLabelQemuLdst {
     TCGReg addrhi_reg;      /* reg index for high word of guest virtual addr */
     TCGReg datalo_reg;      /* reg index for low word to be loaded or stored */
     TCGReg datahi_reg;      /* reg index for high word to be loaded or stored */
-    tcg_insn_unit *raddr;   /* gen code addr of the next IR of qemu_ld/st IR */
+    const tcg_insn_unit *raddr; /* gen code addr of the next IR of qemu_ld/st */
     tcg_insn_unit *label_ptr[2]; /* label pointers to be updated */
     QSIMPLEQ_ENTRY(TCGLabelQemuLdst) next;
 } TCGLabelQemuLdst;
diff --git a/tcg/tcg-pool.c.inc b/tcg/tcg-pool.c.inc
index 82cbcc89bd..97bb90b7cc 100644
--- a/tcg/tcg-pool.c.inc
+++ b/tcg/tcg-pool.c.inc
@@ -119,7 +119,7 @@ static inline void new_pool_l8(TCGContext *s, int rtype, tcg_insn_unit *label,
 }
 
 /* To be provided by cpu/tcg-target.c.inc.  */
-static void tcg_out_nop_fill(tcg_insn_unit *p, int count);
+static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count);
 
 static int tcg_out_pool_finalize(TCGContext *s)
 {
@@ -135,7 +135,7 @@ static int tcg_out_pool_finalize(TCGContext *s)
        again when allocating the next TranslationBlock structure.  */
     a = (void *)ROUND_UP((uintptr_t)s->code_ptr,
                          sizeof(tcg_target_ulong) * p->nlong);
-    tcg_out_nop_fill(s->code_ptr, (tcg_insn_unit *)a - s->code_ptr);
+    tcg_out_nop_fill(s, s->code_ptr, (tcg_insn_unit *)a - s->code_ptr);
     s->data_gen_ptr = a;
 
     for (; p != NULL; p = p->next) {
@@ -144,11 +144,12 @@ static int tcg_out_pool_finalize(TCGContext *s)
             if (unlikely(a > s->code_gen_highwater)) {
                 return -1;
             }
-            memcpy(a, p->data, size);
+            memcpy(TCG_CODE_PTR_RW(s, a), p->data, size);
             a += size;
             l = p;
         }
-        if (!patch_reloc(p->label, p->rtype, (intptr_t)a - size, p->addend)) {
+        if (!patch_reloc(s, p->label, p->rtype,
+                         (intptr_t)a - size, p->addend)) {
             return -2;
         }
     }
diff --git a/tcg/tcg.c b/tcg/tcg.c
index a8c28440e2..ef203a34a6 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -70,7 +70,7 @@
 static void tcg_target_init(TCGContext *s);
 static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode);
 static void tcg_target_qemu_prologue(TCGContext *s);
-static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
                         intptr_t value, intptr_t addend);
 
 /* The CIE and FDE header definitions will be common to all hosts.  */
@@ -148,7 +148,7 @@ static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
                        intptr_t arg2);
 static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
                         TCGReg base, intptr_t ofs);
-static void tcg_out_call(TCGContext *s, tcg_insn_unit *target);
+static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target);
 static int tcg_target_const_match(tcg_target_long val, TCGType type,
                                   const TCGArgConstraint *arg_ct);
 #ifdef TCG_TARGET_NEED_LDST_LABELS
@@ -203,13 +203,15 @@ static TCGRegSet tcg_target_call_clobber_regs;
 #if TCG_TARGET_INSN_UNIT_SIZE == 1
 static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
 {
-    *s->code_ptr++ = v;
+    *TCG_CODE_PTR_RW(s, s->code_ptr) = v;
+    s->code_ptr++;
 }
 
-static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
+static __attribute__((unused)) inline void tcg_patch8(TCGContext *s,
+                                                      tcg_insn_unit *p,
                                                       uint8_t v)
 {
-    *p = v;
+    *TCG_CODE_PTR_RW(s, p) = v;
 }
 #endif
 
@@ -217,21 +219,23 @@ static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
 static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
 {
     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
-        *s->code_ptr++ = v;
+        *TCG_CODE_PTR_RW(s, s->code_ptr) = v;
+        s->code_ptr++;
     } else {
         tcg_insn_unit *p = s->code_ptr;
-        memcpy(p, &v, sizeof(v));
+        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
     }
 }
 
-static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
+static __attribute__((unused)) inline void tcg_patch16(TCGContext *s,
+                                                       tcg_insn_unit *p,
                                                        uint16_t v)
 {
     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
-        *p = v;
+        *TCG_CODE_PTR_RW(s, p) = v;
     } else {
-        memcpy(p, &v, sizeof(v));
+        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
     }
 }
 #endif
@@ -240,21 +244,23 @@ static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
 static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
 {
     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
-        *s->code_ptr++ = v;
+        *TCG_CODE_PTR_RW(s, s->code_ptr) = v;
+        s->code_ptr++;
     } else {
         tcg_insn_unit *p = s->code_ptr;
-        memcpy(p, &v, sizeof(v));
+        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
     }
 }
 
-static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
+static __attribute__((unused)) inline void tcg_patch32(TCGContext *s,
+                                                       tcg_insn_unit *p,
                                                        uint32_t v)
 {
     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
         *p = v;
     } else {
-        memcpy(p, &v, sizeof(v));
+        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
     }
 }
 #endif
@@ -263,21 +269,23 @@ static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
 static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
 {
     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
-        *s->code_ptr++ = v;
+        *TCG_CODE_PTR_RW(s, s->code_ptr) = v;
+        s->code_ptr++;
     } else {
         tcg_insn_unit *p = s->code_ptr;
-        memcpy(p, &v, sizeof(v));
+        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
     }
 }
 
-static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
+static __attribute__((unused)) inline void tcg_patch64(TCGContext *s,
+                                                       tcg_insn_unit *p,
                                                        uint64_t v)
 {
     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
         *p = v;
     } else {
-        memcpy(p, &v, sizeof(v));
+        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
     }
 }
 #endif
@@ -295,7 +303,7 @@ static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
 }
 
-static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr)
+static void tcg_out_label(TCGContext *s, TCGLabel *l, const tcg_insn_unit *ptr)
 {
     tcg_debug_assert(!l->has_value);
     l->has_value = 1;
@@ -325,7 +333,7 @@ static bool tcg_resolve_relocs(TCGContext *s)
         uintptr_t value = l->u.value;
 
         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
-            if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
+            if (!patch_reloc(s, r->ptr, r->type, value, r->addend)) {
                 return false;
             }
         }
@@ -1039,7 +1047,7 @@ TranslationBlock *tcg_tb_alloc(TCGContext *s)
     }
     qatomic_set(&s->code_gen_ptr, next);
     s->data_gen_ptr = NULL;
-    return tb;
+    return (TranslationBlock *)TCG_CODE_PTR_RW(s, tb);
 }
 
 void tcg_prologue_init(TCGContext *s)
@@ -1076,6 +1084,10 @@ void tcg_prologue_init(TCGContext *s)
 #endif
 
     buf1 = s->code_ptr;
+#if defined(CONFIG_IOS_JIT)
+    flush_dcache_range((uintptr_t)TCG_CODE_PTR_RW(s, buf0),
+                       (uintptr_t)TCG_CODE_PTR_RW(s, buf1));
+#endif
     flush_icache_range((uintptr_t)buf0, (uintptr_t)buf1);
 
     /* Deduct the prologue from the buffer.  */
@@ -4267,6 +4279,12 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
         return -2;
     }
 
+#if defined(CONFIG_IOS_JIT)
+    /* flush data cache on mirror */
+    flush_dcache_range((uintptr_t)TCG_CODE_PTR_RW(s, s->code_buf),
+                       (uintptr_t)TCG_CODE_PTR_RW(s, s->code_ptr));
+#endif
+
     /* flush instruction cache */
     flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr);
 
diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc
index 231b9b1775..133213be3a 100644
--- a/tcg/tci/tcg-target.c.inc
+++ b/tcg/tci/tcg-target.c.inc
@@ -369,7 +369,7 @@ static const char *const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
 };
 #endif
 
-static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
                         intptr_t value, intptr_t addend)
 {
     /* tcg_out_reloc always uses the same type, addend. */
@@ -377,9 +377,9 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
     tcg_debug_assert(addend == 0);
     tcg_debug_assert(value != 0);
     if (TCG_TARGET_REG_BITS == 32) {
-        tcg_patch32(code_ptr, value);
+        tcg_patch32(s, code_ptr, value);
     } else {
-        tcg_patch64(code_ptr, value);
+        tcg_patch64(s, code_ptr, value);
     }
     return true;
 }
@@ -545,7 +545,7 @@ static void tcg_out_movi(TCGContext *s, TCGType type,
     old_code_ptr[1] = s->code_ptr - old_code_ptr;
 }
 
-static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *arg)
+static inline void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg)
 {
     uint8_t *old_code_ptr = s->code_ptr;
     tcg_out_op_t(s, INDEX_op_call);
diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h
index 8c1c1d265d..2a258ea350 100644
--- a/tcg/tci/tcg-target.h
+++ b/tcg/tci/tcg-target.h
@@ -195,6 +195,12 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
 {
 }
 
+#if defined(CONFIG_IOS_JIT)
+static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
+{
+}
+#endif
+
 /* We could notice __i386__ or __s390x__ and reduce the barriers depending
    on the host.  But if you want performance, you use the normal backend.
    We prefer consistency across hosts on this.  */
@@ -203,7 +209,8 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
 #define TCG_TARGET_HAS_MEMORY_BSWAP     1
 
 static inline void tb_target_set_jmp_target(uintptr_t tc_ptr,
-                                            uintptr_t jmp_addr, uintptr_t addr)
+                                            uintptr_t jmp_addr, uintptr_t addr,
+                                            uintptr_t wr_addr)
 {
     /* patch the branch destination */
     qatomic_set((int32_t *)jmp_addr, addr - (jmp_addr + 4));
-- 
2.24.3 (Apple Git-128)



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 07/10] tcg: implement bulletproof JIT
@ 2020-10-12 23:29   ` Joelle van Dyne
  0 siblings, 0 replies; 47+ messages in thread
From: Joelle van Dyne @ 2020-10-12 23:29 UTC (permalink / raw)
  To: qemu-devel
  Cc: Joelle van Dyne, Richard Henderson, Paolo Bonzini,
	Andrzej Zaborowski, Aleksandar Markovic, Aurelien Jarno,
	Huacai Chen, Jiaxun Yang, Aleksandar Rikalo, Palmer Dabbelt,
	Alistair Francis, Stefan Weil, open list:AArch64 TCG target,
	open list:RISC-V TCG target, open list:S390 TCG target

From: osy <osy86@users.noreply.github.com>

On iOS, we cannot allocate RWX pages without special entitlements. As a
workaround, we can a RX region and then mirror map it to a separate RX
region. Then we can write to one region and execute from the other one.

To better keep track of pointers to RW/RX memory, we mark any tcg_insn_unit
pointers as `const` if they will never be written to. We also define a new
macro `TCG_CODE_PTR_RW` that returns a pointer to RW memory. Only the
difference between the two regions is stored in the TCG context.

To ensure cache coherency, we flush the data cache in the RW mapping and
then invalidate the instruction cache in the RX mapping (where applicable).
Because data cache flush is OS defined on some architectures, we do not
provide implementations for non iOS platforms (ARM/x86).

Signed-off-by: Joelle van Dyne <j@getutm.app>
---
 accel/tcg/cpu-exec.c         |  7 +++-
 accel/tcg/translate-all.c    | 78 ++++++++++++++++++++++++++++++++++--
 configure                    |  1 +
 docs/devel/ios.rst           | 40 ++++++++++++++++++
 include/exec/exec-all.h      |  8 ++++
 include/tcg/tcg.h            | 18 +++++++--
 tcg/aarch64/tcg-target.c.inc | 48 +++++++++++++---------
 tcg/aarch64/tcg-target.h     | 13 +++++-
 tcg/arm/tcg-target.c.inc     | 33 ++++++++-------
 tcg/arm/tcg-target.h         |  9 ++++-
 tcg/i386/tcg-target.c.inc    | 28 ++++++-------
 tcg/i386/tcg-target.h        | 24 ++++++++++-
 tcg/mips/tcg-target.c.inc    | 64 +++++++++++++++++------------
 tcg/mips/tcg-target.h        |  8 +++-
 tcg/ppc/tcg-target.c.inc     | 55 ++++++++++++++++---------
 tcg/ppc/tcg-target.h         |  8 +++-
 tcg/riscv/tcg-target.c.inc   | 51 +++++++++++++----------
 tcg/riscv/tcg-target.h       |  9 ++++-
 tcg/s390/tcg-target.c.inc    | 25 ++++++------
 tcg/s390/tcg-target.h        | 13 +++++-
 tcg/sparc/tcg-target.c.inc   | 33 +++++++++------
 tcg/sparc/tcg-target.h       |  8 +++-
 tcg/tcg-ldst.c.inc           |  2 +-
 tcg/tcg-pool.c.inc           |  9 +++--
 tcg/tcg.c                    | 60 +++++++++++++++++----------
 tcg/tci/tcg-target.c.inc     |  8 ++--
 tcg/tci/tcg-target.h         |  9 ++++-
 27 files changed, 481 insertions(+), 188 deletions(-)
 create mode 100644 docs/devel/ios.rst

diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index 58aea605d8..821aefdea2 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -354,7 +354,12 @@ void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr)
     if (TCG_TARGET_HAS_direct_jump) {
         uintptr_t offset = tb->jmp_target_arg[n];
         uintptr_t tc_ptr = (uintptr_t)tb->tc.ptr;
-        tb_target_set_jmp_target(tc_ptr, tc_ptr + offset, addr);
+#if defined(CONFIG_IOS_JIT)
+        uintptr_t wr_addr = tc_ptr + offset + tb->code_rw_mirror_diff;
+#else
+        uintptr_t wr_addr = tc_ptr + offset;
+#endif
+        tb_target_set_jmp_target(tc_ptr, tc_ptr + offset, addr, wr_addr);
     } else {
         tb->jmp_target_arg[n] = addr;
     }
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index d76097296d..76d8dc3d7b 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -60,6 +60,22 @@
 #include "sysemu/cpu-timers.h"
 #include "sysemu/tcg.h"
 
+#if defined(CONFIG_IOS_JIT)
+#include <mach/mach.h>
+extern kern_return_t mach_vm_remap(vm_map_t target_task,
+                                   mach_vm_address_t *target_address,
+                                   mach_vm_size_t size,
+                                   mach_vm_offset_t mask,
+                                   int flags,
+                                   vm_map_t src_task,
+                                   mach_vm_address_t src_address,
+                                   boolean_t copy,
+                                   vm_prot_t *cur_protection,
+                                   vm_prot_t *max_protection,
+                                   vm_inherit_t inheritance
+                                  );
+#endif
+
 /* #define DEBUG_TB_INVALIDATE */
 /* #define DEBUG_TB_FLUSH */
 /* make various TB consistency checks */
@@ -302,10 +318,13 @@ static target_long decode_sleb128(uint8_t **pp)
 
 static int encode_search(TranslationBlock *tb, uint8_t *block)
 {
-    uint8_t *highwater = tcg_ctx->code_gen_highwater;
-    uint8_t *p = block;
+    uint8_t *highwater;
+    uint8_t *p;
     int i, j, n;
 
+    highwater = (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx,
+                                           tcg_ctx->code_gen_highwater);
+    p = (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx, block);
     for (i = 0, n = tb->icount; i < n; ++i) {
         target_ulong prev;
 
@@ -329,7 +348,7 @@ static int encode_search(TranslationBlock *tb, uint8_t *block)
         }
     }
 
-    return p - block;
+    return p - (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx, block);
 }
 
 /* The cpu state corresponding to 'searched_pc' is restored.
@@ -1067,7 +1086,11 @@ static inline void *alloc_code_gen_buffer(void)
 #else
 static inline void *alloc_code_gen_buffer(void)
 {
+#if defined(CONFIG_IOS_JIT)
+    int prot = PROT_READ | PROT_EXEC;
+#else
     int prot = PROT_WRITE | PROT_READ | PROT_EXEC;
+#endif
     int flags = MAP_PRIVATE | MAP_ANONYMOUS;
     size_t size = tcg_ctx->code_gen_buffer_size;
     void *buf;
@@ -1118,6 +1141,39 @@ static inline void *alloc_code_gen_buffer(void)
 }
 #endif /* USE_STATIC_CODE_GEN_BUFFER, WIN32, POSIX */
 
+#if defined(CONFIG_IOS_JIT)
+static inline void *alloc_jit_rw_mirror(void *base, size_t size)
+{
+    kern_return_t ret;
+    mach_vm_address_t mirror;
+    vm_prot_t cur_prot, max_prot;
+
+    mirror = 0;
+    ret = mach_vm_remap(mach_task_self(),
+                        &mirror,
+                        size,
+                        0,
+                        VM_FLAGS_ANYWHERE | VM_FLAGS_RANDOM_ADDR,
+                        mach_task_self(),
+                        (mach_vm_address_t)base,
+                        false,
+                        &cur_prot,
+                        &max_prot,
+                        VM_INHERIT_NONE
+                       );
+    if (ret != KERN_SUCCESS) {
+        return NULL;
+    }
+
+    if (mprotect((void *)mirror, size, PROT_READ | PROT_WRITE) != 0) {
+        munmap((void *)mirror, size);
+        return NULL;
+    }
+
+    return (void *)mirror;
+}
+#endif /* CONFIG_IOS_JIT */
+
 static inline void code_gen_alloc(size_t tb_size)
 {
     tcg_ctx->code_gen_buffer_size = size_code_gen_buffer(tb_size);
@@ -1126,6 +1182,19 @@ static inline void code_gen_alloc(size_t tb_size)
         fprintf(stderr, "Could not allocate dynamic translator buffer\n");
         exit(1);
     }
+#if defined(CONFIG_IOS_JIT)
+    void *mirror;
+
+    /* For iOS JIT we need a mirror mapping for code execution */
+    mirror = alloc_jit_rw_mirror(tcg_ctx->code_gen_buffer,
+                                 tcg_ctx->code_gen_buffer_size
+                                );
+    if (mirror == NULL) {
+        fprintf(stderr, "Could not remap code buffer mirror\n");
+        exit(1);
+    }
+    tcg_ctx->code_rw_mirror_diff = mirror - tcg_ctx->code_gen_buffer;
+#endif /* CONFIG_IOS_JIT */
 }
 
 static bool tb_cmp(const void *ap, const void *bp)
@@ -1721,6 +1790,9 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
         cpu_loop_exit(cpu);
     }
 
+#if defined(CONFIG_IOS_JIT)
+    tb->code_rw_mirror_diff = tcg_ctx->code_rw_mirror_diff;
+#endif
     gen_code_buf = tcg_ctx->code_gen_ptr;
     tb->tc.ptr = gen_code_buf;
     tb->pc = pc;
diff --git a/configure b/configure
index 16c66b437c..c5a6584683 100755
--- a/configure
+++ b/configure
@@ -6220,6 +6220,7 @@ fi
 
 if test "$ios" = "yes" ; then
   echo "CONFIG_IOS=y" >> $config_host_mak
+  echo "CONFIG_IOS_JIT=y" >> $config_host_mak
 fi
 
 if test "$solaris" = "yes" ; then
diff --git a/docs/devel/ios.rst b/docs/devel/ios.rst
new file mode 100644
index 0000000000..dba9fdd868
--- /dev/null
+++ b/docs/devel/ios.rst
@@ -0,0 +1,40 @@
+===========
+iOS Support
+===========
+
+To run qemu on the iOS platform, some modifications were required. Most of the
+modifications are conditioned on the ``CONFIG_IOS`` and ``CONFIG_IOS_JIT``
+configuration variables.
+
+Build support
+-------------
+
+For the code to compile, certain changes in the block driver and the slirp
+driver had to be made. There is no ``system()`` call, so code requiring it had
+to be disabled.
+
+``ucontext`` support is broken on iOS. The implementation from ``libucontext``
+is used instead.
+
+Because ``fork()`` is not allowed on iOS apps, the option to build qemu and the
+utilities as shared libraries is added. Note that because qemu does not perform
+resource cleanup in most cases (open files, allocated memory, etc), it is
+advisable that the user implements a proxy layer for syscalls so resources can
+be kept track by the app that uses qemu as a shared library.
+
+JIT support
+-----------
+
+On iOS, allocating RWX pages require special entitlements not usually granted to
+apps. However, it is possible to use `bulletproof JIT`_ with a development
+certificate. This means that we need to allocate one chunk of memory with RX
+permissions and then mirror map the same memory with RW permissions. We generate
+code to the mirror mapping and execute the original mapping.
+
+With ``CONFIG_IOS_JIT`` defined, we store inside the TCG context the difference
+between the two mappings. Then, we make sure that any writes to JIT memory is
+done to the pointer + the difference (in order to get a pointer to the mirror
+mapped space). Additionally, we make sure to flush the data cache before we
+invalidate the instruction cache so the changes are seen in both mappings.
+
+.. _bulletproof JIT: https://www.blackhat.com/docs/us-16/materials/us-16-Krstic.pdf
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 66f9b4cca6..2db155a772 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -483,6 +483,14 @@ struct TranslationBlock {
     uintptr_t jmp_list_head;
     uintptr_t jmp_list_next[2];
     uintptr_t jmp_dest[2];
+
+#if defined(CONFIG_IOS_JIT)
+    /*
+     * Store difference to writable mirror
+     * We need this when patching the jump instructions
+     */
+    ptrdiff_t code_rw_mirror_diff;
+#endif
 };
 
 extern bool parallel_cpus;
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
index 8804a8c4a2..40d1a7a85e 100644
--- a/include/tcg/tcg.h
+++ b/include/tcg/tcg.h
@@ -261,7 +261,7 @@ struct TCGLabel {
     unsigned refs : 16;
     union {
         uintptr_t value;
-        tcg_insn_unit *value_ptr;
+        const tcg_insn_unit *value_ptr;
     } u;
     QSIMPLEQ_HEAD(, TCGRelocation) relocs;
     QSIMPLEQ_ENTRY(TCGLabel) next;
@@ -593,7 +593,7 @@ struct TCGContext {
     int nb_ops;
 
     /* goto_tb support */
-    tcg_insn_unit *code_buf;
+    const tcg_insn_unit *code_buf;
     uint16_t *tb_jmp_reset_offset; /* tb->jmp_reset_offset */
     uintptr_t *tb_jmp_insn_offset; /* tb->jmp_target_arg if direct_jump */
     uintptr_t *tb_jmp_target_addr; /* tb->jmp_target_arg if !direct_jump */
@@ -627,6 +627,9 @@ struct TCGContext {
     size_t code_gen_buffer_size;
     void *code_gen_ptr;
     void *data_gen_ptr;
+#if defined(CONFIG_IOS_JIT)
+    ptrdiff_t code_rw_mirror_diff;
+#endif
 
     /* Threshold to flush the translated code buffer.  */
     void *code_gen_highwater;
@@ -677,6 +680,13 @@ struct TCGContext {
     target_ulong gen_insn_data[TCG_MAX_INSNS][TARGET_INSN_START_WORDS];
 };
 
+#if defined(CONFIG_IOS_JIT)
+# define TCG_CODE_PTR_RW(s, code_ptr) \
+    (tcg_insn_unit *)((uintptr_t)(code_ptr) + (s)->code_rw_mirror_diff)
+#else
+# define TCG_CODE_PTR_RW(s, code_ptr) (code_ptr)
+#endif
+
 extern TCGContext tcg_init_ctx;
 extern __thread TCGContext *tcg_ctx;
 extern TCGv_env cpu_env;
@@ -1099,7 +1109,7 @@ static inline TCGLabel *arg_label(TCGArg i)
  * correct result.
  */
 
-static inline ptrdiff_t tcg_ptr_byte_diff(void *a, void *b)
+static inline ptrdiff_t tcg_ptr_byte_diff(const void *a, const void *b)
 {
     return a - b;
 }
@@ -1113,7 +1123,7 @@ static inline ptrdiff_t tcg_ptr_byte_diff(void *a, void *b)
  * to the destination address.
  */
 
-static inline ptrdiff_t tcg_pcrel_diff(TCGContext *s, void *target)
+static inline ptrdiff_t tcg_pcrel_diff(TCGContext *s, const void *target)
 {
     return tcg_ptr_byte_diff(target, s->code_ptr);
 }
diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc
index 26f71cb599..9cfa2703b3 100644
--- a/tcg/aarch64/tcg-target.c.inc
+++ b/tcg/aarch64/tcg-target.c.inc
@@ -78,38 +78,44 @@ static const int tcg_target_call_oarg_regs[1] = {
 #define TCG_REG_GUEST_BASE TCG_REG_X28
 #endif
 
-static inline bool reloc_pc26(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
+static inline bool reloc_pc26(TCGContext *s,
+                              tcg_insn_unit *code_ptr,
+                              const tcg_insn_unit *target)
 {
     ptrdiff_t offset = target - code_ptr;
     if (offset == sextract64(offset, 0, 26)) {
         /* read instruction, mask away previous PC_REL26 parameter contents,
            set the proper offset, then write back the instruction. */
-        *code_ptr = deposit32(*code_ptr, 0, 26, offset);
+        *TCG_CODE_PTR_RW(s, code_ptr) =
+            deposit32(*TCG_CODE_PTR_RW(s, code_ptr), 0, 26, offset);
         return true;
     }
     return false;
 }
 
-static inline bool reloc_pc19(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
+static inline bool reloc_pc19(TCGContext *s,
+                              tcg_insn_unit *code_ptr,
+                              const tcg_insn_unit *target)
 {
     ptrdiff_t offset = target - code_ptr;
     if (offset == sextract64(offset, 0, 19)) {
-        *code_ptr = deposit32(*code_ptr, 5, 19, offset);
+        *TCG_CODE_PTR_RW(s, code_ptr) =
+            deposit32(*TCG_CODE_PTR_RW(s, code_ptr), 5, 19, offset);
         return true;
     }
     return false;
 }
 
-static inline bool patch_reloc(tcg_insn_unit *code_ptr, int type,
+static inline bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
                                intptr_t value, intptr_t addend)
 {
     tcg_debug_assert(addend == 0);
     switch (type) {
     case R_AARCH64_JUMP26:
     case R_AARCH64_CALL26:
-        return reloc_pc26(code_ptr, (tcg_insn_unit *)value);
+        return reloc_pc26(s, code_ptr, (tcg_insn_unit *)value);
     case R_AARCH64_CONDBR19:
-        return reloc_pc19(code_ptr, (tcg_insn_unit *)value);
+        return reloc_pc19(s, code_ptr, (tcg_insn_unit *)value);
     default:
         g_assert_not_reached();
     }
@@ -1306,14 +1312,14 @@ static void tcg_out_cmp(TCGContext *s, TCGType ext, TCGReg a,
     }
 }
 
-static inline void tcg_out_goto(TCGContext *s, tcg_insn_unit *target)
+static inline void tcg_out_goto(TCGContext *s, const tcg_insn_unit *target)
 {
     ptrdiff_t offset = target - s->code_ptr;
     tcg_debug_assert(offset == sextract64(offset, 0, 26));
     tcg_out_insn(s, 3206, B, offset);
 }
 
-static inline void tcg_out_goto_long(TCGContext *s, tcg_insn_unit *target)
+static inline void tcg_out_goto_long(TCGContext *s, const tcg_insn_unit *target)
 {
     ptrdiff_t offset = target - s->code_ptr;
     if (offset == sextract64(offset, 0, 26)) {
@@ -1329,7 +1335,7 @@ static inline void tcg_out_callr(TCGContext *s, TCGReg reg)
     tcg_out_insn(s, 3207, BLR, reg);
 }
 
-static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *target)
+static inline void tcg_out_call(TCGContext *s, const tcg_insn_unit *target)
 {
     ptrdiff_t offset = target - s->code_ptr;
     if (offset == sextract64(offset, 0, 26)) {
@@ -1341,7 +1347,7 @@ static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *target)
 }
 
 void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
-                              uintptr_t addr)
+                              uintptr_t addr, uintptr_t wr_addr)
 {
     tcg_insn_unit i1, i2;
     TCGType rt = TCG_TYPE_I64;
@@ -1362,7 +1368,10 @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
         i2 = I3401_ADDI | rt << 31 | (addr & 0xfff) << 10 | rd << 5 | rd;
     }
     pair = (uint64_t)i2 << 32 | i1;
-    qatomic_set((uint64_t *)jmp_addr, pair);
+    qatomic_set((uint64_t *)wr_addr, pair);
+#if defined(CONFIG_IOS_JIT)
+    flush_dcache_range(wr_addr, wr_addr + 8);
+#endif
     flush_icache_range(jmp_addr, jmp_addr + 8);
 }
 
@@ -1568,7 +1577,7 @@ static void * const qemu_st_helpers[16] = {
     [MO_BEQ]  = helper_be_stq_mmu,
 };
 
-static inline void tcg_out_adr(TCGContext *s, TCGReg rd, void *target)
+static inline void tcg_out_adr(TCGContext *s, TCGReg rd, const void *target)
 {
     ptrdiff_t offset = tcg_pcrel_diff(s, target);
     tcg_debug_assert(offset == sextract64(offset, 0, 21));
@@ -1581,7 +1590,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
     MemOp opc = get_memop(oi);
     MemOp size = opc & MO_SIZE;
 
-    if (!reloc_pc19(lb->label_ptr[0], s->code_ptr)) {
+    if (!reloc_pc19(s, lb->label_ptr[0], s->code_ptr)) {
         return false;
     }
 
@@ -1606,7 +1615,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
     MemOp opc = get_memop(oi);
     MemOp size = opc & MO_SIZE;
 
-    if (!reloc_pc19(lb->label_ptr[0], s->code_ptr)) {
+    if (!reloc_pc19(s, lb->label_ptr[0], s->code_ptr)) {
         return false;
     }
 
@@ -1622,7 +1631,8 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
 
 static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
                                 TCGType ext, TCGReg data_reg, TCGReg addr_reg,
-                                tcg_insn_unit *raddr, tcg_insn_unit *label_ptr)
+                                const tcg_insn_unit *raddr,
+                                tcg_insn_unit *label_ptr)
 {
     TCGLabelQemuLdst *label = new_ldst_label(s);
 
@@ -1849,7 +1859,7 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg,
 #endif /* CONFIG_SOFTMMU */
 }
 
-static tcg_insn_unit *tb_ret_addr;
+static const tcg_insn_unit *tb_ret_addr;
 
 static void tcg_out_op(TCGContext *s, TCGOpcode opc,
                        const TCGArg args[TCG_MAX_OP_ARGS],
@@ -2916,11 +2926,11 @@ static void tcg_target_qemu_prologue(TCGContext *s)
     tcg_out_insn(s, 3207, RET, TCG_REG_LR);
 }
 
-static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
+static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
 {
     int i;
     for (i = 0; i < count; ++i) {
-        p[i] = NOP;
+        (TCG_CODE_PTR_RW(s, p))[i] = NOP;
     }
 }
 
diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h
index a2b22b4305..78c97460a1 100644
--- a/tcg/aarch64/tcg-target.h
+++ b/tcg/aarch64/tcg-target.h
@@ -150,6 +150,7 @@ typedef enum {
 
 #if defined(__APPLE__)
 void sys_icache_invalidate(void *start, size_t len);
+void sys_dcache_flush(void *start, size_t len);
 #endif
 
 static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
@@ -163,7 +164,17 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
 #endif
 }
 
-void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
+void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+#if defined(CONFIG_IOS_JIT)
+static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
+{
+#if defined(__APPLE__)
+    sys_dcache_flush((char *)start, stop - start);
+#else
+#error "Missing function to flush data cache"
+#endif
+}
+#endif
 
 #ifdef CONFIG_SOFTMMU
 #define TCG_TARGET_NEED_LDST_LABELS
diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc
index 62c37a954b..d27ad851b5 100644
--- a/tcg/arm/tcg-target.c.inc
+++ b/tcg/arm/tcg-target.c.inc
@@ -187,17 +187,22 @@ static const uint8_t tcg_cond_to_arm_cond[] = {
     [TCG_COND_GTU] = COND_HI,
 };
 
-static inline bool reloc_pc24(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
+static inline bool reloc_pc24(TCGContext *s,
+                              tcg_insn_unit *code_ptr,
+                              const tcg_insn_unit *target)
 {
     ptrdiff_t offset = (tcg_ptr_byte_diff(target, code_ptr) - 8) >> 2;
     if (offset == sextract32(offset, 0, 24)) {
-        *code_ptr = (*code_ptr & ~0xffffff) | (offset & 0xffffff);
+        *TCG_CODE_PTR_RW(s, code_ptr) =
+            (*TCG_CODE_PTR_RW(s, code_ptr) & ~0xffffff) | (offset & 0xffffff);
         return true;
     }
     return false;
 }
 
-static inline bool reloc_pc13(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
+static inline bool reloc_pc13(TCGContext *s,
+                              tcg_insn_unit *code_ptr,
+                              const tcg_insn_unit *target)
 {
     ptrdiff_t offset = tcg_ptr_byte_diff(target, code_ptr) - 8;
 
@@ -209,21 +214,21 @@ static inline bool reloc_pc13(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
         }
         insn = deposit32(insn, 23, 1, u);
         insn = deposit32(insn, 0, 12, offset);
-        *code_ptr = insn;
+        *TCG_CODE_PTR_RW(s, code_ptr) = insn;
         return true;
     }
     return false;
 }
 
-static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
                         intptr_t value, intptr_t addend)
 {
     tcg_debug_assert(addend == 0);
 
     if (type == R_ARM_PC24) {
-        return reloc_pc24(code_ptr, (tcg_insn_unit *)value);
+        return reloc_pc24(s, code_ptr, (tcg_insn_unit *)value);
     } else if (type == R_ARM_PC13) {
-        return reloc_pc13(code_ptr, (tcg_insn_unit *)value);
+        return reloc_pc13(s, code_ptr, (tcg_insn_unit *)value);
     } else {
         g_assert_not_reached();
     }
@@ -1019,7 +1024,7 @@ static inline void tcg_out_st8(TCGContext *s, int cond,
  * with the code buffer limited to 16MB we wouldn't need the long case.
  * But we also use it for the tail-call to the qemu_ld/st helpers, which does.
  */
-static void tcg_out_goto(TCGContext *s, int cond, tcg_insn_unit *addr)
+static void tcg_out_goto(TCGContext *s, int cond, const tcg_insn_unit *addr)
 {
     intptr_t addri = (intptr_t)addr;
     ptrdiff_t disp = tcg_pcrel_diff(s, addr);
@@ -1033,7 +1038,7 @@ static void tcg_out_goto(TCGContext *s, int cond, tcg_insn_unit *addr)
 
 /* The call case is mostly used for helpers - so it's not unreasonable
  * for them to be beyond branch range */
-static void tcg_out_call(TCGContext *s, tcg_insn_unit *addr)
+static void tcg_out_call(TCGContext *s, const tcg_insn_unit *addr)
 {
     intptr_t addri = (intptr_t)addr;
     ptrdiff_t disp = tcg_pcrel_diff(s, addr);
@@ -1326,7 +1331,7 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addrlo, TCGReg addrhi,
    helper code.  */
 static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
                                 TCGReg datalo, TCGReg datahi, TCGReg addrlo,
-                                TCGReg addrhi, tcg_insn_unit *raddr,
+                                TCGReg addrhi, const tcg_insn_unit *raddr,
                                 tcg_insn_unit *label_ptr)
 {
     TCGLabelQemuLdst *label = new_ldst_label(s);
@@ -1348,7 +1353,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
     MemOp opc = get_memop(oi);
     void *func;
 
-    if (!reloc_pc24(lb->label_ptr[0], s->code_ptr)) {
+    if (!reloc_pc24(s, lb->label_ptr[0], s->code_ptr)) {
         return false;
     }
 
@@ -1411,7 +1416,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
     TCGMemOpIdx oi = lb->oi;
     MemOp opc = get_memop(oi);
 
-    if (!reloc_pc24(lb->label_ptr[0], s->code_ptr)) {
+    if (!reloc_pc24(s, lb->label_ptr[0], s->code_ptr)) {
         return false;
     }
 
@@ -2255,11 +2260,11 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type,
     tcg_out_movi32(s, COND_AL, ret, arg);
 }
 
-static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
+static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
 {
     int i;
     for (i = 0; i < count; ++i) {
-        p[i] = INSN_NOP;
+        (TCG_CODE_PTR_RW(s, p))[i] = INSN_NOP;
     }
 }
 
diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
index 17e771374d..d8d7e7e239 100644
--- a/tcg/arm/tcg-target.h
+++ b/tcg/arm/tcg-target.h
@@ -139,8 +139,15 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
     __builtin___clear_cache((char *) start, (char *) stop);
 }
 
+#if defined(CONFIG_IOS_JIT)
+static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
+{
+#error "Unimplemented dcache flush function"
+}
+#endif
+
 /* not defined -- call should be eliminated at compile time */
-void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
+void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
 
 #ifdef CONFIG_SOFTMMU
 #define TCG_TARGET_NEED_LDST_LABELS
diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc
index d8797ed398..e9c128d9e7 100644
--- a/tcg/i386/tcg-target.c.inc
+++ b/tcg/i386/tcg-target.c.inc
@@ -165,9 +165,9 @@ static bool have_lzcnt;
 # define have_lzcnt 0
 #endif
 
-static tcg_insn_unit *tb_ret_addr;
+static const tcg_insn_unit *tb_ret_addr;
 
-static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
                         intptr_t value, intptr_t addend)
 {
     value += addend;
@@ -179,14 +179,14 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
         }
         /* FALLTHRU */
     case R_386_32:
-        tcg_patch32(code_ptr, value);
+        tcg_patch32(s, code_ptr, value);
         break;
     case R_386_PC8:
         value -= (uintptr_t)code_ptr;
         if (value != (int8_t)value) {
             return false;
         }
-        tcg_patch8(code_ptr, value);
+        tcg_patch8(s, code_ptr, value);
         break;
     default:
         tcg_abort();
@@ -1591,7 +1591,7 @@ static void tcg_out_clz(TCGContext *s, int rexw, TCGReg dest, TCGReg arg1,
     }
 }
 
-static void tcg_out_branch(TCGContext *s, int call, tcg_insn_unit *dest)
+static void tcg_out_branch(TCGContext *s, int call, const tcg_insn_unit *dest)
 {
     intptr_t disp = tcg_pcrel_diff(s, dest) - 5;
 
@@ -1610,12 +1610,12 @@ static void tcg_out_branch(TCGContext *s, int call, tcg_insn_unit *dest)
     }
 }
 
-static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *dest)
+static inline void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest)
 {
     tcg_out_branch(s, 1, dest);
 }
 
-static void tcg_out_jmp(TCGContext *s, tcg_insn_unit *dest)
+static void tcg_out_jmp(TCGContext *s, const tcg_insn_unit *dest)
 {
     tcg_out_branch(s, 0, dest);
 }
@@ -1774,7 +1774,7 @@ static void add_qemu_ldst_label(TCGContext *s, bool is_ld, bool is_64,
                                 TCGMemOpIdx oi,
                                 TCGReg datalo, TCGReg datahi,
                                 TCGReg addrlo, TCGReg addrhi,
-                                tcg_insn_unit *raddr,
+                                const tcg_insn_unit *raddr,
                                 tcg_insn_unit **label_ptr)
 {
     TCGLabelQemuLdst *label = new_ldst_label(s);
@@ -1805,9 +1805,9 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
     int rexw = (l->type == TCG_TYPE_I64 ? P_REXW : 0);
 
     /* resolve label address */
-    tcg_patch32(label_ptr[0], s->code_ptr - label_ptr[0] - 4);
+    tcg_patch32(s, label_ptr[0], s->code_ptr - label_ptr[0] - 4);
     if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
-        tcg_patch32(label_ptr[1], s->code_ptr - label_ptr[1] - 4);
+        tcg_patch32(s, label_ptr[1], s->code_ptr - label_ptr[1] - 4);
     }
 
     if (TCG_TARGET_REG_BITS == 32) {
@@ -1890,9 +1890,9 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
     TCGReg retaddr;
 
     /* resolve label address */
-    tcg_patch32(label_ptr[0], s->code_ptr - label_ptr[0] - 4);
+    tcg_patch32(s, label_ptr[0], s->code_ptr - label_ptr[0] - 4);
     if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
-        tcg_patch32(label_ptr[1], s->code_ptr - label_ptr[1] - 4);
+        tcg_patch32(s, label_ptr[1], s->code_ptr - label_ptr[1] - 4);
     }
 
     if (TCG_TARGET_REG_BITS == 32) {
@@ -3842,9 +3842,9 @@ static void tcg_target_qemu_prologue(TCGContext *s)
     tcg_out_opc(s, OPC_RET, 0, 0, 0);
 }
 
-static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
+static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
 {
-    memset(p, 0x90, count);
+    memset(TCG_CODE_PTR_RW(s, p), 0x90, count);
 }
 
 static void tcg_target_init(TCGContext *s)
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
index abd4ac7fc0..cdc440ce36 100644
--- a/tcg/i386/tcg-target.h
+++ b/tcg/i386/tcg-target.h
@@ -206,16 +206,36 @@ extern bool have_avx2;
 #define TCG_TARGET_extract_i64_valid(ofs, len) \
     (((ofs) == 8 && (len) == 8) || ((ofs) + (len)) == 32)
 
+#ifdef __APPLE__
+void sys_dcache_flush(void *start, size_t len);
+#endif
+
 static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
 {
 }
 
+#if defined(CONFIG_IOS_JIT)
+static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
+{
+#if defined(__APPLE__)
+    sys_dcache_flush((char *)start, stop - start);
+#else
+#error "Missing function to flush data cache"
+#endif
+}
+#endif
+
 static inline void tb_target_set_jmp_target(uintptr_t tc_ptr,
-                                            uintptr_t jmp_addr, uintptr_t addr)
+                                            uintptr_t jmp_addr, uintptr_t addr,
+                                            uintptr_t wr_addr)
 {
     /* patch the branch destination */
-    qatomic_set((int32_t *)jmp_addr, addr - (jmp_addr + 4));
+    qatomic_set((int32_t *)wr_addr, addr - (jmp_addr + 4));
     /* no need to flush icache explicitly */
+#if defined(CONFIG_IOS_JIT)
+    /* we do need to flush mirror dcache */
+    flush_dcache_range(wr_addr, wr_addr + 4);
+#endif
 }
 
 /* This defines the natural memory order supported by this
diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc
index 41be574e89..e798527437 100644
--- a/tcg/mips/tcg-target.c.inc
+++ b/tcg/mips/tcg-target.c.inc
@@ -139,12 +139,13 @@ static const TCGReg tcg_target_call_oarg_regs[2] = {
     TCG_REG_V1
 };
 
-static tcg_insn_unit *tb_ret_addr;
-static tcg_insn_unit *bswap32_addr;
-static tcg_insn_unit *bswap32u_addr;
-static tcg_insn_unit *bswap64_addr;
+static const tcg_insn_unit *tb_ret_addr;
+static const tcg_insn_unit *bswap32_addr;
+static const tcg_insn_unit *bswap32u_addr;
+static const tcg_insn_unit *bswap64_addr;
 
-static inline uint32_t reloc_pc16_val(tcg_insn_unit *pc, tcg_insn_unit *target)
+static inline uint32_t reloc_pc16_val(const tcg_insn_unit *pc,
+                                      const tcg_insn_unit *target)
 {
     /* Let the compiler perform the right-shift as part of the arithmetic.  */
     ptrdiff_t disp = target - (pc + 1);
@@ -152,28 +153,35 @@ static inline uint32_t reloc_pc16_val(tcg_insn_unit *pc, tcg_insn_unit *target)
     return disp & 0xffff;
 }
 
-static inline void reloc_pc16(tcg_insn_unit *pc, tcg_insn_unit *target)
+static inline void reloc_pc16(TCGContext *s,
+                              tcg_insn_unit *pc,
+                              const tcg_insn_unit *target)
 {
-    *pc = deposit32(*pc, 0, 16, reloc_pc16_val(pc, target));
+    *TCG_CODE_PTR_RW(s, pc) =
+        deposit32(*TCG_CODE_PTR_RW(s, pc), 0, 16, reloc_pc16_val(pc, target));
 }
 
-static inline uint32_t reloc_26_val(tcg_insn_unit *pc, tcg_insn_unit *target)
+static inline uint32_t reloc_26_val(const tcg_insn_unit *pc,
+                                    const tcg_insn_unit *target)
 {
     tcg_debug_assert((((uintptr_t)pc ^ (uintptr_t)target) & 0xf0000000) == 0);
     return ((uintptr_t)target >> 2) & 0x3ffffff;
 }
 
-static inline void reloc_26(tcg_insn_unit *pc, tcg_insn_unit *target)
+static inline void reloc_26(TCGContext *s,
+                            tcg_insn_unit *pc,
+                            const tcg_insn_unit *target)
 {
-    *pc = deposit32(*pc, 0, 26, reloc_26_val(pc, target));
+    *TCG_CODE_PTR_RW(s, pc) =
+        deposit32(*TCG_CODE_PTR_RW(s, pc), 0, 26, reloc_26_val(pc, target));
 }
 
-static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
                         intptr_t value, intptr_t addend)
 {
     tcg_debug_assert(type == R_MIPS_PC16);
     tcg_debug_assert(addend == 0);
-    reloc_pc16(code_ptr, (tcg_insn_unit *)value);
+    reloc_pc16(s, code_ptr, (tcg_insn_unit *)value);
     return true;
 }
 
@@ -516,7 +524,7 @@ static void tcg_out_opc_sa64(TCGContext *s, MIPSInsn opc1, MIPSInsn opc2,
  * Type jump.
  * Returns true if the branch was in range and the insn was emitted.
  */
-static bool tcg_out_opc_jmp(TCGContext *s, MIPSInsn opc, void *target)
+static bool tcg_out_opc_jmp(TCGContext *s, MIPSInsn opc, const void *target)
 {
     uintptr_t dest = (uintptr_t)target;
     uintptr_t from = (uintptr_t)s->code_ptr + 4;
@@ -631,7 +639,7 @@ static inline void tcg_out_bswap16s(TCGContext *s, TCGReg ret, TCGReg arg)
     }
 }
 
-static void tcg_out_bswap_subr(TCGContext *s, tcg_insn_unit *sub)
+static void tcg_out_bswap_subr(TCGContext *s, const tcg_insn_unit *sub)
 {
     bool ok = tcg_out_opc_jmp(s, OPC_JAL, sub);
     tcg_debug_assert(ok);
@@ -925,7 +933,7 @@ static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1,
 
     tcg_out_opc_br(s, b_opc, arg1, arg2);
     if (l->has_value) {
-        reloc_pc16(s->code_ptr - 1, l->u.value_ptr);
+        reloc_pc16(s, s->code_ptr - 1, l->u.value_ptr);
     } else {
         tcg_out_reloc(s, s->code_ptr - 1, R_MIPS_PC16, l, 0);
     }
@@ -1079,7 +1087,7 @@ static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret,
     }
 }
 
-static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
+static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail)
 {
     /* Note that the ABI requires the called function's address to be
        loaded into T9, even if a direct branch is in range.  */
@@ -1097,7 +1105,7 @@ static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
     }
 }
 
-static void tcg_out_call(TCGContext *s, tcg_insn_unit *arg)
+static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg)
 {
     tcg_out_call_int(s, arg, false);
     tcg_out_nop(s);
@@ -1289,7 +1297,8 @@ static void add_qemu_ldst_label(TCGContext *s, int is_ld, TCGMemOpIdx oi,
                                 TCGType ext,
                                 TCGReg datalo, TCGReg datahi,
                                 TCGReg addrlo, TCGReg addrhi,
-                                void *raddr, tcg_insn_unit *label_ptr[2])
+                                const tcg_insn_unit *raddr,
+                                tcg_insn_unit *label_ptr[2])
 {
     TCGLabelQemuLdst *label = new_ldst_label(s);
 
@@ -1315,9 +1324,9 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
     int i;
 
     /* resolve label address */
-    reloc_pc16(l->label_ptr[0], s->code_ptr);
+    reloc_pc16(s, l->label_ptr[0], s->code_ptr);
     if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) {
-        reloc_pc16(l->label_ptr[1], s->code_ptr);
+        reloc_pc16(s, l->label_ptr[1], s->code_ptr);
     }
 
     i = 1;
@@ -1345,7 +1354,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
     }
 
     tcg_out_opc_br(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO);
-    reloc_pc16(s->code_ptr - 1, l->raddr);
+    reloc_pc16(s, s->code_ptr - 1, l->raddr);
 
     /* delay slot */
     if (TCG_TARGET_REG_BITS == 64 && l->type == TCG_TYPE_I32) {
@@ -1365,9 +1374,9 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
     int i;
 
     /* resolve label address */
-    reloc_pc16(l->label_ptr[0], s->code_ptr);
+    reloc_pc16(s, l->label_ptr[0], s->code_ptr);
     if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) {
-        reloc_pc16(l->label_ptr[1], s->code_ptr);
+        reloc_pc16(s, l->label_ptr[1], s->code_ptr);
     }
 
     i = 1;
@@ -2430,7 +2439,7 @@ static void tcg_target_detect_isa(void)
     sigaction(SIGILL, &sa_old, NULL);
 }
 
-static tcg_insn_unit *align_code_ptr(TCGContext *s)
+static const tcg_insn_unit *align_code_ptr(TCGContext *s)
 {
     uintptr_t p = (uintptr_t)s->code_ptr;
     if (p & 15) {
@@ -2657,9 +2666,12 @@ static void tcg_target_init(TCGContext *s)
 }
 
 void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
-                              uintptr_t addr)
+                              uintptr_t addr, uintptr_t wr_addr)
 {
-    qatomic_set((uint32_t *)jmp_addr, deposit32(OPC_J, 0, 26, addr >> 2));
+    qatomic_set((uint32_t *)wr_addr, deposit32(OPC_J, 0, 26, addr >> 2));
+#if defined(CONFIG_IOS_JIT)
+    flush_dcache_range(wr_addr, wr_addr + 4);
+#endif
     flush_icache_range(jmp_addr, jmp_addr + 4);
 }
 
diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
index c6b091d849..80dcba5358 100644
--- a/tcg/mips/tcg-target.h
+++ b/tcg/mips/tcg-target.h
@@ -212,7 +212,13 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
     cacheflush ((void *)start, stop-start, ICACHE);
 }
 
-void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
+void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+#if defined(CONFIG_IOS_JIT)
+static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
+{
+#error "Unimplemented dcache flush function"
+}
+#endif
 
 #ifdef CONFIG_SOFTMMU
 #define TCG_TARGET_NEED_LDST_LABELS
diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc
index 18ee989f95..f5a44e9852 100644
--- a/tcg/ppc/tcg-target.c.inc
+++ b/tcg/ppc/tcg-target.c.inc
@@ -62,7 +62,7 @@
 #define TCG_CT_CONST_MONE 0x2000
 #define TCG_CT_CONST_WSZ  0x4000
 
-static tcg_insn_unit *tb_ret_addr;
+static const tcg_insn_unit *tb_ret_addr;
 
 TCGPowerISA have_isa;
 static bool have_isel;
@@ -184,35 +184,43 @@ static inline bool in_range_b(tcg_target_long target)
     return target == sextract64(target, 0, 26);
 }
 
-static uint32_t reloc_pc24_val(tcg_insn_unit *pc, tcg_insn_unit *target)
+static uint32_t reloc_pc24_val(const tcg_insn_unit *pc,
+                               const tcg_insn_unit *target)
 {
     ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
     tcg_debug_assert(in_range_b(disp));
     return disp & 0x3fffffc;
 }
 
-static bool reloc_pc24(tcg_insn_unit *pc, tcg_insn_unit *target)
+static bool reloc_pc24(TCGContext *s,
+                       tcg_insn_unit *pc,
+                       const tcg_insn_unit *target)
 {
     ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
     if (in_range_b(disp)) {
-        *pc = (*pc & ~0x3fffffc) | (disp & 0x3fffffc);
+        *TCG_CODE_PTR_RW(s, pc) =
+            (*TCG_CODE_PTR_RW(s, pc) & ~0x3fffffc) | (disp & 0x3fffffc);
         return true;
     }
     return false;
 }
 
-static uint16_t reloc_pc14_val(tcg_insn_unit *pc, tcg_insn_unit *target)
+static uint16_t reloc_pc14_val(const tcg_insn_unit *pc,
+                               const tcg_insn_unit *target)
 {
     ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
     tcg_debug_assert(disp == (int16_t) disp);
     return disp & 0xfffc;
 }
 
-static bool reloc_pc14(tcg_insn_unit *pc, tcg_insn_unit *target)
+static bool reloc_pc14(TCGContext *s,
+                       tcg_insn_unit *pc,
+                       const tcg_insn_unit *target)
 {
     ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
     if (disp == (int16_t) disp) {
-        *pc = (*pc & ~0xfffc) | (disp & 0xfffc);
+        *TCG_CODE_PTR_RW(s, pc) =
+            (*TCG_CODE_PTR_RW(s, pc) & ~0xfffc) | (disp & 0xfffc);
         return true;
     }
     return false;
@@ -670,7 +678,7 @@ static const uint32_t tcg_to_isel[] = {
     [TCG_COND_GTU] = ISEL | BC_(7, CR_GT),
 };
 
-static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
                         intptr_t value, intptr_t addend)
 {
     tcg_insn_unit *target;
@@ -682,9 +690,9 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
 
     switch (type) {
     case R_PPC_REL14:
-        return reloc_pc14(code_ptr, target);
+        return reloc_pc14(s, code_ptr, target);
     case R_PPC_REL24:
-        return reloc_pc24(code_ptr, target);
+        return reloc_pc24(s, code_ptr, target);
     case R_PPC_ADDR16:
         /*
          * We are (slightly) abusing this relocation type.  In particular,
@@ -1106,7 +1114,7 @@ static void tcg_out_xori32(TCGContext *s, TCGReg dst, TCGReg src, uint32_t c)
     tcg_out_zori32(s, dst, src, c, XORI, XORIS);
 }
 
-static void tcg_out_b(TCGContext *s, int mask, tcg_insn_unit *target)
+static void tcg_out_b(TCGContext *s, int mask, const tcg_insn_unit *target)
 {
     ptrdiff_t disp = tcg_pcrel_diff(s, target);
     if (in_range_b(disp)) {
@@ -1723,7 +1731,7 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0)
 }
 
 void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
-                              uintptr_t addr)
+                              uintptr_t addr, uintptr_t wr_addr)
 {
     if (TCG_TARGET_REG_BITS == 64) {
         tcg_insn_unit i1, i2;
@@ -1752,17 +1760,23 @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
 
         /* As per the enclosing if, this is ppc64.  Avoid the _Static_assert
            within qatomic_set that would fail to build a ppc32 host.  */
-        qatomic_set__nocheck((uint64_t *)jmp_addr, pair);
+        qatomic_set__nocheck((uint64_t *)wr_addr, pair);
+#if defined(CONFIG_IOS_JIT)
+        flush_dcache_range(wr_addr, wr_addr + 8);
+#endif
         flush_icache_range(jmp_addr, jmp_addr + 8);
     } else {
         intptr_t diff = addr - jmp_addr;
         tcg_debug_assert(in_range_b(diff));
-        qatomic_set((uint32_t *)jmp_addr, B | (diff & 0x3fffffc));
+        qatomic_set((uint32_t *)wr_addr, B | (diff & 0x3fffffc));
+#if defined(CONFIG_IOS_JIT)
+        flush_dcache_range(wr_addr, wr_addr + 8);
+#endif
         flush_icache_range(jmp_addr, jmp_addr + 4);
     }
 }
 
-static void tcg_out_call(TCGContext *s, tcg_insn_unit *target)
+static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target)
 {
 #ifdef _CALL_AIX
     /* Look through the descriptor.  If the branch is in range, and we
@@ -1987,7 +2001,8 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, MemOp opc,
 static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
                                 TCGReg datalo_reg, TCGReg datahi_reg,
                                 TCGReg addrlo_reg, TCGReg addrhi_reg,
-                                tcg_insn_unit *raddr, tcg_insn_unit *lptr)
+                                const tcg_insn_unit *raddr,
+                                tcg_insn_unit *lptr)
 {
     TCGLabelQemuLdst *label = new_ldst_label(s);
 
@@ -2007,7 +2022,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
     MemOp opc = get_memop(oi);
     TCGReg hi, lo, arg = TCG_REG_R3;
 
-    if (!reloc_pc14(lb->label_ptr[0], s->code_ptr)) {
+    if (!reloc_pc14(s, lb->label_ptr[0], s->code_ptr)) {
         return false;
     }
 
@@ -2055,7 +2070,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
     MemOp s_bits = opc & MO_SIZE;
     TCGReg hi, lo, arg = TCG_REG_R3;
 
-    if (!reloc_pc14(lb->label_ptr[0], s->code_ptr)) {
+    if (!reloc_pc14(s, lb->label_ptr[0], s->code_ptr)) {
         return false;
     }
 
@@ -2252,11 +2267,11 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
 #endif
 }
 
-static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
+static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
 {
     int i;
     for (i = 0; i < count; ++i) {
-        p[i] = NOP;
+        (TCG_CODE_PTR_RW(s, p))[i] = NOP;
     }
 }
 
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
index be10363956..23d7a337c9 100644
--- a/tcg/ppc/tcg-target.h
+++ b/tcg/ppc/tcg-target.h
@@ -176,7 +176,13 @@ extern bool have_vsx;
 #define TCG_TARGET_HAS_cmpsel_vec       0
 
 void flush_icache_range(uintptr_t start, uintptr_t stop);
-void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
+void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+#if defined(CONFIG_IOS_JIT)
+static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
+{
+#error "Unimplemented dcache flush function"
+}
+#endif
 
 #define TCG_TARGET_DEFAULT_MO (0)
 #define TCG_TARGET_HAS_MEMORY_BSWAP     1
diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc
index d536f3ccc1..2d96c83c4b 100644
--- a/tcg/riscv/tcg-target.c.inc
+++ b/tcg/riscv/tcg-target.c.inc
@@ -413,11 +413,11 @@ static void tcg_out_opc_jump(TCGContext *s, RISCVInsn opc,
     tcg_out32(s, encode_uj(opc, rd, imm));
 }
 
-static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
+static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
 {
     int i;
     for (i = 0; i < count; ++i) {
-        p[i] = encode_i(OPC_ADDI, TCG_REG_ZERO, TCG_REG_ZERO, 0);
+        (TCG_CODE_PTR_RW(s, p))[i] = encode_i(OPC_ADDI, TCG_REG_ZERO, TCG_REG_ZERO, 0);
     }
 }
 
@@ -425,46 +425,52 @@ static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
  * Relocations
  */
 
-static bool reloc_sbimm12(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
+static bool reloc_sbimm12(TCGContext *s,
+                          tcg_insn_unit *code_ptr,
+                          const tcg_insn_unit *target)
 {
     intptr_t offset = (intptr_t)target - (intptr_t)code_ptr;
 
     if (offset == sextreg(offset, 1, 12) << 1) {
-        code_ptr[0] |= encode_sbimm12(offset);
+        (TCG_CODE_PTR_RW(s, code_ptr))[0] |= encode_sbimm12(offset);
         return true;
     }
 
     return false;
 }
 
-static bool reloc_jimm20(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
+static bool reloc_jimm20(TCGContext *s,
+                         tcg_insn_unit *code_ptr,
+                         const tcg_insn_unit *target)
 {
     intptr_t offset = (intptr_t)target - (intptr_t)code_ptr;
 
     if (offset == sextreg(offset, 1, 20) << 1) {
-        code_ptr[0] |= encode_ujimm20(offset);
+        (TCG_CODE_PTR_RW(s, code_ptr))[0] |= encode_ujimm20(offset);
         return true;
     }
 
     return false;
 }
 
-static bool reloc_call(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
+static bool reloc_call(TCGContext *s,
+                       tcg_insn_unit *code_ptr,
+                       const tcg_insn_unit *target)
 {
     intptr_t offset = (intptr_t)target - (intptr_t)code_ptr;
     int32_t lo = sextreg(offset, 0, 12);
     int32_t hi = offset - lo;
 
     if (offset == hi + lo) {
-        code_ptr[0] |= encode_uimm20(hi);
-        code_ptr[1] |= encode_imm12(lo);
+        (TCG_CODE_PTR_RW(s, code_ptr))[0] |= encode_uimm20(hi);
+        (TCG_CODE_PTR_RW(s, code_ptr))[1] |= encode_imm12(lo);
         return true;
     }
 
     return false;
 }
 
-static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
                         intptr_t value, intptr_t addend)
 {
     uint32_t insn = *code_ptr;
@@ -478,7 +484,7 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
         diff = value - (uintptr_t)code_ptr;
         short_jmp = diff == sextreg(diff, 0, 12);
         if (short_jmp) {
-            return reloc_sbimm12(code_ptr, (tcg_insn_unit *)value);
+            return reloc_sbimm12(s, code_ptr, (tcg_insn_unit *)value);
         } else {
             /* Invert the condition */
             insn = insn ^ (1 << 12);
@@ -499,9 +505,9 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
         }
         break;
     case R_RISCV_JAL:
-        return reloc_jimm20(code_ptr, (tcg_insn_unit *)value);
+        return reloc_jimm20(s, code_ptr, (tcg_insn_unit *)value);
     case R_RISCV_CALL:
-        return reloc_call(code_ptr, (tcg_insn_unit *)value);
+        return reloc_call(s, code_ptr, (tcg_insn_unit *)value);
     default:
         tcg_abort();
     }
@@ -557,7 +563,7 @@ static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd,
     if (tmp == (int32_t)tmp) {
         tcg_out_opc_upper(s, OPC_AUIPC, rd, 0);
         tcg_out_opc_imm(s, OPC_ADDI, rd, rd, 0);
-        ret = reloc_call(s->code_ptr - 2, (tcg_insn_unit *)val);
+        ret = reloc_call(s, s->code_ptr - 2, (tcg_insn_unit *)val);
         tcg_debug_assert(ret == true);
         return;
     }
@@ -854,14 +860,14 @@ static void tcg_out_setcond2(TCGContext *s, TCGCond cond, TCGReg ret,
     g_assert_not_reached();
 }
 
-static inline void tcg_out_goto(TCGContext *s, tcg_insn_unit *target)
+static inline void tcg_out_goto(TCGContext *s, const tcg_insn_unit *target)
 {
     ptrdiff_t offset = tcg_pcrel_diff(s, target);
     tcg_debug_assert(offset == sextreg(offset, 1, 20) << 1);
     tcg_out_opc_jump(s, OPC_JAL, TCG_REG_ZERO, offset);
 }
 
-static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
+static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail)
 {
     TCGReg link = tail ? TCG_REG_ZERO : TCG_REG_RA;
     ptrdiff_t offset = tcg_pcrel_diff(s, arg);
@@ -875,7 +881,7 @@ static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
         /* long jump: -2147483646 to 2147483648 */
         tcg_out_opc_upper(s, OPC_AUIPC, TCG_REG_TMP0, 0);
         tcg_out_opc_imm(s, OPC_JALR, link, TCG_REG_TMP0, 0);
-        ret = reloc_call(s->code_ptr - 2, arg);\
+        ret = reloc_call(s, s->code_ptr - 2, arg);\
         tcg_debug_assert(ret == true);
     } else if (TCG_TARGET_REG_BITS == 64) {
         /* far jump: 64-bit */
@@ -888,7 +894,7 @@ static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
     }
 }
 
-static void tcg_out_call(TCGContext *s, tcg_insn_unit *arg)
+static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg)
 {
     tcg_out_call_int(s, arg, false);
 }
@@ -1022,7 +1028,8 @@ static void add_qemu_ldst_label(TCGContext *s, int is_ld, TCGMemOpIdx oi,
                                 TCGType ext,
                                 TCGReg datalo, TCGReg datahi,
                                 TCGReg addrlo, TCGReg addrhi,
-                                void *raddr, tcg_insn_unit **label_ptr)
+                                const tcg_insn_unit *raddr,
+                                tcg_insn_unit **label_ptr)
 {
     TCGLabelQemuLdst *label = new_ldst_label(s);
 
@@ -1052,7 +1059,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
     }
 
     /* resolve label address */
-    if (!patch_reloc(l->label_ptr[0], R_RISCV_BRANCH,
+    if (!patch_reloc(s, l->label_ptr[0], R_RISCV_BRANCH,
                      (intptr_t) s->code_ptr, 0)) {
         return false;
     }
@@ -1087,7 +1094,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
     }
 
     /* resolve label address */
-    if (!patch_reloc(l->label_ptr[0], R_RISCV_BRANCH,
+    if (!patch_reloc(s, l->label_ptr[0], R_RISCV_BRANCH,
                      (intptr_t) s->code_ptr, 0)) {
         return false;
     }
@@ -1274,7 +1281,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
 #endif
 }
 
-static tcg_insn_unit *tb_ret_addr;
+static const tcg_insn_unit *tb_ret_addr;
 
 static void tcg_out_op(TCGContext *s, TCGOpcode opc,
                        const TCGArg *args, const int *const_args)
diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h
index 032439d806..d42b361991 100644
--- a/tcg/riscv/tcg-target.h
+++ b/tcg/riscv/tcg-target.h
@@ -164,8 +164,15 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
     __builtin___clear_cache((char *)start, (char *)stop);
 }
 
+#if defined(CONFIG_IOS_JIT)
+static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
+{
+#error "Unimplemented dcache flush function"
+}
+#endif
+
 /* not defined -- call should be eliminated at compile time */
-void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
+void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
 
 #define TCG_TARGET_DEFAULT_MO (0)
 
diff --git a/tcg/s390/tcg-target.c.inc b/tcg/s390/tcg-target.c.inc
index c5e096449b..49a96ca15f 100644
--- a/tcg/s390/tcg-target.c.inc
+++ b/tcg/s390/tcg-target.c.inc
@@ -363,10 +363,10 @@ static void * const qemu_st_helpers[16] = {
 };
 #endif
 
-static tcg_insn_unit *tb_ret_addr;
+static const tcg_insn_unit *tb_ret_addr;
 uint64_t s390_facilities;
 
-static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
                         intptr_t value, intptr_t addend)
 {
     intptr_t pcrel2;
@@ -378,13 +378,13 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
     switch (type) {
     case R_390_PC16DBL:
         if (pcrel2 == (int16_t)pcrel2) {
-            tcg_patch16(code_ptr, pcrel2);
+            tcg_patch16(s, code_ptr, pcrel2);
             return true;
         }
         break;
     case R_390_PC32DBL:
         if (pcrel2 == (int32_t)pcrel2) {
-            tcg_patch32(code_ptr, pcrel2);
+            tcg_patch32(s, code_ptr, pcrel2);
             return true;
         }
         break;
@@ -392,7 +392,7 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
         if (value == sextract64(value, 0, 20)) {
             old = *(uint32_t *)code_ptr & 0xf00000ff;
             old |= ((value & 0xfff) << 16) | ((value & 0xff000) >> 4);
-            tcg_patch32(code_ptr, old);
+            tcg_patch32(s, code_ptr, old);
             return true;
         }
         break;
@@ -1302,7 +1302,7 @@ static void tgen_extract(TCGContext *s, TCGReg dest, TCGReg src,
     tcg_out_risbg(s, dest, src, 64 - len, 63, 64 - ofs, 1);
 }
 
-static void tgen_gotoi(TCGContext *s, int cc, tcg_insn_unit *dest)
+static void tgen_gotoi(TCGContext *s, int cc, const tcg_insn_unit *dest)
 {
     ptrdiff_t off = dest - s->code_ptr;
     if (off == (int16_t)off) {
@@ -1415,7 +1415,7 @@ static void tgen_brcond(TCGContext *s, TCGType type, TCGCond c,
     tgen_branch(s, cc, l);
 }
 
-static void tcg_out_call(TCGContext *s, tcg_insn_unit *dest)
+static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest)
 {
     ptrdiff_t off = dest - s->code_ptr;
     if (off == (int32_t)off) {
@@ -1593,7 +1593,8 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, MemOp opc,
 
 static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
                                 TCGReg data, TCGReg addr,
-                                tcg_insn_unit *raddr, tcg_insn_unit *label_ptr)
+                                const tcg_insn_unit *raddr,
+                                tcg_insn_unit *label_ptr)
 {
     TCGLabelQemuLdst *label = new_ldst_label(s);
 
@@ -1612,7 +1613,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
     TCGMemOpIdx oi = lb->oi;
     MemOp opc = get_memop(oi);
 
-    if (!patch_reloc(lb->label_ptr[0], R_390_PC16DBL,
+    if (!patch_reloc(s, lb->label_ptr[0], R_390_PC16DBL,
                      (intptr_t)s->code_ptr, 2)) {
         return false;
     }
@@ -1637,7 +1638,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
     TCGMemOpIdx oi = lb->oi;
     MemOp opc = get_memop(oi);
 
-    if (!patch_reloc(lb->label_ptr[0], R_390_PC16DBL,
+    if (!patch_reloc(s, lb->label_ptr[0], R_390_PC16DBL,
                      (intptr_t)s->code_ptr, 2)) {
         return false;
     }
@@ -2575,9 +2576,9 @@ static void tcg_target_qemu_prologue(TCGContext *s)
     tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_REG_R14);
 }
 
-static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
+static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
 {
-    memset(p, 0x07, count * sizeof(tcg_insn_unit));
+    memset(TCG_CODE_PTR_RW(s, p), 0x07, count * sizeof(tcg_insn_unit));
 }
 
 typedef struct {
diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h
index 63c8797bd3..d67632512d 100644
--- a/tcg/s390/tcg-target.h
+++ b/tcg/s390/tcg-target.h
@@ -149,13 +149,24 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
 {
 }
 
+#if defined(CONFIG_IOS_JIT)
+static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
+{
+#error "Unimplemented dcache flush function"
+}
+#endif
+
 static inline void tb_target_set_jmp_target(uintptr_t tc_ptr,
-                                            uintptr_t jmp_addr, uintptr_t addr)
+                                            uintptr_t jmp_addr, uintptr_t addr,
+                                            uintptr_t wr_addr)
 {
     /* patch the branch destination */
     intptr_t disp = addr - (jmp_addr - 2);
     qatomic_set((int32_t *)jmp_addr, disp / 2);
     /* no need to flush icache explicitly */
+#if defined(CONFIG_IOS_JIT)
+    flush_dcache_range(wr_addr, wr_addr + 4);
+#endif
 }
 
 #ifdef CONFIG_SOFTMMU
diff --git a/tcg/sparc/tcg-target.c.inc b/tcg/sparc/tcg-target.c.inc
index 6775bd30fc..af97cbdeef 100644
--- a/tcg/sparc/tcg-target.c.inc
+++ b/tcg/sparc/tcg-target.c.inc
@@ -291,14 +291,14 @@ static inline int check_fit_i32(int32_t val, unsigned int bits)
 # define check_fit_ptr  check_fit_i32
 #endif
 
-static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
                         intptr_t value, intptr_t addend)
 {
     uint32_t insn = *code_ptr;
     intptr_t pcrel;
 
     value += addend;
-    pcrel = tcg_ptr_byte_diff((tcg_insn_unit *)value, code_ptr);
+    pcrel = tcg_ptr_byte_diff((const tcg_insn_unit *)value, code_ptr);
 
     switch (type) {
     case R_SPARC_WDISP16:
@@ -840,7 +840,7 @@ static void tcg_out_addsub2_i64(TCGContext *s, TCGReg rl, TCGReg rh,
     tcg_out_mov(s, TCG_TYPE_I64, rl, tmp);
 }
 
-static void tcg_out_call_nodelay(TCGContext *s, tcg_insn_unit *dest,
+static void tcg_out_call_nodelay(TCGContext *s, const tcg_insn_unit *dest,
                                  bool in_prologue)
 {
     ptrdiff_t disp = tcg_pcrel_diff(s, dest);
@@ -855,7 +855,7 @@ static void tcg_out_call_nodelay(TCGContext *s, tcg_insn_unit *dest,
     }
 }
 
-static void tcg_out_call(TCGContext *s, tcg_insn_unit *dest)
+static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest)
 {
     tcg_out_call_nodelay(s, dest, false);
     tcg_out_nop(s);
@@ -868,8 +868,8 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0)
 }
 
 #ifdef CONFIG_SOFTMMU
-static tcg_insn_unit *qemu_ld_trampoline[16];
-static tcg_insn_unit *qemu_st_trampoline[16];
+static const tcg_insn_unit *qemu_ld_trampoline[16];
+static const tcg_insn_unit *qemu_st_trampoline[16];
 
 static void emit_extend(TCGContext *s, TCGReg r, int op)
 {
@@ -1048,11 +1048,11 @@ static void tcg_target_qemu_prologue(TCGContext *s)
 #endif
 }
 
-static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
+static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
 {
     int i;
     for (i = 0; i < count; ++i) {
-        p[i] = NOP;
+        (TCG_CODE_PTR_RW(s, p))[i] = NOP;
     }
 }
 
@@ -1163,7 +1163,7 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr,
 #ifdef CONFIG_SOFTMMU
     unsigned memi = get_mmuidx(oi);
     TCGReg addrz, param;
-    tcg_insn_unit *func;
+    const tcg_insn_unit *func;
     tcg_insn_unit *label_ptr;
 
     addrz = tcg_out_tlb_load(s, addr, memi, memop,
@@ -1226,7 +1226,8 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr,
         }
     }
 
-    *label_ptr |= INSN_OFF19(tcg_ptr_byte_diff(s->code_ptr, label_ptr));
+    *TCG_CODE_PTR_RW(s, label_ptr) |=
+        INSN_OFF19(tcg_ptr_byte_diff(s->code_ptr, label_ptr));
 #else
     if (SPARC64 && TARGET_LONG_BITS == 32) {
         tcg_out_arithi(s, TCG_REG_T1, addr, 0, SHIFT_SRL);
@@ -1822,7 +1823,7 @@ void tcg_register_jit(void *buf, size_t buf_size)
 }
 
 void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
-                              uintptr_t addr)
+                              uintptr_t addr, uintptr_t wr_addr)
 {
     intptr_t tb_disp = addr - tc_ptr;
     intptr_t br_disp = addr - jmp_addr;
@@ -1834,8 +1835,11 @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
     tcg_debug_assert(br_disp == (int32_t)br_disp);
 
     if (!USE_REG_TB) {
-        qatomic_set((uint32_t *)jmp_addr,
+        qatomic_set((uint32_t *)wr_addr,
 		    deposit32(CALL, 0, 30, br_disp >> 2));
+#if defined(CONFIG_IOS_JIT)
+        flush_dcache_range(wr_addr, wr_addr + 4);
+#endif
         flush_icache_range(jmp_addr, jmp_addr + 4);
         return;
     }
@@ -1859,6 +1863,9 @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
               | INSN_IMM13((tb_disp & 0x3ff) | -0x400));
     }
 
-    qatomic_set((uint64_t *)jmp_addr, deposit64(i2, 32, 32, i1));
+    qatomic_set((uint64_t *)wr_addr, deposit64(i2, 32, 32, i1));
+#if defined(CONFIG_IOS_JIT)
+    flush_dcache_range(wr_addr, wr_addr + 8);
+#endif
     flush_icache_range(jmp_addr, jmp_addr + 8);
 }
diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h
index 633841ebf2..d102e13692 100644
--- a/tcg/sparc/tcg-target.h
+++ b/tcg/sparc/tcg-target.h
@@ -176,7 +176,13 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
     }
 }
 
-void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
+void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+#if defined(CONFIG_IOS_JIT)
+static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
+{
+#error "Unimplemented dcache flush function"
+}
+#endif
 
 #define TCG_TARGET_NEED_POOL_LABELS
 
diff --git a/tcg/tcg-ldst.c.inc b/tcg/tcg-ldst.c.inc
index 05f9b3ccd6..eaba08700e 100644
--- a/tcg/tcg-ldst.c.inc
+++ b/tcg/tcg-ldst.c.inc
@@ -28,7 +28,7 @@ typedef struct TCGLabelQemuLdst {
     TCGReg addrhi_reg;      /* reg index for high word of guest virtual addr */
     TCGReg datalo_reg;      /* reg index for low word to be loaded or stored */
     TCGReg datahi_reg;      /* reg index for high word to be loaded or stored */
-    tcg_insn_unit *raddr;   /* gen code addr of the next IR of qemu_ld/st IR */
+    const tcg_insn_unit *raddr; /* gen code addr of the next IR of qemu_ld/st */
     tcg_insn_unit *label_ptr[2]; /* label pointers to be updated */
     QSIMPLEQ_ENTRY(TCGLabelQemuLdst) next;
 } TCGLabelQemuLdst;
diff --git a/tcg/tcg-pool.c.inc b/tcg/tcg-pool.c.inc
index 82cbcc89bd..97bb90b7cc 100644
--- a/tcg/tcg-pool.c.inc
+++ b/tcg/tcg-pool.c.inc
@@ -119,7 +119,7 @@ static inline void new_pool_l8(TCGContext *s, int rtype, tcg_insn_unit *label,
 }
 
 /* To be provided by cpu/tcg-target.c.inc.  */
-static void tcg_out_nop_fill(tcg_insn_unit *p, int count);
+static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count);
 
 static int tcg_out_pool_finalize(TCGContext *s)
 {
@@ -135,7 +135,7 @@ static int tcg_out_pool_finalize(TCGContext *s)
        again when allocating the next TranslationBlock structure.  */
     a = (void *)ROUND_UP((uintptr_t)s->code_ptr,
                          sizeof(tcg_target_ulong) * p->nlong);
-    tcg_out_nop_fill(s->code_ptr, (tcg_insn_unit *)a - s->code_ptr);
+    tcg_out_nop_fill(s, s->code_ptr, (tcg_insn_unit *)a - s->code_ptr);
     s->data_gen_ptr = a;
 
     for (; p != NULL; p = p->next) {
@@ -144,11 +144,12 @@ static int tcg_out_pool_finalize(TCGContext *s)
             if (unlikely(a > s->code_gen_highwater)) {
                 return -1;
             }
-            memcpy(a, p->data, size);
+            memcpy(TCG_CODE_PTR_RW(s, a), p->data, size);
             a += size;
             l = p;
         }
-        if (!patch_reloc(p->label, p->rtype, (intptr_t)a - size, p->addend)) {
+        if (!patch_reloc(s, p->label, p->rtype,
+                         (intptr_t)a - size, p->addend)) {
             return -2;
         }
     }
diff --git a/tcg/tcg.c b/tcg/tcg.c
index a8c28440e2..ef203a34a6 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -70,7 +70,7 @@
 static void tcg_target_init(TCGContext *s);
 static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode);
 static void tcg_target_qemu_prologue(TCGContext *s);
-static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
                         intptr_t value, intptr_t addend);
 
 /* The CIE and FDE header definitions will be common to all hosts.  */
@@ -148,7 +148,7 @@ static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
                        intptr_t arg2);
 static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
                         TCGReg base, intptr_t ofs);
-static void tcg_out_call(TCGContext *s, tcg_insn_unit *target);
+static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target);
 static int tcg_target_const_match(tcg_target_long val, TCGType type,
                                   const TCGArgConstraint *arg_ct);
 #ifdef TCG_TARGET_NEED_LDST_LABELS
@@ -203,13 +203,15 @@ static TCGRegSet tcg_target_call_clobber_regs;
 #if TCG_TARGET_INSN_UNIT_SIZE == 1
 static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
 {
-    *s->code_ptr++ = v;
+    *TCG_CODE_PTR_RW(s, s->code_ptr) = v;
+    s->code_ptr++;
 }
 
-static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
+static __attribute__((unused)) inline void tcg_patch8(TCGContext *s,
+                                                      tcg_insn_unit *p,
                                                       uint8_t v)
 {
-    *p = v;
+    *TCG_CODE_PTR_RW(s, p) = v;
 }
 #endif
 
@@ -217,21 +219,23 @@ static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
 static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
 {
     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
-        *s->code_ptr++ = v;
+        *TCG_CODE_PTR_RW(s, s->code_ptr) = v;
+        s->code_ptr++;
     } else {
         tcg_insn_unit *p = s->code_ptr;
-        memcpy(p, &v, sizeof(v));
+        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
     }
 }
 
-static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
+static __attribute__((unused)) inline void tcg_patch16(TCGContext *s,
+                                                       tcg_insn_unit *p,
                                                        uint16_t v)
 {
     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
-        *p = v;
+        *TCG_CODE_PTR_RW(s, p) = v;
     } else {
-        memcpy(p, &v, sizeof(v));
+        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
     }
 }
 #endif
@@ -240,21 +244,23 @@ static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
 static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
 {
     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
-        *s->code_ptr++ = v;
+        *TCG_CODE_PTR_RW(s, s->code_ptr) = v;
+        s->code_ptr++;
     } else {
         tcg_insn_unit *p = s->code_ptr;
-        memcpy(p, &v, sizeof(v));
+        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
     }
 }
 
-static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
+static __attribute__((unused)) inline void tcg_patch32(TCGContext *s,
+                                                       tcg_insn_unit *p,
                                                        uint32_t v)
 {
     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
         *p = v;
     } else {
-        memcpy(p, &v, sizeof(v));
+        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
     }
 }
 #endif
@@ -263,21 +269,23 @@ static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
 static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
 {
     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
-        *s->code_ptr++ = v;
+        *TCG_CODE_PTR_RW(s, s->code_ptr) = v;
+        s->code_ptr++;
     } else {
         tcg_insn_unit *p = s->code_ptr;
-        memcpy(p, &v, sizeof(v));
+        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
     }
 }
 
-static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
+static __attribute__((unused)) inline void tcg_patch64(TCGContext *s,
+                                                       tcg_insn_unit *p,
                                                        uint64_t v)
 {
     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
         *p = v;
     } else {
-        memcpy(p, &v, sizeof(v));
+        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
     }
 }
 #endif
@@ -295,7 +303,7 @@ static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
 }
 
-static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr)
+static void tcg_out_label(TCGContext *s, TCGLabel *l, const tcg_insn_unit *ptr)
 {
     tcg_debug_assert(!l->has_value);
     l->has_value = 1;
@@ -325,7 +333,7 @@ static bool tcg_resolve_relocs(TCGContext *s)
         uintptr_t value = l->u.value;
 
         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
-            if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
+            if (!patch_reloc(s, r->ptr, r->type, value, r->addend)) {
                 return false;
             }
         }
@@ -1039,7 +1047,7 @@ TranslationBlock *tcg_tb_alloc(TCGContext *s)
     }
     qatomic_set(&s->code_gen_ptr, next);
     s->data_gen_ptr = NULL;
-    return tb;
+    return (TranslationBlock *)TCG_CODE_PTR_RW(s, tb);
 }
 
 void tcg_prologue_init(TCGContext *s)
@@ -1076,6 +1084,10 @@ void tcg_prologue_init(TCGContext *s)
 #endif
 
     buf1 = s->code_ptr;
+#if defined(CONFIG_IOS_JIT)
+    flush_dcache_range((uintptr_t)TCG_CODE_PTR_RW(s, buf0),
+                       (uintptr_t)TCG_CODE_PTR_RW(s, buf1));
+#endif
     flush_icache_range((uintptr_t)buf0, (uintptr_t)buf1);
 
     /* Deduct the prologue from the buffer.  */
@@ -4267,6 +4279,12 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
         return -2;
     }
 
+#if defined(CONFIG_IOS_JIT)
+    /* flush data cache on mirror */
+    flush_dcache_range((uintptr_t)TCG_CODE_PTR_RW(s, s->code_buf),
+                       (uintptr_t)TCG_CODE_PTR_RW(s, s->code_ptr));
+#endif
+
     /* flush instruction cache */
     flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr);
 
diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc
index 231b9b1775..133213be3a 100644
--- a/tcg/tci/tcg-target.c.inc
+++ b/tcg/tci/tcg-target.c.inc
@@ -369,7 +369,7 @@ static const char *const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
 };
 #endif
 
-static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
                         intptr_t value, intptr_t addend)
 {
     /* tcg_out_reloc always uses the same type, addend. */
@@ -377,9 +377,9 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
     tcg_debug_assert(addend == 0);
     tcg_debug_assert(value != 0);
     if (TCG_TARGET_REG_BITS == 32) {
-        tcg_patch32(code_ptr, value);
+        tcg_patch32(s, code_ptr, value);
     } else {
-        tcg_patch64(code_ptr, value);
+        tcg_patch64(s, code_ptr, value);
     }
     return true;
 }
@@ -545,7 +545,7 @@ static void tcg_out_movi(TCGContext *s, TCGType type,
     old_code_ptr[1] = s->code_ptr - old_code_ptr;
 }
 
-static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *arg)
+static inline void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg)
 {
     uint8_t *old_code_ptr = s->code_ptr;
     tcg_out_op_t(s, INDEX_op_call);
diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h
index 8c1c1d265d..2a258ea350 100644
--- a/tcg/tci/tcg-target.h
+++ b/tcg/tci/tcg-target.h
@@ -195,6 +195,12 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
 {
 }
 
+#if defined(CONFIG_IOS_JIT)
+static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
+{
+}
+#endif
+
 /* We could notice __i386__ or __s390x__ and reduce the barriers depending
    on the host.  But if you want performance, you use the normal backend.
    We prefer consistency across hosts on this.  */
@@ -203,7 +209,8 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
 #define TCG_TARGET_HAS_MEMORY_BSWAP     1
 
 static inline void tb_target_set_jmp_target(uintptr_t tc_ptr,
-                                            uintptr_t jmp_addr, uintptr_t addr)
+                                            uintptr_t jmp_addr, uintptr_t addr,
+                                            uintptr_t wr_addr)
 {
     /* patch the branch destination */
     qatomic_set((int32_t *)jmp_addr, addr - (jmp_addr + 4));
-- 
2.24.3 (Apple Git-128)



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 08/10] tcg: mirror mapping RWX pages for iOS optional
  2020-10-12 23:29 [PATCH 00/10] iOS and Apple Silicon host support Joelle van Dyne
                   ` (6 preceding siblings ...)
  2020-10-12 23:29   ` Joelle van Dyne
@ 2020-10-12 23:29 ` Joelle van Dyne
  2020-10-13 13:52   ` Paolo Bonzini
  2020-10-12 23:29 ` [PATCH 09/10] tcg: support JIT on Apple Silicon Joelle van Dyne
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 47+ messages in thread
From: Joelle van Dyne @ 2020-10-12 23:29 UTC (permalink / raw)
  To: qemu-devel
  Cc: Paolo Bonzini, Laurent Vivier, Joelle van Dyne, Richard Henderson

From: osy <osy86@users.noreply.github.com>

This allows jailbroken devices with entitlements to switch the option off.

Signed-off-by: Joelle van Dyne <j@getutm.app>
---
 accel/tcg/tcg-all.c       | 27 +++++++++++++++++-
 accel/tcg/translate-all.c | 60 +++++++++++++++++++++++++--------------
 bsd-user/main.c           |  2 +-
 include/sysemu/tcg.h      |  2 +-
 linux-user/main.c         |  2 +-
 qemu-options.hx           | 11 +++++++
 6 files changed, 79 insertions(+), 25 deletions(-)

diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c
index fa1208158f..5845744396 100644
--- a/accel/tcg/tcg-all.c
+++ b/accel/tcg/tcg-all.c
@@ -39,6 +39,7 @@ struct TCGState {
 
     bool mttcg_enabled;
     unsigned long tb_size;
+    bool mirror_rwx;
 };
 typedef struct TCGState TCGState;
 
@@ -94,6 +95,7 @@ static void tcg_accel_instance_init(Object *obj)
     TCGState *s = TCG_STATE(obj);
 
     s->mttcg_enabled = default_mttcg_enabled();
+    s->mirror_rwx = false;
 }
 
 bool mttcg_enabled;
@@ -102,7 +104,7 @@ static int tcg_init(MachineState *ms)
 {
     TCGState *s = TCG_STATE(current_accel());
 
-    tcg_exec_init(s->tb_size * 1024 * 1024);
+    tcg_exec_init(s->tb_size * 1024 * 1024, s->mirror_rwx);
     mttcg_enabled = s->mttcg_enabled;
     cpus_register_accel(&tcg_cpus);
 
@@ -168,6 +170,22 @@ static void tcg_set_tb_size(Object *obj, Visitor *v,
     s->tb_size = value;
 }
 
+#ifdef CONFIG_IOS_JIT
+static bool tcg_get_mirror_rwx(Object *obj, Error **errp)
+{
+    TCGState *s = TCG_STATE(obj);
+
+    return s->mirror_rwx;
+}
+
+static void tcg_set_mirror_rwx(Object *obj, bool value, Error **errp)
+{
+    TCGState *s = TCG_STATE(obj);
+
+    s->mirror_rwx = value;
+}
+#endif
+
 static void tcg_accel_class_init(ObjectClass *oc, void *data)
 {
     AccelClass *ac = ACCEL_CLASS(oc);
@@ -185,6 +203,13 @@ static void tcg_accel_class_init(ObjectClass *oc, void *data)
     object_class_property_set_description(oc, "tb-size",
         "TCG translation block cache size");
 
+#ifdef CONFIG_IOS_JIT
+    object_class_property_add_bool(oc, "mirror-rwx",
+        tcg_get_mirror_rwx, tcg_set_mirror_rwx);
+    object_class_property_set_description(oc, "mirror-rwx",
+        "mirror map executable pages for TCG on iOS");
+#endif
+
 }
 
 static const TypeInfo tcg_accel_type = {
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 76d8dc3d7b..de9b7d9ab6 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -1043,12 +1043,15 @@ static inline void *split_cross_256mb(void *buf1, size_t size1)
 static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE]
     __attribute__((aligned(CODE_GEN_ALIGN)));
 
-static inline void *alloc_code_gen_buffer(void)
+static inline void *alloc_code_gen_buffer(bool no_rwx_pages)
 {
     void *buf = static_code_gen_buffer;
     void *end = static_code_gen_buffer + sizeof(static_code_gen_buffer);
     size_t size;
 
+    /* not applicable */
+    assert(!no_rwx_pages);
+
     /* page-align the beginning and end of the buffer */
     buf = QEMU_ALIGN_PTR_UP(buf, qemu_real_host_page_size);
     end = QEMU_ALIGN_PTR_DOWN(end, qemu_real_host_page_size);
@@ -1077,24 +1080,32 @@ static inline void *alloc_code_gen_buffer(void)
     return buf;
 }
 #elif defined(_WIN32)
-static inline void *alloc_code_gen_buffer(void)
+static inline void *alloc_code_gen_buffer(bool no_rwx_pages)
 {
     size_t size = tcg_ctx->code_gen_buffer_size;
+    assert(!no_rwx_pages); /* not applicable */
     return VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT,
                         PAGE_EXECUTE_READWRITE);
 }
 #else
-static inline void *alloc_code_gen_buffer(void)
+static inline void *alloc_code_gen_buffer(bool no_rwx_pages)
 {
-#if defined(CONFIG_IOS_JIT)
     int prot = PROT_READ | PROT_EXEC;
-#else
-    int prot = PROT_WRITE | PROT_READ | PROT_EXEC;
-#endif
     int flags = MAP_PRIVATE | MAP_ANONYMOUS;
     size_t size = tcg_ctx->code_gen_buffer_size;
     void *buf;
 
+#if defined(CONFIG_DARWIN) /* both iOS and macOS (Apple Silicon) applicable */
+    if (!no_rwx_pages) {
+        prot |= PROT_WRITE;
+        flags |= MAP_JIT;
+    }
+#else
+    /* not applicable */
+    assert(!no_rwx_pages);
+    prot |= PROT_WRITE;
+#endif
+
     buf = mmap(NULL, size, prot, flags, -1, 0);
     if (buf == MAP_FAILED) {
         return NULL;
@@ -1174,10 +1185,10 @@ static inline void *alloc_jit_rw_mirror(void *base, size_t size)
 }
 #endif /* CONFIG_IOS_JIT */
 
-static inline void code_gen_alloc(size_t tb_size)
+static inline void code_gen_alloc(size_t tb_size, bool mirror_rwx)
 {
     tcg_ctx->code_gen_buffer_size = size_code_gen_buffer(tb_size);
-    tcg_ctx->code_gen_buffer = alloc_code_gen_buffer();
+    tcg_ctx->code_gen_buffer = alloc_code_gen_buffer(mirror_rwx);
     if (tcg_ctx->code_gen_buffer == NULL) {
         fprintf(stderr, "Could not allocate dynamic translator buffer\n");
         exit(1);
@@ -1185,13 +1196,18 @@ static inline void code_gen_alloc(size_t tb_size)
 #if defined(CONFIG_IOS_JIT)
     void *mirror;
 
-    /* For iOS JIT we need a mirror mapping for code execution */
-    mirror = alloc_jit_rw_mirror(tcg_ctx->code_gen_buffer,
-                                 tcg_ctx->code_gen_buffer_size
-                                );
-    if (mirror == NULL) {
-        fprintf(stderr, "Could not remap code buffer mirror\n");
-        exit(1);
+    if (mirror_rwx) {
+        /* For iOS JIT we need a mirror mapping for code execution */
+        mirror = alloc_jit_rw_mirror(tcg_ctx->code_gen_buffer,
+                                     tcg_ctx->code_gen_buffer_size
+                                    );
+        if (mirror == NULL) {
+            fprintf(stderr, "Could not remap code buffer mirror\n");
+            exit(1);
+        }
+    } else {
+        /* If we have JIT entitlements */
+        mirror = tcg_ctx->code_gen_buffer;
     }
     tcg_ctx->code_rw_mirror_diff = mirror - tcg_ctx->code_gen_buffer;
 #endif /* CONFIG_IOS_JIT */
@@ -1218,16 +1234,18 @@ static void tb_htable_init(void)
     qht_init(&tb_ctx.htable, tb_cmp, CODE_GEN_HTABLE_SIZE, mode);
 }
 
-/* Must be called before using the QEMU cpus. 'tb_size' is the size
-   (in bytes) allocated to the translation buffer. Zero means default
-   size. */
-void tcg_exec_init(unsigned long tb_size)
+/*
+ * Must be called before using the QEMU cpus. 'tb_size' is the size
+ * (in bytes) allocated to the translation buffer. Zero means default
+ * size. mirror_rwx only applicable on iOS.
+ */
+void tcg_exec_init(unsigned long tb_size, bool mirror_rwx)
 {
     tcg_allowed = true;
     cpu_gen_init();
     page_init();
     tb_htable_init();
-    code_gen_alloc(tb_size);
+    code_gen_alloc(tb_size, mirror_rwx);
 #if defined(CONFIG_SOFTMMU)
     /* There's no guest base to take into account, so go ahead and
        initialize the prologue now.  */
diff --git a/bsd-user/main.c b/bsd-user/main.c
index ac40d79bfa..ffd4888a26 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -910,7 +910,7 @@ int main(int argc, char **argv)
     }
 
     /* init tcg before creating CPUs and to get qemu_host_page_size */
-    tcg_exec_init(0);
+    tcg_exec_init(0, false);
 
     cpu_type = parse_cpu_option(cpu_model);
     cpu = cpu_create(cpu_type);
diff --git a/include/sysemu/tcg.h b/include/sysemu/tcg.h
index d9d3ca8559..569f90b11d 100644
--- a/include/sysemu/tcg.h
+++ b/include/sysemu/tcg.h
@@ -8,7 +8,7 @@
 #ifndef SYSEMU_TCG_H
 #define SYSEMU_TCG_H
 
-void tcg_exec_init(unsigned long tb_size);
+void tcg_exec_init(unsigned long tb_size, bool mirror_rwx);
 #ifdef CONFIG_TCG
 extern bool tcg_allowed;
 #define tcg_enabled() (tcg_allowed)
diff --git a/linux-user/main.c b/linux-user/main.c
index 75c9785157..3856b2611d 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -705,7 +705,7 @@ int main(int argc, char **argv, char **envp)
     cpu_type = parse_cpu_option(cpu_model);
 
     /* init tcg before creating CPUs and to get qemu_host_page_size */
-    tcg_exec_init(0);
+    tcg_exec_init(0, false);
 
     cpu = cpu_create(cpu_type);
     env = cpu->env_ptr;
diff --git a/qemu-options.hx b/qemu-options.hx
index 1da52a269c..deb39d56f5 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -123,6 +123,9 @@ DEF("accel", HAS_ARG, QEMU_OPTION_accel,
     "                igd-passthru=on|off (enable Xen integrated Intel graphics passthrough, default=off)\n"
     "                kernel-irqchip=on|off|split controls accelerated irqchip support (default=on)\n"
     "                kvm-shadow-mem=size of KVM shadow MMU in bytes\n"
+#ifdef CONFIG_IOS_JIT
+    "                mirror-rwx=on|off (mirror map executable pages for TCG on iOS)\n"
+#endif
     "                tb-size=n (TCG translation block cache size)\n"
     "                thread=single|multi (enable multi-threaded TCG)\n", QEMU_ARCH_ALL)
 SRST
@@ -148,6 +151,14 @@ SRST
     ``kvm-shadow-mem=size``
         Defines the size of the KVM shadow MMU.
 
+#ifdef CONFIG_IOS_JIT
+
+    ``mirror-rwx=on|off``
+        Only applicable to TCG running on iOS hosts. When enabled, TB code
+        is written to a mirror mapped address separate from the address that is
+        executed. By default, this is disabled.
+#endif
+
     ``tb-size=n``
         Controls the size (in MiB) of the TCG translation block cache.
 
-- 
2.24.3 (Apple Git-128)



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 09/10] tcg: support JIT on Apple Silicon
  2020-10-12 23:29 [PATCH 00/10] iOS and Apple Silicon host support Joelle van Dyne
                   ` (7 preceding siblings ...)
  2020-10-12 23:29 ` [PATCH 08/10] tcg: mirror mapping RWX pages for iOS optional Joelle van Dyne
@ 2020-10-12 23:29 ` Joelle van Dyne
  2020-10-13 13:55   ` Paolo Bonzini
  2020-10-12 23:29 ` [PATCH 10/10] block: check availablity for preadv/pwritev on mac Joelle van Dyne
  2020-10-13  1:21 ` [PATCH 00/10] iOS and Apple Silicon host support no-reply
  10 siblings, 1 reply; 47+ messages in thread
From: Joelle van Dyne @ 2020-10-12 23:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: Paolo Bonzini, Joelle van Dyne, Richard Henderson

From: osy <osy86@users.noreply.github.com>

https://developer.apple.com/documentation/apple_silicon/porting_just-in-time_compilers_to_apple_silicon

For < iOS 14, reverse engineered functions from libsystem_pthread.dylib is
implemented to handle APRR supported SoCs.

The following rules apply for JIT write protect:
  * JIT write-protect is enabled before tcg_qemu_tb_exec()
  * JIT write-protect is disabled after tcg_qemu_tb_exec() returns
  * JIT write-protect is disabled inside do_tb_phys_invalidate() but if it
    is called inside of tcg_qemu_tb_exec() then write-protect will be
    enabled again before returning.
  * JIT write-protect is disabled by cpu_loop_exit() for interrupt handling.
  * JIT write-protect is disabled everywhere else.

Signed-off-by: Joelle van Dyne <j@getutm.app>
---
 accel/tcg/cpu-exec-common.c |  2 +
 accel/tcg/cpu-exec.c        |  2 +
 accel/tcg/translate-all.c   | 51 ++++++++++++++++++++++
 configure                   | 20 +++++++++
 include/exec/exec-all.h     |  2 +
 include/tcg/tcg-apple-jit.h | 85 +++++++++++++++++++++++++++++++++++++
 include/tcg/tcg.h           |  3 ++
 tcg/tcg.c                   |  4 ++
 8 files changed, 169 insertions(+)
 create mode 100644 include/tcg/tcg-apple-jit.h

diff --git a/accel/tcg/cpu-exec-common.c b/accel/tcg/cpu-exec-common.c
index 12c1e3e974..f1eb767b02 100644
--- a/accel/tcg/cpu-exec-common.c
+++ b/accel/tcg/cpu-exec-common.c
@@ -64,6 +64,8 @@ void cpu_reloading_memory_map(void)
 
 void cpu_loop_exit(CPUState *cpu)
 {
+    /* Unlock JIT write protect if applicable. */
+    tb_exec_unlock();
     /* Undo the setting in cpu_tb_exec.  */
     cpu->can_do_io = 1;
     siglongjmp(cpu->jmp_env, 1);
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index 821aefdea2..d00d17f3c6 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -175,7 +175,9 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb)
     }
 #endif /* DEBUG_DISAS */
 
+    tb_exec_lock();
     ret = tcg_qemu_tb_exec(env, tb_ptr);
+    tb_exec_unlock();
     cpu->can_do_io = 1;
     last_tb = (TranslationBlock *)(ret & ~TB_EXIT_MASK);
     tb_exit = ret & TB_EXIT_MASK;
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index de9b7d9ab6..98daabbfc0 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -27,6 +27,9 @@
 #include "disas/disas.h"
 #include "exec/exec-all.h"
 #include "tcg/tcg.h"
+#if defined(CONFIG_DARWIN)
+#include "tcg/tcg-apple-jit.h"
+#endif
 #if defined(CONFIG_USER_ONLY)
 #include "qemu.h"
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
@@ -76,6 +79,9 @@ extern kern_return_t mach_vm_remap(vm_map_t target_task,
                                   );
 #endif
 
+static bool tb_exec_is_locked(void);
+static void tb_exec_change(bool locked);
+
 /* #define DEBUG_TB_INVALIDATE */
 /* #define DEBUG_TB_FLUSH */
 /* make various TB consistency checks */
@@ -1246,6 +1252,7 @@ void tcg_exec_init(unsigned long tb_size, bool mirror_rwx)
     page_init();
     tb_htable_init();
     code_gen_alloc(tb_size, mirror_rwx);
+    tb_exec_unlock();
 #if defined(CONFIG_SOFTMMU)
     /* There's no guest base to take into account, so go ahead and
        initialize the prologue now.  */
@@ -1522,8 +1529,11 @@ static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list)
     PageDesc *p;
     uint32_t h;
     tb_page_addr_t phys_pc;
+    bool code_gen_locked;
 
     assert_memory_lock();
+    code_gen_locked = tb_exec_is_locked();
+    tb_exec_unlock();
 
     /* make sure no further incoming jumps will be chained to this TB */
     qemu_spin_lock(&tb->jmp_lock);
@@ -1536,6 +1546,7 @@ static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list)
                      tb->trace_vcpu_dstate);
     if (!(tb->cflags & CF_NOCACHE) &&
         !qht_remove(&tb_ctx.htable, tb, h)) {
+        tb_exec_change(code_gen_locked);
         return;
     }
 
@@ -1568,6 +1579,8 @@ static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list)
 
     qatomic_set(&tcg_ctx->tb_phys_invalidate_count,
                tcg_ctx->tb_phys_invalidate_count + 1);
+
+    tb_exec_change(code_gen_locked);
 }
 
 static void tb_phys_invalidate__locked(TranslationBlock *tb)
@@ -2808,3 +2821,41 @@ void tcg_flush_softmmu_tlb(CPUState *cs)
     tlb_flush(cs);
 #endif
 }
+
+#if defined(CONFIG_DARWIN) && !defined(CONFIG_TCG_INTERPRETER)
+static bool tb_exec_is_locked(void)
+{
+    return tcg_ctx->code_gen_locked;
+}
+
+static void tb_exec_change(bool locked)
+{
+#if defined(HAVE_PTHREAD_JIT_PROTECT)
+    if (__builtin_available(macOS 11, iOS 14, watchOS 7, tvOS 14, *)) {
+        pthread_jit_write_protect_np(locked);
+    } else
+#endif
+    if (jit_write_protect_supported()) {
+        jit_write_protect(locked);
+    }
+    tcg_ctx->code_gen_locked = locked;
+}
+#else /* not needed on non-Darwin platforms */
+static bool tb_exec_is_locked(void)
+{
+    return false;
+}
+
+static void tb_exec_change(bool locked) {}
+#endif
+
+void tb_exec_lock(void)
+{
+    /* assumes sys_icache_invalidate already called */
+    tb_exec_change(true);
+}
+
+void tb_exec_unlock(void)
+{
+    tb_exec_change(false);
+}
diff --git a/configure b/configure
index c5a6584683..4c8cb63670 100755
--- a/configure
+++ b/configure
@@ -5874,6 +5874,22 @@ but not implemented on your system"
     fi
 fi
 
+##########################################
+# check for Apple Silicon JIT function
+
+if [ "$darwin" = "yes" ] ; then
+  cat > $TMPC << EOF
+#include <pthread.h>
+int main() { pthread_jit_write_protect_np(0); return 0; }
+EOF
+  if ! compile_prog ""; then
+    have_pthread_jit_protect='no'
+  else
+    have_pthread_jit_protect='yes'
+  fi
+fi
+
+
 ##########################################
 # End of CC checks
 # After here, no more $cc or $ld runs
@@ -6994,6 +7010,10 @@ if test "$secret_keyring" = "yes" ; then
   echo "CONFIG_SECRET_KEYRING=y" >> $config_host_mak
 fi
 
+if test "$have_pthread_jit_protect" = "yes" ; then
+  echo "HAVE_PTHREAD_JIT_PROTECT=y" >> $config_host_mak
+fi
+
 if test "$tcg_interpreter" = "yes"; then
   QEMU_INCLUDES="-iquote ${source_path}/tcg/tci $QEMU_INCLUDES"
 elif test "$ARCH" = "sparc64" ; then
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 2db155a772..253af30a2e 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -521,6 +521,8 @@ TranslationBlock *tb_htable_lookup(CPUState *cpu, target_ulong pc,
                                    target_ulong cs_base, uint32_t flags,
                                    uint32_t cf_mask);
 void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr);
+void tb_exec_lock(void);
+void tb_exec_unlock(void);
 
 /* GETPC is the true target of the return instruction that we'll execute.  */
 #if defined(CONFIG_TCG_INTERPRETER)
diff --git a/include/tcg/tcg-apple-jit.h b/include/tcg/tcg-apple-jit.h
new file mode 100644
index 0000000000..1e70bf3afe
--- /dev/null
+++ b/include/tcg/tcg-apple-jit.h
@@ -0,0 +1,85 @@
+/*
+ * Apple Silicon APRR functions for JIT handling
+ *
+ * Copyright (c) 2020 osy
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Credits to: https://siguza.github.io/APRR/
+ * Reversed from /usr/lib/system/libsystem_pthread.dylib
+ */
+
+#ifndef TCG_APPLE_JIT_H
+#define TCG_APPLE_JIT_H
+
+#if defined(__aarch64__) && defined(CONFIG_DARWIN)
+
+#define _COMM_PAGE_START_ADDRESS        (0x0000000FFFFFC000ULL) /* In TTBR0 */
+#define _COMM_PAGE_APRR_SUPPORT         (_COMM_PAGE_START_ADDRESS + 0x10C)
+#define _COMM_PAGE_APPR_WRITE_ENABLE    (_COMM_PAGE_START_ADDRESS + 0x110)
+#define _COMM_PAGE_APRR_WRITE_DISABLE   (_COMM_PAGE_START_ADDRESS + 0x118)
+
+static __attribute__((__always_inline__)) bool jit_write_protect_supported(void)
+{
+    /* Access shared kernel page at fixed memory location. */
+    uint8_t aprr_support = *(volatile uint8_t *)_COMM_PAGE_APRR_SUPPORT;
+    return aprr_support > 0;
+}
+
+/* write protect enable = write disable */
+static __attribute__((__always_inline__)) void jit_write_protect(int enabled)
+{
+    /* Access shared kernel page at fixed memory location. */
+    uint8_t aprr_support = *(volatile uint8_t *)_COMM_PAGE_APRR_SUPPORT;
+    if (aprr_support == 0 || aprr_support > 3) {
+        return;
+    } else if (aprr_support == 1) {
+        __asm__ __volatile__ (
+            "mov x0, %0\n"
+            "ldr x0, [x0]\n"
+            "msr S3_4_c15_c2_7, x0\n"
+            "isb sy\n"
+            :: "r" (enabled ? _COMM_PAGE_APRR_WRITE_DISABLE
+                            : _COMM_PAGE_APPR_WRITE_ENABLE)
+            : "memory", "x0"
+        );
+    } else {
+        __asm__ __volatile__ (
+            "mov x0, %0\n"
+            "ldr x0, [x0]\n"
+            "msr S3_6_c15_c1_5, x0\n"
+            "isb sy\n"
+            :: "r" (enabled ? _COMM_PAGE_APRR_WRITE_DISABLE
+                            : _COMM_PAGE_APPR_WRITE_ENABLE)
+            : "memory", "x0"
+        );
+    }
+}
+
+#else /* defined(__aarch64__) && defined(CONFIG_DARWIN) */
+
+static __attribute__((__always_inline__)) bool jit_write_protect_supported(void)
+{
+    return false;
+}
+
+static __attribute__((__always_inline__)) void jit_write_protect(int enabled)
+{
+}
+
+#endif
+
+#endif /* define TCG_APPLE_JIT_H */
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
index 40d1a7a85e..fbe00af4e1 100644
--- a/include/tcg/tcg.h
+++ b/include/tcg/tcg.h
@@ -630,6 +630,9 @@ struct TCGContext {
 #if defined(CONFIG_IOS_JIT)
     ptrdiff_t code_rw_mirror_diff;
 #endif
+#if defined(CONFIG_DARWIN) && !defined(CONFIG_TCG_INTERPRETER)
+    bool code_gen_locked; /* on Darwin each thread tracks W^X flags */
+#endif
 
     /* Threshold to flush the translated code buffer.  */
     void *code_gen_highwater;
diff --git a/tcg/tcg.c b/tcg/tcg.c
index ef203a34a6..244a0a43bf 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -781,6 +781,8 @@ static void alloc_tcg_plugin_context(TCGContext *s)
 void tcg_register_thread(void)
 {
     tcg_ctx = &tcg_init_ctx;
+
+    tb_exec_unlock();
 }
 #else
 void tcg_register_thread(void)
@@ -815,6 +817,8 @@ void tcg_register_thread(void)
     err = tcg_region_initial_alloc__locked(tcg_ctx);
     g_assert(!err);
     qemu_mutex_unlock(&region.lock);
+
+    tb_exec_unlock();
 }
 #endif /* !CONFIG_USER_ONLY */
 
-- 
2.24.3 (Apple Git-128)



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 10/10] block: check availablity for preadv/pwritev on mac
  2020-10-12 23:29 [PATCH 00/10] iOS and Apple Silicon host support Joelle van Dyne
                   ` (8 preceding siblings ...)
  2020-10-12 23:29 ` [PATCH 09/10] tcg: support JIT on Apple Silicon Joelle van Dyne
@ 2020-10-12 23:29 ` Joelle van Dyne
  2020-10-13  1:21 ` [PATCH 00/10] iOS and Apple Silicon host support no-reply
  10 siblings, 0 replies; 47+ messages in thread
From: Joelle van Dyne @ 2020-10-12 23:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Joelle van Dyne, open list:raw, Max Reitz

From: osy <osy86@users.noreply.github.com>

macOS 11/iOS 14 added preadv/pwritev APIs. Due to weak linking, configure
will succeed with CONFIG_PREADV even when targeting a lower OS version. We
therefore need to check at run time if we can actually use these APIs.

Signed-off-by: Joelle van Dyne <j@getutm.app>
---
 block/file-posix.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/block/file-posix.c b/block/file-posix.c
index cdc73b5f1d..d7482036a3 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -1393,12 +1393,24 @@ static bool preadv_present = true;
 static ssize_t
 qemu_preadv(int fd, const struct iovec *iov, int nr_iov, off_t offset)
 {
+#ifdef CONFIG_DARWIN /* preadv introduced in macOS 11 */
+    if (!__builtin_available(macOS 11, iOS 14, watchOS 7, tvOS 14, *)) {
+        preadv_present = false;
+        return -ENOSYS;
+    } else
+#endif
     return preadv(fd, iov, nr_iov, offset);
 }
 
 static ssize_t
 qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset)
 {
+#ifdef CONFIG_DARWIN /* pwritev introduced in macOS 11 */
+    if (!__builtin_available(macOS 11, iOS 14, watchOS 7, tvOS 14, *)) {
+        preadv_present = false;
+        return -ENOSYS;
+    } else
+#endif
     return pwritev(fd, iov, nr_iov, offset);
 }
 
-- 
2.24.3 (Apple Git-128)



^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: [PATCH 00/10] iOS and Apple Silicon host support
  2020-10-12 23:29 [PATCH 00/10] iOS and Apple Silicon host support Joelle van Dyne
                   ` (9 preceding siblings ...)
  2020-10-12 23:29 ` [PATCH 10/10] block: check availablity for preadv/pwritev on mac Joelle van Dyne
@ 2020-10-13  1:21 ` no-reply
  2020-10-13  2:12   ` Joelle van Dyne
  10 siblings, 1 reply; 47+ messages in thread
From: no-reply @ 2020-10-13  1:21 UTC (permalink / raw)
  To: j; +Cc: qemu-devel

Patchew URL: https://patchew.org/QEMU/20201012232939.48481-1-j@getutm.app/



Hi,

This series seems to have some coding style problems. See output below for
more information:

Type: series
Message-id: 20201012232939.48481-1-j@getutm.app
Subject: [PATCH 00/10] iOS and Apple Silicon host support

=== TEST SCRIPT BEGIN ===
#!/bin/bash
git rev-parse base > /dev/null || exit 0
git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram
./scripts/checkpatch.pl --mailback base..
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
From https://github.com/patchew-project/qemu
 * [new tag]         patchew/20201012232939.48481-1-j@getutm.app -> patchew/20201012232939.48481-1-j@getutm.app
Switched to a new branch 'test'
b6c449f block: check availablity for preadv/pwritev on mac
86f3837 tcg: support JIT on Apple Silicon
6389bee tcg: mirror mapping RWX pages for iOS optional
8727db6 tcg: implement bulletproof JIT
e655897 coroutine: add libucontext as external library
e43d59a slirp: update for iOS resolv fix
715f3bd meson: option to build as shared library
7276968 qemu: add support for iOS host
9f6bafb configure: cross-compiling without cross_prefix
9187922 configure: option to disable host block devices

=== OUTPUT BEGIN ===
1/10 Checking commit 9187922c6d93 (configure: option to disable host block devices)
WARNING: architecture specific defines should be avoided
#22: FILE: block/file-posix.c:44:
+#if defined(CONFIG_HOST_BLOCK_DEVICE) && defined(__APPLE__) && (__MACH__)

total: 0 errors, 1 warnings, 61 lines checked

Patch 1/10 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
2/10 Checking commit 9f6bafb19c1d (configure: cross-compiling without cross_prefix)
3/10 Checking commit 72769683dd9c (qemu: add support for iOS host)
WARNING: architecture specific defines should be avoided
#27: FILE: block.c:56:
+#if !defined(__DragonFly__) && !defined(CONFIG_IOS)

ERROR: braces {} are necessary for all arms of this statement
#45: FILE: block/file-posix.c:189:
+    if (s->fd >= 0)
[...]

WARNING: architecture specific defines should be avoided
#79: FILE: block/file-posix.c:2325:
+#if !defined(CONFIG_IOS) && defined(__APPLE__) && defined(__MACH__)

WARNING: architecture specific defines should be avoided
#363: FILE: tcg/aarch64/tcg-target.h:151:
+#if defined(__APPLE__)

WARNING: architecture specific defines should be avoided
#369: FILE: tcg/aarch64/tcg-target.h:157:
+#if defined(__APPLE__)

total: 1 errors, 4 warnings, 316 lines checked

Patch 3/10 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

4/10 Checking commit 715f3bddd393 (meson: option to build as shared library)
5/10 Checking commit e43d59afc25c (slirp: update for iOS resolv fix)
6/10 Checking commit e655897c7ab2 (coroutine: add libucontext as external library)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#97: 
new file mode 160000

total: 0 errors, 1 warnings, 140 lines checked

Patch 6/10 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
7/10 Checking commit 8727db6cfd2d (tcg: implement bulletproof JIT)
ERROR: externs should be avoided in .c files
#52: FILE: accel/tcg/translate-all.c:65:
+extern kern_return_t mach_vm_remap(vm_map_t target_task,

WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#189: 
new file mode 100644

WARNING: architecture specific defines should be avoided
#501: FILE: tcg/aarch64/tcg-target.h:171:
+#if defined(__APPLE__)

WARNING: architecture specific defines should be avoided
#757: FILE: tcg/i386/tcg-target.h:209:
+#ifdef __APPLE__

WARNING: architecture specific defines should be avoided
#768: FILE: tcg/i386/tcg-target.h:220:
+#if defined(__APPLE__)

total: 1 errors, 4 warnings, 1673 lines checked

Patch 7/10 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

8/10 Checking commit 6389bee4f3d0 (tcg: mirror mapping RWX pages for iOS optional)
9/10 Checking commit 86f3837d7074 (tcg: support JIT on Apple Silicon)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#206: 
new file mode 100644

WARNING: architecture specific defines should be avoided
#238: FILE: include/tcg/tcg-apple-jit.h:28:
+#if defined(__aarch64__) && defined(CONFIG_DARWIN)

total: 0 errors, 2 warnings, 259 lines checked

Patch 9/10 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
10/10 Checking commit b6c449ff37a3 (block: check availablity for preadv/pwritev on mac)
=== OUTPUT END ===

Test command exited with code: 1


The full log is available at
http://patchew.org/logs/20201012232939.48481-1-j@getutm.app/testing.checkpatch/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 00/10] iOS and Apple Silicon host support
  2020-10-13  1:21 ` [PATCH 00/10] iOS and Apple Silicon host support no-reply
@ 2020-10-13  2:12   ` Joelle van Dyne
  0 siblings, 0 replies; 47+ messages in thread
From: Joelle van Dyne @ 2020-10-13  2:12 UTC (permalink / raw)
  To: qemu-devel

I did run the style check tool. Of the errors/warnings, a few are from
code moved from one place to another, re-formatting the moved code
seems to break another rule (don't include irrelevant changes).



On Mon, Oct 12, 2020 at 6:21 PM <no-reply@patchew.org> wrote:
>
> Patchew URL: https://patchew.org/QEMU/20201012232939.48481-1-j@getutm.app/
>
>
>
> Hi,
>
> This series seems to have some coding style problems. See output below for
> more information:
>
> Type: series
> Message-id: 20201012232939.48481-1-j@getutm.app
> Subject: [PATCH 00/10] iOS and Apple Silicon host support
>
> === TEST SCRIPT BEGIN ===
> #!/bin/bash
> git rev-parse base > /dev/null || exit 0
> git config --local diff.renamelimit 0
> git config --local diff.renames True
> git config --local diff.algorithm histogram
> ./scripts/checkpatch.pl --mailback base..
> === TEST SCRIPT END ===
>
> Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
> From https://github.com/patchew-project/qemu
>  * [new tag]         patchew/20201012232939.48481-1-j@getutm.app -> patchew/20201012232939.48481-1-j@getutm.app
> Switched to a new branch 'test'
> b6c449f block: check availablity for preadv/pwritev on mac
> 86f3837 tcg: support JIT on Apple Silicon
> 6389bee tcg: mirror mapping RWX pages for iOS optional
> 8727db6 tcg: implement bulletproof JIT
> e655897 coroutine: add libucontext as external library
> e43d59a slirp: update for iOS resolv fix
> 715f3bd meson: option to build as shared library
> 7276968 qemu: add support for iOS host
> 9f6bafb configure: cross-compiling without cross_prefix
> 9187922 configure: option to disable host block devices
>
> === OUTPUT BEGIN ===
> 1/10 Checking commit 9187922c6d93 (configure: option to disable host block devices)
> WARNING: architecture specific defines should be avoided
> #22: FILE: block/file-posix.c:44:
> +#if defined(CONFIG_HOST_BLOCK_DEVICE) && defined(__APPLE__) && (__MACH__)
>
> total: 0 errors, 1 warnings, 61 lines checked
>
> Patch 1/10 has style problems, please review.  If any of these errors
> are false positives report them to the maintainer, see
> CHECKPATCH in MAINTAINERS.
> 2/10 Checking commit 9f6bafb19c1d (configure: cross-compiling without cross_prefix)
> 3/10 Checking commit 72769683dd9c (qemu: add support for iOS host)
> WARNING: architecture specific defines should be avoided
> #27: FILE: block.c:56:
> +#if !defined(__DragonFly__) && !defined(CONFIG_IOS)
>
> ERROR: braces {} are necessary for all arms of this statement
> #45: FILE: block/file-posix.c:189:
> +    if (s->fd >= 0)
> [...]
>
> WARNING: architecture specific defines should be avoided
> #79: FILE: block/file-posix.c:2325:
> +#if !defined(CONFIG_IOS) && defined(__APPLE__) && defined(__MACH__)
>
> WARNING: architecture specific defines should be avoided
> #363: FILE: tcg/aarch64/tcg-target.h:151:
> +#if defined(__APPLE__)
>
> WARNING: architecture specific defines should be avoided
> #369: FILE: tcg/aarch64/tcg-target.h:157:
> +#if defined(__APPLE__)
>
> total: 1 errors, 4 warnings, 316 lines checked
>
> Patch 3/10 has style problems, please review.  If any of these errors
> are false positives report them to the maintainer, see
> CHECKPATCH in MAINTAINERS.
>
> 4/10 Checking commit 715f3bddd393 (meson: option to build as shared library)
> 5/10 Checking commit e43d59afc25c (slirp: update for iOS resolv fix)
> 6/10 Checking commit e655897c7ab2 (coroutine: add libucontext as external library)
> WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
> #97:
> new file mode 160000
>
> total: 0 errors, 1 warnings, 140 lines checked
>
> Patch 6/10 has style problems, please review.  If any of these errors
> are false positives report them to the maintainer, see
> CHECKPATCH in MAINTAINERS.
> 7/10 Checking commit 8727db6cfd2d (tcg: implement bulletproof JIT)
> ERROR: externs should be avoided in .c files
> #52: FILE: accel/tcg/translate-all.c:65:
> +extern kern_return_t mach_vm_remap(vm_map_t target_task,
>
> WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
> #189:
> new file mode 100644
>
> WARNING: architecture specific defines should be avoided
> #501: FILE: tcg/aarch64/tcg-target.h:171:
> +#if defined(__APPLE__)
>
> WARNING: architecture specific defines should be avoided
> #757: FILE: tcg/i386/tcg-target.h:209:
> +#ifdef __APPLE__
>
> WARNING: architecture specific defines should be avoided
> #768: FILE: tcg/i386/tcg-target.h:220:
> +#if defined(__APPLE__)
>
> total: 1 errors, 4 warnings, 1673 lines checked
>
> Patch 7/10 has style problems, please review.  If any of these errors
> are false positives report them to the maintainer, see
> CHECKPATCH in MAINTAINERS.
>
> 8/10 Checking commit 6389bee4f3d0 (tcg: mirror mapping RWX pages for iOS optional)
> 9/10 Checking commit 86f3837d7074 (tcg: support JIT on Apple Silicon)
> WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
> #206:
> new file mode 100644
>
> WARNING: architecture specific defines should be avoided
> #238: FILE: include/tcg/tcg-apple-jit.h:28:
> +#if defined(__aarch64__) && defined(CONFIG_DARWIN)
>
> total: 0 errors, 2 warnings, 259 lines checked
>
> Patch 9/10 has style problems, please review.  If any of these errors
> are false positives report them to the maintainer, see
> CHECKPATCH in MAINTAINERS.
> 10/10 Checking commit b6c449ff37a3 (block: check availablity for preadv/pwritev on mac)
> === OUTPUT END ===
>
> Test command exited with code: 1
>
>
> The full log is available at
> http://patchew.org/logs/20201012232939.48481-1-j@getutm.app/testing.checkpatch/?type=message.
> ---
> Email generated automatically by Patchew [https://patchew.org/].
> Please send your feedback to patchew-devel@redhat.com


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 04/10] meson: option to build as shared library
  2020-10-12 23:29 ` [PATCH 04/10] meson: option to build as shared library Joelle van Dyne
@ 2020-10-13  7:51   ` Daniel P. Berrangé
  2020-10-13 14:41     ` BALATON Zoltan via
  0 siblings, 1 reply; 47+ messages in thread
From: Daniel P. Berrangé @ 2020-10-13  7:51 UTC (permalink / raw)
  To: Joelle van Dyne; +Cc: qemu-devel

On Mon, Oct 12, 2020 at 04:29:33PM -0700, Joelle van Dyne wrote:
> From: osy <osy86@users.noreply.github.com>
> 
> On iOS, we cannot fork() new processes, so the best way to load QEMU into an
> app is through a shared library. We add a new configure option
> `--enable-shared-lib` that will build the bulk of QEMU into a shared lib.
> The usual executables will then link to the library.

Note that QEMU as a combined work is licensed GPLv2-only, so if an app is
linking to it as a shared library, the application's license has to be
GPLv2 compatible. I fear that shipping as a shared library is an easy way
for apps to get into a license violating situation without realizing.

Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 07/10] tcg: implement bulletproof JIT
  2020-10-12 23:29   ` Joelle van Dyne
@ 2020-10-13  8:22     ` Philippe Mathieu-Daudé
  -1 siblings, 0 replies; 47+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-10-13  8:22 UTC (permalink / raw)
  To: Joelle van Dyne, qemu-devel
  Cc: Aleksandar Rikalo, open list:RISC-V TCG target, Stefan Weil,
	Aleksandar Markovic, open list:S390 TCG target,
	open list:AArch64 TCG target, Palmer Dabbelt, Paolo Bonzini,
	Huacai Chen, Alistair Francis, Aurelien Jarno, Richard Henderson

Hi Joelle,

On 10/13/20 1:29 AM, Joelle van Dyne wrote:
> From: osy <osy86@users.noreply.github.com>
> 
> On iOS, we cannot allocate RWX pages without special entitlements. As a
> workaround, we can a RX region and then mirror map it to a separate RX
> region. Then we can write to one region and execute from the other one.
> 
> To better keep track of pointers to RW/RX memory, we mark any tcg_insn_unit
> pointers as `const` if they will never be written to. We also define a new
> macro `TCG_CODE_PTR_RW` that returns a pointer to RW memory. Only the
> difference between the two regions is stored in the TCG context.

^ one change,

v another change. Consider splitting in 2 patches to ease review.

> 
> To ensure cache coherency, we flush the data cache in the RW mapping and
> then invalidate the instruction cache in the RX mapping (where applicable).
> Because data cache flush is OS defined on some architectures, we do not
> provide implementations for non iOS platforms (ARM/x86).
> 
> Signed-off-by: Joelle van Dyne <j@getutm.app>
> ---
>   accel/tcg/cpu-exec.c         |  7 +++-
>   accel/tcg/translate-all.c    | 78 ++++++++++++++++++++++++++++++++++--
>   configure                    |  1 +
>   docs/devel/ios.rst           | 40 ++++++++++++++++++
>   include/exec/exec-all.h      |  8 ++++
>   include/tcg/tcg.h            | 18 +++++++--
>   tcg/aarch64/tcg-target.c.inc | 48 +++++++++++++---------
>   tcg/aarch64/tcg-target.h     | 13 +++++-
>   tcg/arm/tcg-target.c.inc     | 33 ++++++++-------
>   tcg/arm/tcg-target.h         |  9 ++++-
>   tcg/i386/tcg-target.c.inc    | 28 ++++++-------
>   tcg/i386/tcg-target.h        | 24 ++++++++++-
>   tcg/mips/tcg-target.c.inc    | 64 +++++++++++++++++------------
>   tcg/mips/tcg-target.h        |  8 +++-
>   tcg/ppc/tcg-target.c.inc     | 55 ++++++++++++++++---------
>   tcg/ppc/tcg-target.h         |  8 +++-
>   tcg/riscv/tcg-target.c.inc   | 51 +++++++++++++----------
>   tcg/riscv/tcg-target.h       |  9 ++++-
>   tcg/s390/tcg-target.c.inc    | 25 ++++++------
>   tcg/s390/tcg-target.h        | 13 +++++-
>   tcg/sparc/tcg-target.c.inc   | 33 +++++++++------
>   tcg/sparc/tcg-target.h       |  8 +++-
>   tcg/tcg-ldst.c.inc           |  2 +-
>   tcg/tcg-pool.c.inc           |  9 +++--
>   tcg/tcg.c                    | 60 +++++++++++++++++----------
>   tcg/tci/tcg-target.c.inc     |  8 ++--
>   tcg/tci/tcg-target.h         |  9 ++++-
>   27 files changed, 481 insertions(+), 188 deletions(-)
>   create mode 100644 docs/devel/ios.rst

When posting big series, consider using scripts/git.orderfile.

Regards,

Phil.


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 07/10] tcg: implement bulletproof JIT
@ 2020-10-13  8:22     ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 47+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-10-13  8:22 UTC (permalink / raw)
  To: Joelle van Dyne, qemu-devel
  Cc: Aleksandar Rikalo, open list:RISC-V TCG target, Stefan Weil,
	open list:S390 TCG target, Jiaxun Yang, Aleksandar Markovic,
	open list:AArch64 TCG target, Palmer Dabbelt, Huacai Chen,
	Paolo Bonzini, Alistair Francis, Andrzej Zaborowski,
	Aurelien Jarno, Richard Henderson

Hi Joelle,

On 10/13/20 1:29 AM, Joelle van Dyne wrote:
> From: osy <osy86@users.noreply.github.com>
> 
> On iOS, we cannot allocate RWX pages without special entitlements. As a
> workaround, we can a RX region and then mirror map it to a separate RX
> region. Then we can write to one region and execute from the other one.
> 
> To better keep track of pointers to RW/RX memory, we mark any tcg_insn_unit
> pointers as `const` if they will never be written to. We also define a new
> macro `TCG_CODE_PTR_RW` that returns a pointer to RW memory. Only the
> difference between the two regions is stored in the TCG context.

^ one change,

v another change. Consider splitting in 2 patches to ease review.

> 
> To ensure cache coherency, we flush the data cache in the RW mapping and
> then invalidate the instruction cache in the RX mapping (where applicable).
> Because data cache flush is OS defined on some architectures, we do not
> provide implementations for non iOS platforms (ARM/x86).
> 
> Signed-off-by: Joelle van Dyne <j@getutm.app>
> ---
>   accel/tcg/cpu-exec.c         |  7 +++-
>   accel/tcg/translate-all.c    | 78 ++++++++++++++++++++++++++++++++++--
>   configure                    |  1 +
>   docs/devel/ios.rst           | 40 ++++++++++++++++++
>   include/exec/exec-all.h      |  8 ++++
>   include/tcg/tcg.h            | 18 +++++++--
>   tcg/aarch64/tcg-target.c.inc | 48 +++++++++++++---------
>   tcg/aarch64/tcg-target.h     | 13 +++++-
>   tcg/arm/tcg-target.c.inc     | 33 ++++++++-------
>   tcg/arm/tcg-target.h         |  9 ++++-
>   tcg/i386/tcg-target.c.inc    | 28 ++++++-------
>   tcg/i386/tcg-target.h        | 24 ++++++++++-
>   tcg/mips/tcg-target.c.inc    | 64 +++++++++++++++++------------
>   tcg/mips/tcg-target.h        |  8 +++-
>   tcg/ppc/tcg-target.c.inc     | 55 ++++++++++++++++---------
>   tcg/ppc/tcg-target.h         |  8 +++-
>   tcg/riscv/tcg-target.c.inc   | 51 +++++++++++++----------
>   tcg/riscv/tcg-target.h       |  9 ++++-
>   tcg/s390/tcg-target.c.inc    | 25 ++++++------
>   tcg/s390/tcg-target.h        | 13 +++++-
>   tcg/sparc/tcg-target.c.inc   | 33 +++++++++------
>   tcg/sparc/tcg-target.h       |  8 +++-
>   tcg/tcg-ldst.c.inc           |  2 +-
>   tcg/tcg-pool.c.inc           |  9 +++--
>   tcg/tcg.c                    | 60 +++++++++++++++++----------
>   tcg/tci/tcg-target.c.inc     |  8 ++--
>   tcg/tci/tcg-target.h         |  9 ++++-
>   27 files changed, 481 insertions(+), 188 deletions(-)
>   create mode 100644 docs/devel/ios.rst

When posting big series, consider using scripts/git.orderfile.

Regards,

Phil.


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 06/10] coroutine: add libucontext as external library
  2020-10-12 23:29 ` [PATCH 06/10] coroutine: add libucontext as external library Joelle van Dyne
@ 2020-10-13 13:31   ` Stefan Hajnoczi
  2020-10-13 14:49     ` BALATON Zoltan via
  0 siblings, 1 reply; 47+ messages in thread
From: Stefan Hajnoczi @ 2020-10-13 13:31 UTC (permalink / raw)
  To: Joelle van Dyne; +Cc: Kevin Wolf, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 907 bytes --]

On Mon, Oct 12, 2020 at 04:29:35PM -0700, Joelle van Dyne wrote:
> From: osy <osy86@users.noreply.github.com>
> 
> iOS does not support ucontext natively for aarch64 and the sigaltstack is
> also unsupported (even worse, it fails silently, see:
> https://openradar.appspot.com/13002712 )
> 
> As a workaround we include a library implementation of ucontext and add it
> as a build option.
> 
> Signed-off-by: Joelle van Dyne <j@getutm.app>

Hi,
Thanks for sending posting this!

Please indicate what license libucontext is under, that it is compatible
with QEMU's overall GPL v2 license, and update QEMU license
documentation (LICENSE, etc), if necessary.

Please update .gitlab-ci.yml with build tests. Is there a way to test
building QEMU for iOS? If not, then it's difficult for the upstream QEMU
project to carry iOS-specific features since we cannot test them.

Thanks,
Stefan

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 05/10] slirp: update for iOS resolv fix
  2020-10-12 23:29 ` [PATCH 05/10] slirp: update for iOS resolv fix Joelle van Dyne
@ 2020-10-13 13:32   ` Philippe Mathieu-Daudé
  2020-10-13 14:38     ` Marc-André Lureau
  0 siblings, 1 reply; 47+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-10-13 13:32 UTC (permalink / raw)
  To: Joelle van Dyne, qemu-devel

On 10/13/20 1:29 AM, Joelle van Dyne wrote:
> From: osy <osy86@users.noreply.github.com>
> 
> We cannot access /etc/resolv.conf on iOS so libslirp is modified to use
> libresolv instead.
> 
> Signed-off-by: Joelle van Dyne <j@getutm.app>
> ---
>   .gitmodules | 2 +-
>   meson.build | 2 ++
>   slirp       | 2 +-
>   3 files changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/.gitmodules b/.gitmodules
> index 2bdeeacef8..f23e859210 100644
> --- a/.gitmodules
> +++ b/.gitmodules
> @@ -51,7 +51,7 @@
>   	url = https://git.qemu.org/git/edk2.git
>   [submodule "slirp"]
>   	path = slirp
> -	url = https://git.qemu.org/git/libslirp.git
> +	url = https://github.com/utmapp/libslirp.git

NAck.

You can not take over the SLiRP project submodule that way.

I suggest getting your SLiRP changes merged with mainstream
instead, see:
https://gitlab.freedesktop.org/slirp/libslirp#contributing

>   [submodule "roms/opensbi"]
>   	path = roms/opensbi
>   	url = 	https://git.qemu.org/git/opensbi.git
> diff --git a/meson.build b/meson.build
> index 32cf08619f..da96e296e0 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -996,6 +996,8 @@ if have_system
>       slirp_deps = []
>       if targetos == 'windows'
>         slirp_deps = cc.find_library('iphlpapi')
> +    elif targetos == 'darwin'
> +      slirp_deps = cc.find_library('resolv')
>       endif
>       slirp_conf = configuration_data()
>       slirp_conf.set('SLIRP_MAJOR_VERSION', meson.project_version().split('.')[0])
> diff --git a/slirp b/slirp
> index ce94eba204..452c389d82 160000
> --- a/slirp
> +++ b/slirp
> @@ -1 +1 @@
> -Subproject commit ce94eba2042d52a0ba3d9e252ebce86715e94275
> +Subproject commit 452c389d8288f81ec9d59d983a047d4e54f3194e



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 08/10] tcg: mirror mapping RWX pages for iOS optional
  2020-10-12 23:29 ` [PATCH 08/10] tcg: mirror mapping RWX pages for iOS optional Joelle van Dyne
@ 2020-10-13 13:52   ` Paolo Bonzini
  2020-10-13 15:10     ` Joelle van Dyne
  0 siblings, 1 reply; 47+ messages in thread
From: Paolo Bonzini @ 2020-10-13 13:52 UTC (permalink / raw)
  To: Joelle van Dyne, qemu-devel; +Cc: Laurent Vivier, Richard Henderson

On 13/10/20 01:29, Joelle van Dyne wrote:
> From: osy <osy86@users.noreply.github.com>
> 
> This allows jailbroken devices with entitlements to switch the option off.
> 
> Signed-off-by: Joelle van Dyne <j@getutm.app>
> ---

What is the advantage in doing so?

Paolo



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 09/10] tcg: support JIT on Apple Silicon
  2020-10-12 23:29 ` [PATCH 09/10] tcg: support JIT on Apple Silicon Joelle van Dyne
@ 2020-10-13 13:55   ` Paolo Bonzini
  2020-10-13 14:09     ` Peter Maydell
  0 siblings, 1 reply; 47+ messages in thread
From: Paolo Bonzini @ 2020-10-13 13:55 UTC (permalink / raw)
  To: Joelle van Dyne, qemu-devel; +Cc: Richard Henderson

On 13/10/20 01:29, Joelle van Dyne wrote:
> From: osy <osy86@users.noreply.github.com>
> 
> https://developer.apple.com/documentation/apple_silicon/porting_just-in-time_compilers_to_apple_silicon
> 
> For < iOS 14, reverse engineered functions from libsystem_pthread.dylib is
> implemented to handle APRR supported SoCs.
> 
> The following rules apply for JIT write protect:
>   * JIT write-protect is enabled before tcg_qemu_tb_exec()
>   * JIT write-protect is disabled after tcg_qemu_tb_exec() returns
>   * JIT write-protect is disabled inside do_tb_phys_invalidate() but if it
>     is called inside of tcg_qemu_tb_exec() then write-protect will be
>     enabled again before returning.
>   * JIT write-protect is disabled by cpu_loop_exit() for interrupt handling.
>   * JIT write-protect is disabled everywhere else.
> 
> Signed-off-by: Joelle van Dyne <j@getutm.app>

Can this be emulated somehow on other platforms (such as Linux) so that
it does not bitrot?

Paolo

> ---
>  accel/tcg/cpu-exec-common.c |  2 +
>  accel/tcg/cpu-exec.c        |  2 +
>  accel/tcg/translate-all.c   | 51 ++++++++++++++++++++++
>  configure                   | 20 +++++++++
>  include/exec/exec-all.h     |  2 +
>  include/tcg/tcg-apple-jit.h | 85 +++++++++++++++++++++++++++++++++++++
>  include/tcg/tcg.h           |  3 ++
>  tcg/tcg.c                   |  4 ++
>  8 files changed, 169 insertions(+)
>  create mode 100644 include/tcg/tcg-apple-jit.h
> 
> diff --git a/accel/tcg/cpu-exec-common.c b/accel/tcg/cpu-exec-common.c
> index 12c1e3e974..f1eb767b02 100644
> --- a/accel/tcg/cpu-exec-common.c
> +++ b/accel/tcg/cpu-exec-common.c
> @@ -64,6 +64,8 @@ void cpu_reloading_memory_map(void)
>  
>  void cpu_loop_exit(CPUState *cpu)
>  {
> +    /* Unlock JIT write protect if applicable. */
> +    tb_exec_unlock();
>      /* Undo the setting in cpu_tb_exec.  */
>      cpu->can_do_io = 1;
>      siglongjmp(cpu->jmp_env, 1);
> diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
> index 821aefdea2..d00d17f3c6 100644
> --- a/accel/tcg/cpu-exec.c
> +++ b/accel/tcg/cpu-exec.c
> @@ -175,7 +175,9 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb)
>      }
>  #endif /* DEBUG_DISAS */
>  
> +    tb_exec_lock();
>      ret = tcg_qemu_tb_exec(env, tb_ptr);
> +    tb_exec_unlock();
>      cpu->can_do_io = 1;
>      last_tb = (TranslationBlock *)(ret & ~TB_EXIT_MASK);
>      tb_exit = ret & TB_EXIT_MASK;
> diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
> index de9b7d9ab6..98daabbfc0 100644
> --- a/accel/tcg/translate-all.c
> +++ b/accel/tcg/translate-all.c
> @@ -27,6 +27,9 @@
>  #include "disas/disas.h"
>  #include "exec/exec-all.h"
>  #include "tcg/tcg.h"
> +#if defined(CONFIG_DARWIN)
> +#include "tcg/tcg-apple-jit.h"
> +#endif
>  #if defined(CONFIG_USER_ONLY)
>  #include "qemu.h"
>  #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
> @@ -76,6 +79,9 @@ extern kern_return_t mach_vm_remap(vm_map_t target_task,
>                                    );
>  #endif
>  
> +static bool tb_exec_is_locked(void);
> +static void tb_exec_change(bool locked);
> +
>  /* #define DEBUG_TB_INVALIDATE */
>  /* #define DEBUG_TB_FLUSH */
>  /* make various TB consistency checks */
> @@ -1246,6 +1252,7 @@ void tcg_exec_init(unsigned long tb_size, bool mirror_rwx)
>      page_init();
>      tb_htable_init();
>      code_gen_alloc(tb_size, mirror_rwx);
> +    tb_exec_unlock();
>  #if defined(CONFIG_SOFTMMU)
>      /* There's no guest base to take into account, so go ahead and
>         initialize the prologue now.  */
> @@ -1522,8 +1529,11 @@ static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list)
>      PageDesc *p;
>      uint32_t h;
>      tb_page_addr_t phys_pc;
> +    bool code_gen_locked;
>  
>      assert_memory_lock();
> +    code_gen_locked = tb_exec_is_locked();
> +    tb_exec_unlock();
>  
>      /* make sure no further incoming jumps will be chained to this TB */
>      qemu_spin_lock(&tb->jmp_lock);
> @@ -1536,6 +1546,7 @@ static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list)
>                       tb->trace_vcpu_dstate);
>      if (!(tb->cflags & CF_NOCACHE) &&
>          !qht_remove(&tb_ctx.htable, tb, h)) {
> +        tb_exec_change(code_gen_locked);
>          return;
>      }
>  
> @@ -1568,6 +1579,8 @@ static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list)
>  
>      qatomic_set(&tcg_ctx->tb_phys_invalidate_count,
>                 tcg_ctx->tb_phys_invalidate_count + 1);
> +
> +    tb_exec_change(code_gen_locked);
>  }
>  
>  static void tb_phys_invalidate__locked(TranslationBlock *tb)
> @@ -2808,3 +2821,41 @@ void tcg_flush_softmmu_tlb(CPUState *cs)
>      tlb_flush(cs);
>  #endif
>  }
> +
> +#if defined(CONFIG_DARWIN) && !defined(CONFIG_TCG_INTERPRETER)
> +static bool tb_exec_is_locked(void)
> +{
> +    return tcg_ctx->code_gen_locked;
> +}
> +
> +static void tb_exec_change(bool locked)
> +{
> +#if defined(HAVE_PTHREAD_JIT_PROTECT)
> +    if (__builtin_available(macOS 11, iOS 14, watchOS 7, tvOS 14, *)) {
> +        pthread_jit_write_protect_np(locked);
> +    } else
> +#endif
> +    if (jit_write_protect_supported()) {
> +        jit_write_protect(locked);
> +    }
> +    tcg_ctx->code_gen_locked = locked;
> +}
> +#else /* not needed on non-Darwin platforms */
> +static bool tb_exec_is_locked(void)
> +{
> +    return false;
> +}
> +
> +static void tb_exec_change(bool locked) {}
> +#endif
> +
> +void tb_exec_lock(void)
> +{
> +    /* assumes sys_icache_invalidate already called */
> +    tb_exec_change(true);
> +}
> +
> +void tb_exec_unlock(void)
> +{
> +    tb_exec_change(false);
> +}
> diff --git a/configure b/configure
> index c5a6584683..4c8cb63670 100755
> --- a/configure
> +++ b/configure
> @@ -5874,6 +5874,22 @@ but not implemented on your system"
>      fi
>  fi
>  
> +##########################################
> +# check for Apple Silicon JIT function
> +
> +if [ "$darwin" = "yes" ] ; then
> +  cat > $TMPC << EOF
> +#include <pthread.h>
> +int main() { pthread_jit_write_protect_np(0); return 0; }
> +EOF
> +  if ! compile_prog ""; then
> +    have_pthread_jit_protect='no'
> +  else
> +    have_pthread_jit_protect='yes'
> +  fi
> +fi
> +
> +
>  ##########################################
>  # End of CC checks
>  # After here, no more $cc or $ld runs
> @@ -6994,6 +7010,10 @@ if test "$secret_keyring" = "yes" ; then
>    echo "CONFIG_SECRET_KEYRING=y" >> $config_host_mak
>  fi
>  
> +if test "$have_pthread_jit_protect" = "yes" ; then
> +  echo "HAVE_PTHREAD_JIT_PROTECT=y" >> $config_host_mak
> +fi
> +
>  if test "$tcg_interpreter" = "yes"; then
>    QEMU_INCLUDES="-iquote ${source_path}/tcg/tci $QEMU_INCLUDES"
>  elif test "$ARCH" = "sparc64" ; then
> diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
> index 2db155a772..253af30a2e 100644
> --- a/include/exec/exec-all.h
> +++ b/include/exec/exec-all.h
> @@ -521,6 +521,8 @@ TranslationBlock *tb_htable_lookup(CPUState *cpu, target_ulong pc,
>                                     target_ulong cs_base, uint32_t flags,
>                                     uint32_t cf_mask);
>  void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr);
> +void tb_exec_lock(void);
> +void tb_exec_unlock(void);
>  
>  /* GETPC is the true target of the return instruction that we'll execute.  */
>  #if defined(CONFIG_TCG_INTERPRETER)
> diff --git a/include/tcg/tcg-apple-jit.h b/include/tcg/tcg-apple-jit.h
> new file mode 100644
> index 0000000000..1e70bf3afe
> --- /dev/null
> +++ b/include/tcg/tcg-apple-jit.h
> @@ -0,0 +1,85 @@
> +/*
> + * Apple Silicon APRR functions for JIT handling
> + *
> + * Copyright (c) 2020 osy
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +/*
> + * Credits to: https://siguza.github.io/APRR/
> + * Reversed from /usr/lib/system/libsystem_pthread.dylib
> + */
> +
> +#ifndef TCG_APPLE_JIT_H
> +#define TCG_APPLE_JIT_H
> +
> +#if defined(__aarch64__) && defined(CONFIG_DARWIN)
> +
> +#define _COMM_PAGE_START_ADDRESS        (0x0000000FFFFFC000ULL) /* In TTBR0 */
> +#define _COMM_PAGE_APRR_SUPPORT         (_COMM_PAGE_START_ADDRESS + 0x10C)
> +#define _COMM_PAGE_APPR_WRITE_ENABLE    (_COMM_PAGE_START_ADDRESS + 0x110)
> +#define _COMM_PAGE_APRR_WRITE_DISABLE   (_COMM_PAGE_START_ADDRESS + 0x118)
> +
> +static __attribute__((__always_inline__)) bool jit_write_protect_supported(void)
> +{
> +    /* Access shared kernel page at fixed memory location. */
> +    uint8_t aprr_support = *(volatile uint8_t *)_COMM_PAGE_APRR_SUPPORT;
> +    return aprr_support > 0;
> +}
> +
> +/* write protect enable = write disable */
> +static __attribute__((__always_inline__)) void jit_write_protect(int enabled)
> +{
> +    /* Access shared kernel page at fixed memory location. */
> +    uint8_t aprr_support = *(volatile uint8_t *)_COMM_PAGE_APRR_SUPPORT;
> +    if (aprr_support == 0 || aprr_support > 3) {
> +        return;
> +    } else if (aprr_support == 1) {
> +        __asm__ __volatile__ (
> +            "mov x0, %0\n"
> +            "ldr x0, [x0]\n"
> +            "msr S3_4_c15_c2_7, x0\n"
> +            "isb sy\n"
> +            :: "r" (enabled ? _COMM_PAGE_APRR_WRITE_DISABLE
> +                            : _COMM_PAGE_APPR_WRITE_ENABLE)
> +            : "memory", "x0"
> +        );
> +    } else {
> +        __asm__ __volatile__ (
> +            "mov x0, %0\n"
> +            "ldr x0, [x0]\n"
> +            "msr S3_6_c15_c1_5, x0\n"
> +            "isb sy\n"
> +            :: "r" (enabled ? _COMM_PAGE_APRR_WRITE_DISABLE
> +                            : _COMM_PAGE_APPR_WRITE_ENABLE)
> +            : "memory", "x0"
> +        );
> +    }
> +}
> +
> +#else /* defined(__aarch64__) && defined(CONFIG_DARWIN) */
> +
> +static __attribute__((__always_inline__)) bool jit_write_protect_supported(void)
> +{
> +    return false;
> +}
> +
> +static __attribute__((__always_inline__)) void jit_write_protect(int enabled)
> +{
> +}
> +
> +#endif
> +
> +#endif /* define TCG_APPLE_JIT_H */
> diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
> index 40d1a7a85e..fbe00af4e1 100644
> --- a/include/tcg/tcg.h
> +++ b/include/tcg/tcg.h
> @@ -630,6 +630,9 @@ struct TCGContext {
>  #if defined(CONFIG_IOS_JIT)
>      ptrdiff_t code_rw_mirror_diff;
>  #endif
> +#if defined(CONFIG_DARWIN) && !defined(CONFIG_TCG_INTERPRETER)
> +    bool code_gen_locked; /* on Darwin each thread tracks W^X flags */
> +#endif
>  
>      /* Threshold to flush the translated code buffer.  */
>      void *code_gen_highwater;
> diff --git a/tcg/tcg.c b/tcg/tcg.c
> index ef203a34a6..244a0a43bf 100644
> --- a/tcg/tcg.c
> +++ b/tcg/tcg.c
> @@ -781,6 +781,8 @@ static void alloc_tcg_plugin_context(TCGContext *s)
>  void tcg_register_thread(void)
>  {
>      tcg_ctx = &tcg_init_ctx;
> +
> +    tb_exec_unlock();
>  }
>  #else
>  void tcg_register_thread(void)
> @@ -815,6 +817,8 @@ void tcg_register_thread(void)
>      err = tcg_region_initial_alloc__locked(tcg_ctx);
>      g_assert(!err);
>      qemu_mutex_unlock(&region.lock);
> +
> +    tb_exec_unlock();
>  }
>  #endif /* !CONFIG_USER_ONLY */
>  
> 



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 09/10] tcg: support JIT on Apple Silicon
  2020-10-13 13:55   ` Paolo Bonzini
@ 2020-10-13 14:09     ` Peter Maydell
  2020-10-13 15:13       ` Joelle van Dyne
  0 siblings, 1 reply; 47+ messages in thread
From: Peter Maydell @ 2020-10-13 14:09 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: Richard Henderson, Joelle van Dyne, QEMU Developers

On Tue, 13 Oct 2020 at 14:58, Paolo Bonzini <pbonzini@redhat.com> wrote:
>
> On 13/10/20 01:29, Joelle van Dyne wrote:
> > From: osy <osy86@users.noreply.github.com>
> >
> > https://developer.apple.com/documentation/apple_silicon/porting_just-in-time_compilers_to_apple_silicon
> >
> > For < iOS 14, reverse engineered functions from libsystem_pthread.dylib is
> > implemented to handle APRR supported SoCs.
> >
> > The following rules apply for JIT write protect:
> >   * JIT write-protect is enabled before tcg_qemu_tb_exec()
> >   * JIT write-protect is disabled after tcg_qemu_tb_exec() returns
> >   * JIT write-protect is disabled inside do_tb_phys_invalidate() but if it
> >     is called inside of tcg_qemu_tb_exec() then write-protect will be
> >     enabled again before returning.
> >   * JIT write-protect is disabled by cpu_loop_exit() for interrupt handling.
> >   * JIT write-protect is disabled everywhere else.
> >
> > Signed-off-by: Joelle van Dyne <j@getutm.app>
>
> Can this be emulated somehow on other platforms (such as Linux) so that
> it does not bitrot?

Some of it is write^execute, which we could test via OpenBSD
I think if we updated our VM image not to mount the disk
with that protection disabled. Having "generically support
w^x" be separate from "iOS specifics" might be useful.

The apple.com webpage linked above suggests also that we could
test some at least of these APIs on our OSX builds if we
enable the "hardened runtime" on x86 (though that might also
enable other stuff we don't want to deal with? no idea)

thanks
-- PMM


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 05/10] slirp: update for iOS resolv fix
  2020-10-13 13:32   ` Philippe Mathieu-Daudé
@ 2020-10-13 14:38     ` Marc-André Lureau
  2020-10-13 14:59       ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 47+ messages in thread
From: Marc-André Lureau @ 2020-10-13 14:38 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé; +Cc: Joelle van Dyne, QEMU

[-- Attachment #1: Type: text/plain, Size: 2298 bytes --]

Hi

On Tue, Oct 13, 2020 at 5:34 PM Philippe Mathieu-Daudé <philmd@redhat.com>
wrote:

> On 10/13/20 1:29 AM, Joelle van Dyne wrote:
> > From: osy <osy86@users.noreply.github.com>
> >
> > We cannot access /etc/resolv.conf on iOS so libslirp is modified to use
> > libresolv instead.
> >
> > Signed-off-by: Joelle van Dyne <j@getutm.app>
> > ---
> >   .gitmodules | 2 +-
> >   meson.build | 2 ++
> >   slirp       | 2 +-
> >   3 files changed, 4 insertions(+), 2 deletions(-)
> >
> > diff --git a/.gitmodules b/.gitmodules
> > index 2bdeeacef8..f23e859210 100644
> > --- a/.gitmodules
> > +++ b/.gitmodules
> > @@ -51,7 +51,7 @@
> >       url = https://git.qemu.org/git/edk2.git
> >   [submodule "slirp"]
> >       path = slirp
> > -     url = https://git.qemu.org/git/libslirp.git
> > +     url = https://github.com/utmapp/libslirp.git
>
> NAck.
>
> You can not take over the SLiRP project submodule that way.
>
> I suggest getting your SLiRP changes merged with mainstream
> instead, see:
> https://gitlab.freedesktop.org/slirp/libslirp#contributing
>
>
I think he did:
https://gitlab.freedesktop.org/slirp/libslirp/-/merge_requests/54

Btw, I also noticed the coroutine library submodule proposed in this series
is a fork from the original library. Not sure what the upstream status is
and whether this is fine.

>   [submodule "roms/opensbi"]
> >       path = roms/opensbi
> >       url =   https://git.qemu.org/git/opensbi.git
> > diff --git a/meson.build b/meson.build
> > index 32cf08619f..da96e296e0 100644
> > --- a/meson.build
> > +++ b/meson.build
> > @@ -996,6 +996,8 @@ if have_system
> >       slirp_deps = []
> >       if targetos == 'windows'
> >         slirp_deps = cc.find_library('iphlpapi')
> > +    elif targetos == 'darwin'
> > +      slirp_deps = cc.find_library('resolv')
> >       endif
> >       slirp_conf = configuration_data()
> >       slirp_conf.set('SLIRP_MAJOR_VERSION',
> meson.project_version().split('.')[0])
> > diff --git a/slirp b/slirp
> > index ce94eba204..452c389d82 160000
> > --- a/slirp
> > +++ b/slirp
> > @@ -1 +1 @@
> > -Subproject commit ce94eba2042d52a0ba3d9e252ebce86715e94275
> > +Subproject commit 452c389d8288f81ec9d59d983a047d4e54f3194e
>
>
>

-- 
Marc-André Lureau

[-- Attachment #2: Type: text/html, Size: 3844 bytes --]

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 04/10] meson: option to build as shared library
  2020-10-13  7:51   ` Daniel P. Berrangé
@ 2020-10-13 14:41     ` BALATON Zoltan via
  2020-10-13 14:46       ` Daniel P. Berrangé
  0 siblings, 1 reply; 47+ messages in thread
From: BALATON Zoltan via @ 2020-10-13 14:41 UTC (permalink / raw)
  To: Daniel P. Berrangé; +Cc: Joelle van Dyne, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 2221 bytes --]

On Tue, 13 Oct 2020, Daniel P. Berrangé wrote:
> On Mon, Oct 12, 2020 at 04:29:33PM -0700, Joelle van Dyne wrote:
>> From: osy <osy86@users.noreply.github.com>
>>
>> On iOS, we cannot fork() new processes, so the best way to load QEMU into an
>> app is through a shared library. We add a new configure option
>> `--enable-shared-lib` that will build the bulk of QEMU into a shared lib.
>> The usual executables will then link to the library.
>
> Note that QEMU as a combined work is licensed GPLv2-only, so if an app is
> linking to it as a shared library, the application's license has to be
> GPLv2 compatible. I fear that shipping as a shared library is an easy way
> for apps to get into a license violating situation without realizing.

Please don't let that be an obstacle in merging this series. They'll do it 
anyway as seen here so having it upstream is probably better than having a 
lot of different/divergent forks.

In case of UTM it seems to be licensed under Apache License 2.0:

https://github.com/utmapp/UTM/blob/master/LICENSE

which FSF says not compatible with GPLv2 but it is with GPLv3:

http://www.gnu.org/licenses/license-list.html#apache2

Not sure however if that's for using Apache licenced part in GPLv2 code or 
the other way around like in UTM in which case I think the whole work will 
effectively become GPLv3 as most parts of QEMU is probably GPLv2+ already 
or BSD like free that should be possible to combine with only files 
explicitely GPLv2 in QEMU remaining at that license and UTM parts are 
Apache 2.0 when separated from QEMU. I have no idea about legal stuff 
whatsoever but combining two free software components should be legal some 
way (otherwise it's not possible to combine GPLv2 with GPLv3 either).

I hope this does not turn into a legal bike shedding thread that results 
in finding out there are other than technical problems in the way to 
accept this series but the contrary, I'd say let the legal problems be 
handled by those using QEMU and don't reject patches based on maybe 
possible legal problems. Stating the licence clearly and maybe providing 
links to further resources to resolve licence problems in QEMU docs should 
be enough.

Regards,
BALATON Zoltan

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 04/10] meson: option to build as shared library
  2020-10-13 14:41     ` BALATON Zoltan via
@ 2020-10-13 14:46       ` Daniel P. Berrangé
  2020-10-13 15:16         ` Joelle van Dyne
  2020-10-13 15:23         ` BALATON Zoltan via
  0 siblings, 2 replies; 47+ messages in thread
From: Daniel P. Berrangé @ 2020-10-13 14:46 UTC (permalink / raw)
  To: BALATON Zoltan; +Cc: Joelle van Dyne, qemu-devel

On Tue, Oct 13, 2020 at 04:41:06PM +0200, BALATON Zoltan wrote:
> On Tue, 13 Oct 2020, Daniel P. Berrangé wrote:
> > On Mon, Oct 12, 2020 at 04:29:33PM -0700, Joelle van Dyne wrote:
> > > From: osy <osy86@users.noreply.github.com>
> > > 
> > > On iOS, we cannot fork() new processes, so the best way to load QEMU into an
> > > app is through a shared library. We add a new configure option
> > > `--enable-shared-lib` that will build the bulk of QEMU into a shared lib.
> > > The usual executables will then link to the library.
> > 
> > Note that QEMU as a combined work is licensed GPLv2-only, so if an app is
> > linking to it as a shared library, the application's license has to be
> > GPLv2 compatible. I fear that shipping as a shared library is an easy way
> > for apps to get into a license violating situation without realizing.
> 
> Please don't let that be an obstacle in merging this series. They'll do it
> anyway as seen here so having it upstream is probably better than having a
> lot of different/divergent forks.

"They'll violate the license anyway" is not a compelling argument.

> In case of UTM it seems to be licensed under Apache License 2.0:
> 
> https://github.com/utmapp/UTM/blob/master/LICENSE
> 
> which FSF says not compatible with GPLv2 but it is with GPLv3:
> 
> http://www.gnu.org/licenses/license-list.html#apache2
> 
> Not sure however if that's for using Apache licenced part in GPLv2 code or
> the other way around like in UTM in which case I think the whole work will
> effectively become GPLv3 as most parts of QEMU is probably GPLv2+ already or
> BSD like free that should be possible to combine with only files explicitely
> GPLv2 in QEMU remaining at that license and UTM parts are Apache 2.0 when
> separated from QEMU. I have no idea about legal stuff whatsoever but
> combining two free software components should be legal some way (otherwise
> it's not possible to combine GPLv2 with GPLv3 either).

You need to distinguish between GPLv2-only and GPLv2-or-later.

GPLv2-or-later is fine as that upgrades to GPLv3 when used in a
combined work with Apache License or GPLv3 software.

GPLv2-only will, by design, *not* upgrade to newer GPL versions
when combined - it is simply license incompatible.

QEMU unfortunately has a bunch a GPLv2-only code present that we
cannot eliminate.

Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 06/10] coroutine: add libucontext as external library
  2020-10-13 13:31   ` Stefan Hajnoczi
@ 2020-10-13 14:49     ` BALATON Zoltan via
  2020-10-13 15:25       ` Joelle van Dyne
  2020-10-13 16:18       ` Daniel P. Berrangé
  0 siblings, 2 replies; 47+ messages in thread
From: BALATON Zoltan via @ 2020-10-13 14:49 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: Kevin Wolf, Joelle van Dyne, qemu-devel

On Tue, 13 Oct 2020, Stefan Hajnoczi wrote:
> On Mon, Oct 12, 2020 at 04:29:35PM -0700, Joelle van Dyne wrote:
>> From: osy <osy86@users.noreply.github.com>
>>
>> iOS does not support ucontext natively for aarch64 and the sigaltstack is
>> also unsupported (even worse, it fails silently, see:
>> https://openradar.appspot.com/13002712 )
>>
>> As a workaround we include a library implementation of ucontext and add it
>> as a build option.
>>
>> Signed-off-by: Joelle van Dyne <j@getutm.app>
>
> Hi,
> Thanks for sending posting this!
>
> Please indicate what license libucontext is under, that it is compatible
> with QEMU's overall GPL v2 license, and update QEMU license

https://github.com/utmapp/libucontext/blob/master/LICENSE

Maybe the submodule repo should be mirrored in qemu.git eventually.

> documentation (LICENSE, etc), if necessary.
>
> Please update .gitlab-ci.yml with build tests. Is there a way to test
> building QEMU for iOS? If not, then it's difficult for the upstream QEMU
> project to carry iOS-specific features since we cannot test them.

Build testing should be possible on OS X host that I think we already have 
provided it has the right XCode version installed. (Running it is 
difficult due to app deployment requirements of iOS devices.) But I don't 
know much about these, just trying to point at some possible directions to 
solve this.

Regards,
BALATON Zoltan


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 07/10] tcg: implement bulletproof JIT
  2020-10-12 23:29   ` Joelle van Dyne
@ 2020-10-13 14:58     ` BALATON Zoltan
  -1 siblings, 0 replies; 47+ messages in thread
From: BALATON Zoltan via @ 2020-10-13 14:58 UTC (permalink / raw)
  To: Joelle van Dyne
  Cc: Aleksandar Rikalo, open list:RISC-V TCG target,
	Aleksandar Markovic, Stefan Weil, qemu-devel,
	open list:S390 TCG target, open list:AArch64 TCG target,
	Palmer Dabbelt, Paolo Bonzini, Huacai Chen, Alistair Francis,
	Aurelien Jarno, Richard Henderson

On Mon, 12 Oct 2020, Joelle van Dyne wrote:
> From: osy <osy86@users.noreply.github.com>
>
> On iOS, we cannot allocate RWX pages without special entitlements. As a
> workaround, we can a RX region and then mirror map it to a separate RX

Missing a verb here: "we can a RX region"

> region. Then we can write to one region and execute from the other one.
>
> To better keep track of pointers to RW/RX memory, we mark any tcg_insn_unit
> pointers as `const` if they will never be written to. We also define a new
> macro `TCG_CODE_PTR_RW` that returns a pointer to RW memory. Only the
> difference between the two regions is stored in the TCG context.

Maybe it's easier to review if constification is split off as separate 
patch before other changes.

> To ensure cache coherency, we flush the data cache in the RW mapping and
> then invalidate the instruction cache in the RX mapping (where applicable).
> Because data cache flush is OS defined on some architectures, we do not
> provide implementations for non iOS platforms (ARM/x86).
>
> Signed-off-by: Joelle van Dyne <j@getutm.app>
> ---
> accel/tcg/cpu-exec.c         |  7 +++-
> accel/tcg/translate-all.c    | 78 ++++++++++++++++++++++++++++++++++--
> configure                    |  1 +
> docs/devel/ios.rst           | 40 ++++++++++++++++++
> include/exec/exec-all.h      |  8 ++++
> include/tcg/tcg.h            | 18 +++++++--
> tcg/aarch64/tcg-target.c.inc | 48 +++++++++++++---------
> tcg/aarch64/tcg-target.h     | 13 +++++-
> tcg/arm/tcg-target.c.inc     | 33 ++++++++-------
> tcg/arm/tcg-target.h         |  9 ++++-
> tcg/i386/tcg-target.c.inc    | 28 ++++++-------
> tcg/i386/tcg-target.h        | 24 ++++++++++-
> tcg/mips/tcg-target.c.inc    | 64 +++++++++++++++++------------
> tcg/mips/tcg-target.h        |  8 +++-
> tcg/ppc/tcg-target.c.inc     | 55 ++++++++++++++++---------
> tcg/ppc/tcg-target.h         |  8 +++-
> tcg/riscv/tcg-target.c.inc   | 51 +++++++++++++----------
> tcg/riscv/tcg-target.h       |  9 ++++-
> tcg/s390/tcg-target.c.inc    | 25 ++++++------
> tcg/s390/tcg-target.h        | 13 +++++-
> tcg/sparc/tcg-target.c.inc   | 33 +++++++++------
> tcg/sparc/tcg-target.h       |  8 +++-
> tcg/tcg-ldst.c.inc           |  2 +-
> tcg/tcg-pool.c.inc           |  9 +++--
> tcg/tcg.c                    | 60 +++++++++++++++++----------
> tcg/tci/tcg-target.c.inc     |  8 ++--
> tcg/tci/tcg-target.h         |  9 ++++-
> 27 files changed, 481 insertions(+), 188 deletions(-)
> create mode 100644 docs/devel/ios.rst
>
> diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
> index 58aea605d8..821aefdea2 100644
> --- a/accel/tcg/cpu-exec.c
> +++ b/accel/tcg/cpu-exec.c
> @@ -354,7 +354,12 @@ void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr)
>     if (TCG_TARGET_HAS_direct_jump) {
>         uintptr_t offset = tb->jmp_target_arg[n];
>         uintptr_t tc_ptr = (uintptr_t)tb->tc.ptr;
> -        tb_target_set_jmp_target(tc_ptr, tc_ptr + offset, addr);
> +#if defined(CONFIG_IOS_JIT)
> +        uintptr_t wr_addr = tc_ptr + offset + tb->code_rw_mirror_diff;
> +#else
> +        uintptr_t wr_addr = tc_ptr + offset;
> +#endif
> +        tb_target_set_jmp_target(tc_ptr, tc_ptr + offset, addr, wr_addr);
>     } else {
>         tb->jmp_target_arg[n] = addr;
>     }
> diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
> index d76097296d..76d8dc3d7b 100644
> --- a/accel/tcg/translate-all.c
> +++ b/accel/tcg/translate-all.c
> @@ -60,6 +60,22 @@
> #include "sysemu/cpu-timers.h"
> #include "sysemu/tcg.h"
>
> +#if defined(CONFIG_IOS_JIT)
> +#include <mach/mach.h>
> +extern kern_return_t mach_vm_remap(vm_map_t target_task,
> +                                   mach_vm_address_t *target_address,
> +                                   mach_vm_size_t size,
> +                                   mach_vm_offset_t mask,
> +                                   int flags,
> +                                   vm_map_t src_task,
> +                                   mach_vm_address_t src_address,
> +                                   boolean_t copy,
> +                                   vm_prot_t *cur_protection,
> +                                   vm_prot_t *max_protection,
> +                                   vm_inherit_t inheritance
> +                                  );
> +#endif
> +
> /* #define DEBUG_TB_INVALIDATE */
> /* #define DEBUG_TB_FLUSH */
> /* make various TB consistency checks */
> @@ -302,10 +318,13 @@ static target_long decode_sleb128(uint8_t **pp)
>
> static int encode_search(TranslationBlock *tb, uint8_t *block)
> {
> -    uint8_t *highwater = tcg_ctx->code_gen_highwater;
> -    uint8_t *p = block;
> +    uint8_t *highwater;
> +    uint8_t *p;
>     int i, j, n;
>
> +    highwater = (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx,
> +                                           tcg_ctx->code_gen_highwater);
> +    p = (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx, block);

Why do you need explicit casts here? Can this be avoided by using 
appropriate type or within the macro (I haven't checked this at all just 
dislike casts as they can hide problems otherwise caught by the compiler).

Regards,
BALATON Zoltan

>     for (i = 0, n = tb->icount; i < n; ++i) {
>         target_ulong prev;
>
> @@ -329,7 +348,7 @@ static int encode_search(TranslationBlock *tb, uint8_t *block)
>         }
>     }
>
> -    return p - block;
> +    return p - (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx, block);
> }
>
> /* The cpu state corresponding to 'searched_pc' is restored.
> @@ -1067,7 +1086,11 @@ static inline void *alloc_code_gen_buffer(void)
> #else
> static inline void *alloc_code_gen_buffer(void)
> {
> +#if defined(CONFIG_IOS_JIT)
> +    int prot = PROT_READ | PROT_EXEC;
> +#else
>     int prot = PROT_WRITE | PROT_READ | PROT_EXEC;
> +#endif
>     int flags = MAP_PRIVATE | MAP_ANONYMOUS;
>     size_t size = tcg_ctx->code_gen_buffer_size;
>     void *buf;
> @@ -1118,6 +1141,39 @@ static inline void *alloc_code_gen_buffer(void)
> }
> #endif /* USE_STATIC_CODE_GEN_BUFFER, WIN32, POSIX */
>
> +#if defined(CONFIG_IOS_JIT)
> +static inline void *alloc_jit_rw_mirror(void *base, size_t size)
> +{
> +    kern_return_t ret;
> +    mach_vm_address_t mirror;
> +    vm_prot_t cur_prot, max_prot;
> +
> +    mirror = 0;
> +    ret = mach_vm_remap(mach_task_self(),
> +                        &mirror,
> +                        size,
> +                        0,
> +                        VM_FLAGS_ANYWHERE | VM_FLAGS_RANDOM_ADDR,
> +                        mach_task_self(),
> +                        (mach_vm_address_t)base,
> +                        false,
> +                        &cur_prot,
> +                        &max_prot,
> +                        VM_INHERIT_NONE
> +                       );
> +    if (ret != KERN_SUCCESS) {
> +        return NULL;
> +    }
> +
> +    if (mprotect((void *)mirror, size, PROT_READ | PROT_WRITE) != 0) {
> +        munmap((void *)mirror, size);
> +        return NULL;
> +    }
> +
> +    return (void *)mirror;
> +}
> +#endif /* CONFIG_IOS_JIT */
> +
> static inline void code_gen_alloc(size_t tb_size)
> {
>     tcg_ctx->code_gen_buffer_size = size_code_gen_buffer(tb_size);
> @@ -1126,6 +1182,19 @@ static inline void code_gen_alloc(size_t tb_size)
>         fprintf(stderr, "Could not allocate dynamic translator buffer\n");
>         exit(1);
>     }
> +#if defined(CONFIG_IOS_JIT)
> +    void *mirror;
> +
> +    /* For iOS JIT we need a mirror mapping for code execution */
> +    mirror = alloc_jit_rw_mirror(tcg_ctx->code_gen_buffer,
> +                                 tcg_ctx->code_gen_buffer_size
> +                                );
> +    if (mirror == NULL) {
> +        fprintf(stderr, "Could not remap code buffer mirror\n");
> +        exit(1);
> +    }
> +    tcg_ctx->code_rw_mirror_diff = mirror - tcg_ctx->code_gen_buffer;
> +#endif /* CONFIG_IOS_JIT */
> }
>
> static bool tb_cmp(const void *ap, const void *bp)
> @@ -1721,6 +1790,9 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
>         cpu_loop_exit(cpu);
>     }
>
> +#if defined(CONFIG_IOS_JIT)
> +    tb->code_rw_mirror_diff = tcg_ctx->code_rw_mirror_diff;
> +#endif
>     gen_code_buf = tcg_ctx->code_gen_ptr;
>     tb->tc.ptr = gen_code_buf;
>     tb->pc = pc;
> diff --git a/configure b/configure
> index 16c66b437c..c5a6584683 100755
> --- a/configure
> +++ b/configure
> @@ -6220,6 +6220,7 @@ fi
>
> if test "$ios" = "yes" ; then
>   echo "CONFIG_IOS=y" >> $config_host_mak
> +  echo "CONFIG_IOS_JIT=y" >> $config_host_mak
> fi
>
> if test "$solaris" = "yes" ; then
> diff --git a/docs/devel/ios.rst b/docs/devel/ios.rst
> new file mode 100644
> index 0000000000..dba9fdd868
> --- /dev/null
> +++ b/docs/devel/ios.rst
> @@ -0,0 +1,40 @@
> +===========
> +iOS Support
> +===========
> +
> +To run qemu on the iOS platform, some modifications were required. Most of the
> +modifications are conditioned on the ``CONFIG_IOS`` and ``CONFIG_IOS_JIT``
> +configuration variables.
> +
> +Build support
> +-------------
> +
> +For the code to compile, certain changes in the block driver and the slirp
> +driver had to be made. There is no ``system()`` call, so code requiring it had
> +to be disabled.
> +
> +``ucontext`` support is broken on iOS. The implementation from ``libucontext``
> +is used instead.
> +
> +Because ``fork()`` is not allowed on iOS apps, the option to build qemu and the
> +utilities as shared libraries is added. Note that because qemu does not perform
> +resource cleanup in most cases (open files, allocated memory, etc), it is
> +advisable that the user implements a proxy layer for syscalls so resources can
> +be kept track by the app that uses qemu as a shared library.
> +
> +JIT support
> +-----------
> +
> +On iOS, allocating RWX pages require special entitlements not usually granted to
> +apps. However, it is possible to use `bulletproof JIT`_ with a development
> +certificate. This means that we need to allocate one chunk of memory with RX
> +permissions and then mirror map the same memory with RW permissions. We generate
> +code to the mirror mapping and execute the original mapping.
> +
> +With ``CONFIG_IOS_JIT`` defined, we store inside the TCG context the difference
> +between the two mappings. Then, we make sure that any writes to JIT memory is
> +done to the pointer + the difference (in order to get a pointer to the mirror
> +mapped space). Additionally, we make sure to flush the data cache before we
> +invalidate the instruction cache so the changes are seen in both mappings.
> +
> +.. _bulletproof JIT: https://www.blackhat.com/docs/us-16/materials/us-16-Krstic.pdf
> diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
> index 66f9b4cca6..2db155a772 100644
> --- a/include/exec/exec-all.h
> +++ b/include/exec/exec-all.h
> @@ -483,6 +483,14 @@ struct TranslationBlock {
>     uintptr_t jmp_list_head;
>     uintptr_t jmp_list_next[2];
>     uintptr_t jmp_dest[2];
> +
> +#if defined(CONFIG_IOS_JIT)
> +    /*
> +     * Store difference to writable mirror
> +     * We need this when patching the jump instructions
> +     */
> +    ptrdiff_t code_rw_mirror_diff;
> +#endif
> };
>
> extern bool parallel_cpus;
> diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
> index 8804a8c4a2..40d1a7a85e 100644
> --- a/include/tcg/tcg.h
> +++ b/include/tcg/tcg.h
> @@ -261,7 +261,7 @@ struct TCGLabel {
>     unsigned refs : 16;
>     union {
>         uintptr_t value;
> -        tcg_insn_unit *value_ptr;
> +        const tcg_insn_unit *value_ptr;
>     } u;
>     QSIMPLEQ_HEAD(, TCGRelocation) relocs;
>     QSIMPLEQ_ENTRY(TCGLabel) next;
> @@ -593,7 +593,7 @@ struct TCGContext {
>     int nb_ops;
>
>     /* goto_tb support */
> -    tcg_insn_unit *code_buf;
> +    const tcg_insn_unit *code_buf;
>     uint16_t *tb_jmp_reset_offset; /* tb->jmp_reset_offset */
>     uintptr_t *tb_jmp_insn_offset; /* tb->jmp_target_arg if direct_jump */
>     uintptr_t *tb_jmp_target_addr; /* tb->jmp_target_arg if !direct_jump */
> @@ -627,6 +627,9 @@ struct TCGContext {
>     size_t code_gen_buffer_size;
>     void *code_gen_ptr;
>     void *data_gen_ptr;
> +#if defined(CONFIG_IOS_JIT)
> +    ptrdiff_t code_rw_mirror_diff;
> +#endif
>
>     /* Threshold to flush the translated code buffer.  */
>     void *code_gen_highwater;
> @@ -677,6 +680,13 @@ struct TCGContext {
>     target_ulong gen_insn_data[TCG_MAX_INSNS][TARGET_INSN_START_WORDS];
> };
>
> +#if defined(CONFIG_IOS_JIT)
> +# define TCG_CODE_PTR_RW(s, code_ptr) \
> +    (tcg_insn_unit *)((uintptr_t)(code_ptr) + (s)->code_rw_mirror_diff)
> +#else
> +# define TCG_CODE_PTR_RW(s, code_ptr) (code_ptr)
> +#endif
> +
> extern TCGContext tcg_init_ctx;
> extern __thread TCGContext *tcg_ctx;
> extern TCGv_env cpu_env;
> @@ -1099,7 +1109,7 @@ static inline TCGLabel *arg_label(TCGArg i)
>  * correct result.
>  */
>
> -static inline ptrdiff_t tcg_ptr_byte_diff(void *a, void *b)
> +static inline ptrdiff_t tcg_ptr_byte_diff(const void *a, const void *b)
> {
>     return a - b;
> }
> @@ -1113,7 +1123,7 @@ static inline ptrdiff_t tcg_ptr_byte_diff(void *a, void *b)
>  * to the destination address.
>  */
>
> -static inline ptrdiff_t tcg_pcrel_diff(TCGContext *s, void *target)
> +static inline ptrdiff_t tcg_pcrel_diff(TCGContext *s, const void *target)
> {
>     return tcg_ptr_byte_diff(target, s->code_ptr);
> }
> diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc
> index 26f71cb599..9cfa2703b3 100644
> --- a/tcg/aarch64/tcg-target.c.inc
> +++ b/tcg/aarch64/tcg-target.c.inc
> @@ -78,38 +78,44 @@ static const int tcg_target_call_oarg_regs[1] = {
> #define TCG_REG_GUEST_BASE TCG_REG_X28
> #endif
>
> -static inline bool reloc_pc26(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
> +static inline bool reloc_pc26(TCGContext *s,
> +                              tcg_insn_unit *code_ptr,
> +                              const tcg_insn_unit *target)
> {
>     ptrdiff_t offset = target - code_ptr;
>     if (offset == sextract64(offset, 0, 26)) {
>         /* read instruction, mask away previous PC_REL26 parameter contents,
>            set the proper offset, then write back the instruction. */
> -        *code_ptr = deposit32(*code_ptr, 0, 26, offset);
> +        *TCG_CODE_PTR_RW(s, code_ptr) =
> +            deposit32(*TCG_CODE_PTR_RW(s, code_ptr), 0, 26, offset);
>         return true;
>     }
>     return false;
> }
>
> -static inline bool reloc_pc19(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
> +static inline bool reloc_pc19(TCGContext *s,
> +                              tcg_insn_unit *code_ptr,
> +                              const tcg_insn_unit *target)
> {
>     ptrdiff_t offset = target - code_ptr;
>     if (offset == sextract64(offset, 0, 19)) {
> -        *code_ptr = deposit32(*code_ptr, 5, 19, offset);
> +        *TCG_CODE_PTR_RW(s, code_ptr) =
> +            deposit32(*TCG_CODE_PTR_RW(s, code_ptr), 5, 19, offset);
>         return true;
>     }
>     return false;
> }
>
> -static inline bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> +static inline bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
>                                intptr_t value, intptr_t addend)
> {
>     tcg_debug_assert(addend == 0);
>     switch (type) {
>     case R_AARCH64_JUMP26:
>     case R_AARCH64_CALL26:
> -        return reloc_pc26(code_ptr, (tcg_insn_unit *)value);
> +        return reloc_pc26(s, code_ptr, (tcg_insn_unit *)value);
>     case R_AARCH64_CONDBR19:
> -        return reloc_pc19(code_ptr, (tcg_insn_unit *)value);
> +        return reloc_pc19(s, code_ptr, (tcg_insn_unit *)value);
>     default:
>         g_assert_not_reached();
>     }
> @@ -1306,14 +1312,14 @@ static void tcg_out_cmp(TCGContext *s, TCGType ext, TCGReg a,
>     }
> }
>
> -static inline void tcg_out_goto(TCGContext *s, tcg_insn_unit *target)
> +static inline void tcg_out_goto(TCGContext *s, const tcg_insn_unit *target)
> {
>     ptrdiff_t offset = target - s->code_ptr;
>     tcg_debug_assert(offset == sextract64(offset, 0, 26));
>     tcg_out_insn(s, 3206, B, offset);
> }
>
> -static inline void tcg_out_goto_long(TCGContext *s, tcg_insn_unit *target)
> +static inline void tcg_out_goto_long(TCGContext *s, const tcg_insn_unit *target)
> {
>     ptrdiff_t offset = target - s->code_ptr;
>     if (offset == sextract64(offset, 0, 26)) {
> @@ -1329,7 +1335,7 @@ static inline void tcg_out_callr(TCGContext *s, TCGReg reg)
>     tcg_out_insn(s, 3207, BLR, reg);
> }
>
> -static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *target)
> +static inline void tcg_out_call(TCGContext *s, const tcg_insn_unit *target)
> {
>     ptrdiff_t offset = target - s->code_ptr;
>     if (offset == sextract64(offset, 0, 26)) {
> @@ -1341,7 +1347,7 @@ static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *target)
> }
>
> void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
> -                              uintptr_t addr)
> +                              uintptr_t addr, uintptr_t wr_addr)
> {
>     tcg_insn_unit i1, i2;
>     TCGType rt = TCG_TYPE_I64;
> @@ -1362,7 +1368,10 @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
>         i2 = I3401_ADDI | rt << 31 | (addr & 0xfff) << 10 | rd << 5 | rd;
>     }
>     pair = (uint64_t)i2 << 32 | i1;
> -    qatomic_set((uint64_t *)jmp_addr, pair);
> +    qatomic_set((uint64_t *)wr_addr, pair);
> +#if defined(CONFIG_IOS_JIT)
> +    flush_dcache_range(wr_addr, wr_addr + 8);
> +#endif
>     flush_icache_range(jmp_addr, jmp_addr + 8);
> }
>
> @@ -1568,7 +1577,7 @@ static void * const qemu_st_helpers[16] = {
>     [MO_BEQ]  = helper_be_stq_mmu,
> };
>
> -static inline void tcg_out_adr(TCGContext *s, TCGReg rd, void *target)
> +static inline void tcg_out_adr(TCGContext *s, TCGReg rd, const void *target)
> {
>     ptrdiff_t offset = tcg_pcrel_diff(s, target);
>     tcg_debug_assert(offset == sextract64(offset, 0, 21));
> @@ -1581,7 +1590,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
>     MemOp opc = get_memop(oi);
>     MemOp size = opc & MO_SIZE;
>
> -    if (!reloc_pc19(lb->label_ptr[0], s->code_ptr)) {
> +    if (!reloc_pc19(s, lb->label_ptr[0], s->code_ptr)) {
>         return false;
>     }
>
> @@ -1606,7 +1615,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
>     MemOp opc = get_memop(oi);
>     MemOp size = opc & MO_SIZE;
>
> -    if (!reloc_pc19(lb->label_ptr[0], s->code_ptr)) {
> +    if (!reloc_pc19(s, lb->label_ptr[0], s->code_ptr)) {
>         return false;
>     }
>
> @@ -1622,7 +1631,8 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
>
> static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
>                                 TCGType ext, TCGReg data_reg, TCGReg addr_reg,
> -                                tcg_insn_unit *raddr, tcg_insn_unit *label_ptr)
> +                                const tcg_insn_unit *raddr,
> +                                tcg_insn_unit *label_ptr)
> {
>     TCGLabelQemuLdst *label = new_ldst_label(s);
>
> @@ -1849,7 +1859,7 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg,
> #endif /* CONFIG_SOFTMMU */
> }
>
> -static tcg_insn_unit *tb_ret_addr;
> +static const tcg_insn_unit *tb_ret_addr;
>
> static void tcg_out_op(TCGContext *s, TCGOpcode opc,
>                        const TCGArg args[TCG_MAX_OP_ARGS],
> @@ -2916,11 +2926,11 @@ static void tcg_target_qemu_prologue(TCGContext *s)
>     tcg_out_insn(s, 3207, RET, TCG_REG_LR);
> }
>
> -static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
> +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
> {
>     int i;
>     for (i = 0; i < count; ++i) {
> -        p[i] = NOP;
> +        (TCG_CODE_PTR_RW(s, p))[i] = NOP;
>     }
> }
>
> diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h
> index a2b22b4305..78c97460a1 100644
> --- a/tcg/aarch64/tcg-target.h
> +++ b/tcg/aarch64/tcg-target.h
> @@ -150,6 +150,7 @@ typedef enum {
>
> #if defined(__APPLE__)
> void sys_icache_invalidate(void *start, size_t len);
> +void sys_dcache_flush(void *start, size_t len);
> #endif
>
> static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
> @@ -163,7 +164,17 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
> #endif
> }
>
> -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
> +void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
> +#if defined(CONFIG_IOS_JIT)
> +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> +{
> +#if defined(__APPLE__)
> +    sys_dcache_flush((char *)start, stop - start);
> +#else
> +#error "Missing function to flush data cache"
> +#endif
> +}
> +#endif
>
> #ifdef CONFIG_SOFTMMU
> #define TCG_TARGET_NEED_LDST_LABELS
> diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc
> index 62c37a954b..d27ad851b5 100644
> --- a/tcg/arm/tcg-target.c.inc
> +++ b/tcg/arm/tcg-target.c.inc
> @@ -187,17 +187,22 @@ static const uint8_t tcg_cond_to_arm_cond[] = {
>     [TCG_COND_GTU] = COND_HI,
> };
>
> -static inline bool reloc_pc24(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
> +static inline bool reloc_pc24(TCGContext *s,
> +                              tcg_insn_unit *code_ptr,
> +                              const tcg_insn_unit *target)
> {
>     ptrdiff_t offset = (tcg_ptr_byte_diff(target, code_ptr) - 8) >> 2;
>     if (offset == sextract32(offset, 0, 24)) {
> -        *code_ptr = (*code_ptr & ~0xffffff) | (offset & 0xffffff);
> +        *TCG_CODE_PTR_RW(s, code_ptr) =
> +            (*TCG_CODE_PTR_RW(s, code_ptr) & ~0xffffff) | (offset & 0xffffff);
>         return true;
>     }
>     return false;
> }
>
> -static inline bool reloc_pc13(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
> +static inline bool reloc_pc13(TCGContext *s,
> +                              tcg_insn_unit *code_ptr,
> +                              const tcg_insn_unit *target)
> {
>     ptrdiff_t offset = tcg_ptr_byte_diff(target, code_ptr) - 8;
>
> @@ -209,21 +214,21 @@ static inline bool reloc_pc13(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
>         }
>         insn = deposit32(insn, 23, 1, u);
>         insn = deposit32(insn, 0, 12, offset);
> -        *code_ptr = insn;
> +        *TCG_CODE_PTR_RW(s, code_ptr) = insn;
>         return true;
>     }
>     return false;
> }
>
> -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
>                         intptr_t value, intptr_t addend)
> {
>     tcg_debug_assert(addend == 0);
>
>     if (type == R_ARM_PC24) {
> -        return reloc_pc24(code_ptr, (tcg_insn_unit *)value);
> +        return reloc_pc24(s, code_ptr, (tcg_insn_unit *)value);
>     } else if (type == R_ARM_PC13) {
> -        return reloc_pc13(code_ptr, (tcg_insn_unit *)value);
> +        return reloc_pc13(s, code_ptr, (tcg_insn_unit *)value);
>     } else {
>         g_assert_not_reached();
>     }
> @@ -1019,7 +1024,7 @@ static inline void tcg_out_st8(TCGContext *s, int cond,
>  * with the code buffer limited to 16MB we wouldn't need the long case.
>  * But we also use it for the tail-call to the qemu_ld/st helpers, which does.
>  */
> -static void tcg_out_goto(TCGContext *s, int cond, tcg_insn_unit *addr)
> +static void tcg_out_goto(TCGContext *s, int cond, const tcg_insn_unit *addr)
> {
>     intptr_t addri = (intptr_t)addr;
>     ptrdiff_t disp = tcg_pcrel_diff(s, addr);
> @@ -1033,7 +1038,7 @@ static void tcg_out_goto(TCGContext *s, int cond, tcg_insn_unit *addr)
>
> /* The call case is mostly used for helpers - so it's not unreasonable
>  * for them to be beyond branch range */
> -static void tcg_out_call(TCGContext *s, tcg_insn_unit *addr)
> +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *addr)
> {
>     intptr_t addri = (intptr_t)addr;
>     ptrdiff_t disp = tcg_pcrel_diff(s, addr);
> @@ -1326,7 +1331,7 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addrlo, TCGReg addrhi,
>    helper code.  */
> static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
>                                 TCGReg datalo, TCGReg datahi, TCGReg addrlo,
> -                                TCGReg addrhi, tcg_insn_unit *raddr,
> +                                TCGReg addrhi, const tcg_insn_unit *raddr,
>                                 tcg_insn_unit *label_ptr)
> {
>     TCGLabelQemuLdst *label = new_ldst_label(s);
> @@ -1348,7 +1353,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
>     MemOp opc = get_memop(oi);
>     void *func;
>
> -    if (!reloc_pc24(lb->label_ptr[0], s->code_ptr)) {
> +    if (!reloc_pc24(s, lb->label_ptr[0], s->code_ptr)) {
>         return false;
>     }
>
> @@ -1411,7 +1416,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
>     TCGMemOpIdx oi = lb->oi;
>     MemOp opc = get_memop(oi);
>
> -    if (!reloc_pc24(lb->label_ptr[0], s->code_ptr)) {
> +    if (!reloc_pc24(s, lb->label_ptr[0], s->code_ptr)) {
>         return false;
>     }
>
> @@ -2255,11 +2260,11 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type,
>     tcg_out_movi32(s, COND_AL, ret, arg);
> }
>
> -static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
> +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
> {
>     int i;
>     for (i = 0; i < count; ++i) {
> -        p[i] = INSN_NOP;
> +        (TCG_CODE_PTR_RW(s, p))[i] = INSN_NOP;
>     }
> }
>
> diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
> index 17e771374d..d8d7e7e239 100644
> --- a/tcg/arm/tcg-target.h
> +++ b/tcg/arm/tcg-target.h
> @@ -139,8 +139,15 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
>     __builtin___clear_cache((char *) start, (char *) stop);
> }
>
> +#if defined(CONFIG_IOS_JIT)
> +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> +{
> +#error "Unimplemented dcache flush function"
> +}
> +#endif
> +
> /* not defined -- call should be eliminated at compile time */
> -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
> +void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
>
> #ifdef CONFIG_SOFTMMU
> #define TCG_TARGET_NEED_LDST_LABELS
> diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc
> index d8797ed398..e9c128d9e7 100644
> --- a/tcg/i386/tcg-target.c.inc
> +++ b/tcg/i386/tcg-target.c.inc
> @@ -165,9 +165,9 @@ static bool have_lzcnt;
> # define have_lzcnt 0
> #endif
>
> -static tcg_insn_unit *tb_ret_addr;
> +static const tcg_insn_unit *tb_ret_addr;
>
> -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
>                         intptr_t value, intptr_t addend)
> {
>     value += addend;
> @@ -179,14 +179,14 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
>         }
>         /* FALLTHRU */
>     case R_386_32:
> -        tcg_patch32(code_ptr, value);
> +        tcg_patch32(s, code_ptr, value);
>         break;
>     case R_386_PC8:
>         value -= (uintptr_t)code_ptr;
>         if (value != (int8_t)value) {
>             return false;
>         }
> -        tcg_patch8(code_ptr, value);
> +        tcg_patch8(s, code_ptr, value);
>         break;
>     default:
>         tcg_abort();
> @@ -1591,7 +1591,7 @@ static void tcg_out_clz(TCGContext *s, int rexw, TCGReg dest, TCGReg arg1,
>     }
> }
>
> -static void tcg_out_branch(TCGContext *s, int call, tcg_insn_unit *dest)
> +static void tcg_out_branch(TCGContext *s, int call, const tcg_insn_unit *dest)
> {
>     intptr_t disp = tcg_pcrel_diff(s, dest) - 5;
>
> @@ -1610,12 +1610,12 @@ static void tcg_out_branch(TCGContext *s, int call, tcg_insn_unit *dest)
>     }
> }
>
> -static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *dest)
> +static inline void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest)
> {
>     tcg_out_branch(s, 1, dest);
> }
>
> -static void tcg_out_jmp(TCGContext *s, tcg_insn_unit *dest)
> +static void tcg_out_jmp(TCGContext *s, const tcg_insn_unit *dest)
> {
>     tcg_out_branch(s, 0, dest);
> }
> @@ -1774,7 +1774,7 @@ static void add_qemu_ldst_label(TCGContext *s, bool is_ld, bool is_64,
>                                 TCGMemOpIdx oi,
>                                 TCGReg datalo, TCGReg datahi,
>                                 TCGReg addrlo, TCGReg addrhi,
> -                                tcg_insn_unit *raddr,
> +                                const tcg_insn_unit *raddr,
>                                 tcg_insn_unit **label_ptr)
> {
>     TCGLabelQemuLdst *label = new_ldst_label(s);
> @@ -1805,9 +1805,9 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
>     int rexw = (l->type == TCG_TYPE_I64 ? P_REXW : 0);
>
>     /* resolve label address */
> -    tcg_patch32(label_ptr[0], s->code_ptr - label_ptr[0] - 4);
> +    tcg_patch32(s, label_ptr[0], s->code_ptr - label_ptr[0] - 4);
>     if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
> -        tcg_patch32(label_ptr[1], s->code_ptr - label_ptr[1] - 4);
> +        tcg_patch32(s, label_ptr[1], s->code_ptr - label_ptr[1] - 4);
>     }
>
>     if (TCG_TARGET_REG_BITS == 32) {
> @@ -1890,9 +1890,9 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
>     TCGReg retaddr;
>
>     /* resolve label address */
> -    tcg_patch32(label_ptr[0], s->code_ptr - label_ptr[0] - 4);
> +    tcg_patch32(s, label_ptr[0], s->code_ptr - label_ptr[0] - 4);
>     if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
> -        tcg_patch32(label_ptr[1], s->code_ptr - label_ptr[1] - 4);
> +        tcg_patch32(s, label_ptr[1], s->code_ptr - label_ptr[1] - 4);
>     }
>
>     if (TCG_TARGET_REG_BITS == 32) {
> @@ -3842,9 +3842,9 @@ static void tcg_target_qemu_prologue(TCGContext *s)
>     tcg_out_opc(s, OPC_RET, 0, 0, 0);
> }
>
> -static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
> +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
> {
> -    memset(p, 0x90, count);
> +    memset(TCG_CODE_PTR_RW(s, p), 0x90, count);
> }
>
> static void tcg_target_init(TCGContext *s)
> diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
> index abd4ac7fc0..cdc440ce36 100644
> --- a/tcg/i386/tcg-target.h
> +++ b/tcg/i386/tcg-target.h
> @@ -206,16 +206,36 @@ extern bool have_avx2;
> #define TCG_TARGET_extract_i64_valid(ofs, len) \
>     (((ofs) == 8 && (len) == 8) || ((ofs) + (len)) == 32)
>
> +#ifdef __APPLE__
> +void sys_dcache_flush(void *start, size_t len);
> +#endif
> +
> static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
> {
> }
>
> +#if defined(CONFIG_IOS_JIT)
> +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> +{
> +#if defined(__APPLE__)
> +    sys_dcache_flush((char *)start, stop - start);
> +#else
> +#error "Missing function to flush data cache"
> +#endif
> +}
> +#endif
> +
> static inline void tb_target_set_jmp_target(uintptr_t tc_ptr,
> -                                            uintptr_t jmp_addr, uintptr_t addr)
> +                                            uintptr_t jmp_addr, uintptr_t addr,
> +                                            uintptr_t wr_addr)
> {
>     /* patch the branch destination */
> -    qatomic_set((int32_t *)jmp_addr, addr - (jmp_addr + 4));
> +    qatomic_set((int32_t *)wr_addr, addr - (jmp_addr + 4));
>     /* no need to flush icache explicitly */
> +#if defined(CONFIG_IOS_JIT)
> +    /* we do need to flush mirror dcache */
> +    flush_dcache_range(wr_addr, wr_addr + 4);
> +#endif
> }
>
> /* This defines the natural memory order supported by this
> diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc
> index 41be574e89..e798527437 100644
> --- a/tcg/mips/tcg-target.c.inc
> +++ b/tcg/mips/tcg-target.c.inc
> @@ -139,12 +139,13 @@ static const TCGReg tcg_target_call_oarg_regs[2] = {
>     TCG_REG_V1
> };
>
> -static tcg_insn_unit *tb_ret_addr;
> -static tcg_insn_unit *bswap32_addr;
> -static tcg_insn_unit *bswap32u_addr;
> -static tcg_insn_unit *bswap64_addr;
> +static const tcg_insn_unit *tb_ret_addr;
> +static const tcg_insn_unit *bswap32_addr;
> +static const tcg_insn_unit *bswap32u_addr;
> +static const tcg_insn_unit *bswap64_addr;
>
> -static inline uint32_t reloc_pc16_val(tcg_insn_unit *pc, tcg_insn_unit *target)
> +static inline uint32_t reloc_pc16_val(const tcg_insn_unit *pc,
> +                                      const tcg_insn_unit *target)
> {
>     /* Let the compiler perform the right-shift as part of the arithmetic.  */
>     ptrdiff_t disp = target - (pc + 1);
> @@ -152,28 +153,35 @@ static inline uint32_t reloc_pc16_val(tcg_insn_unit *pc, tcg_insn_unit *target)
>     return disp & 0xffff;
> }
>
> -static inline void reloc_pc16(tcg_insn_unit *pc, tcg_insn_unit *target)
> +static inline void reloc_pc16(TCGContext *s,
> +                              tcg_insn_unit *pc,
> +                              const tcg_insn_unit *target)
> {
> -    *pc = deposit32(*pc, 0, 16, reloc_pc16_val(pc, target));
> +    *TCG_CODE_PTR_RW(s, pc) =
> +        deposit32(*TCG_CODE_PTR_RW(s, pc), 0, 16, reloc_pc16_val(pc, target));
> }
>
> -static inline uint32_t reloc_26_val(tcg_insn_unit *pc, tcg_insn_unit *target)
> +static inline uint32_t reloc_26_val(const tcg_insn_unit *pc,
> +                                    const tcg_insn_unit *target)
> {
>     tcg_debug_assert((((uintptr_t)pc ^ (uintptr_t)target) & 0xf0000000) == 0);
>     return ((uintptr_t)target >> 2) & 0x3ffffff;
> }
>
> -static inline void reloc_26(tcg_insn_unit *pc, tcg_insn_unit *target)
> +static inline void reloc_26(TCGContext *s,
> +                            tcg_insn_unit *pc,
> +                            const tcg_insn_unit *target)
> {
> -    *pc = deposit32(*pc, 0, 26, reloc_26_val(pc, target));
> +    *TCG_CODE_PTR_RW(s, pc) =
> +        deposit32(*TCG_CODE_PTR_RW(s, pc), 0, 26, reloc_26_val(pc, target));
> }
>
> -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
>                         intptr_t value, intptr_t addend)
> {
>     tcg_debug_assert(type == R_MIPS_PC16);
>     tcg_debug_assert(addend == 0);
> -    reloc_pc16(code_ptr, (tcg_insn_unit *)value);
> +    reloc_pc16(s, code_ptr, (tcg_insn_unit *)value);
>     return true;
> }
>
> @@ -516,7 +524,7 @@ static void tcg_out_opc_sa64(TCGContext *s, MIPSInsn opc1, MIPSInsn opc2,
>  * Type jump.
>  * Returns true if the branch was in range and the insn was emitted.
>  */
> -static bool tcg_out_opc_jmp(TCGContext *s, MIPSInsn opc, void *target)
> +static bool tcg_out_opc_jmp(TCGContext *s, MIPSInsn opc, const void *target)
> {
>     uintptr_t dest = (uintptr_t)target;
>     uintptr_t from = (uintptr_t)s->code_ptr + 4;
> @@ -631,7 +639,7 @@ static inline void tcg_out_bswap16s(TCGContext *s, TCGReg ret, TCGReg arg)
>     }
> }
>
> -static void tcg_out_bswap_subr(TCGContext *s, tcg_insn_unit *sub)
> +static void tcg_out_bswap_subr(TCGContext *s, const tcg_insn_unit *sub)
> {
>     bool ok = tcg_out_opc_jmp(s, OPC_JAL, sub);
>     tcg_debug_assert(ok);
> @@ -925,7 +933,7 @@ static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1,
>
>     tcg_out_opc_br(s, b_opc, arg1, arg2);
>     if (l->has_value) {
> -        reloc_pc16(s->code_ptr - 1, l->u.value_ptr);
> +        reloc_pc16(s, s->code_ptr - 1, l->u.value_ptr);
>     } else {
>         tcg_out_reloc(s, s->code_ptr - 1, R_MIPS_PC16, l, 0);
>     }
> @@ -1079,7 +1087,7 @@ static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret,
>     }
> }
>
> -static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
> +static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail)
> {
>     /* Note that the ABI requires the called function's address to be
>        loaded into T9, even if a direct branch is in range.  */
> @@ -1097,7 +1105,7 @@ static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
>     }
> }
>
> -static void tcg_out_call(TCGContext *s, tcg_insn_unit *arg)
> +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg)
> {
>     tcg_out_call_int(s, arg, false);
>     tcg_out_nop(s);
> @@ -1289,7 +1297,8 @@ static void add_qemu_ldst_label(TCGContext *s, int is_ld, TCGMemOpIdx oi,
>                                 TCGType ext,
>                                 TCGReg datalo, TCGReg datahi,
>                                 TCGReg addrlo, TCGReg addrhi,
> -                                void *raddr, tcg_insn_unit *label_ptr[2])
> +                                const tcg_insn_unit *raddr,
> +                                tcg_insn_unit *label_ptr[2])
> {
>     TCGLabelQemuLdst *label = new_ldst_label(s);
>
> @@ -1315,9 +1324,9 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
>     int i;
>
>     /* resolve label address */
> -    reloc_pc16(l->label_ptr[0], s->code_ptr);
> +    reloc_pc16(s, l->label_ptr[0], s->code_ptr);
>     if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) {
> -        reloc_pc16(l->label_ptr[1], s->code_ptr);
> +        reloc_pc16(s, l->label_ptr[1], s->code_ptr);
>     }
>
>     i = 1;
> @@ -1345,7 +1354,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
>     }
>
>     tcg_out_opc_br(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO);
> -    reloc_pc16(s->code_ptr - 1, l->raddr);
> +    reloc_pc16(s, s->code_ptr - 1, l->raddr);
>
>     /* delay slot */
>     if (TCG_TARGET_REG_BITS == 64 && l->type == TCG_TYPE_I32) {
> @@ -1365,9 +1374,9 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
>     int i;
>
>     /* resolve label address */
> -    reloc_pc16(l->label_ptr[0], s->code_ptr);
> +    reloc_pc16(s, l->label_ptr[0], s->code_ptr);
>     if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) {
> -        reloc_pc16(l->label_ptr[1], s->code_ptr);
> +        reloc_pc16(s, l->label_ptr[1], s->code_ptr);
>     }
>
>     i = 1;
> @@ -2430,7 +2439,7 @@ static void tcg_target_detect_isa(void)
>     sigaction(SIGILL, &sa_old, NULL);
> }
>
> -static tcg_insn_unit *align_code_ptr(TCGContext *s)
> +static const tcg_insn_unit *align_code_ptr(TCGContext *s)
> {
>     uintptr_t p = (uintptr_t)s->code_ptr;
>     if (p & 15) {
> @@ -2657,9 +2666,12 @@ static void tcg_target_init(TCGContext *s)
> }
>
> void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
> -                              uintptr_t addr)
> +                              uintptr_t addr, uintptr_t wr_addr)
> {
> -    qatomic_set((uint32_t *)jmp_addr, deposit32(OPC_J, 0, 26, addr >> 2));
> +    qatomic_set((uint32_t *)wr_addr, deposit32(OPC_J, 0, 26, addr >> 2));
> +#if defined(CONFIG_IOS_JIT)
> +    flush_dcache_range(wr_addr, wr_addr + 4);
> +#endif
>     flush_icache_range(jmp_addr, jmp_addr + 4);
> }
>
> diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
> index c6b091d849..80dcba5358 100644
> --- a/tcg/mips/tcg-target.h
> +++ b/tcg/mips/tcg-target.h
> @@ -212,7 +212,13 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
>     cacheflush ((void *)start, stop-start, ICACHE);
> }
>
> -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
> +void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
> +#if defined(CONFIG_IOS_JIT)
> +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> +{
> +#error "Unimplemented dcache flush function"
> +}
> +#endif
>
> #ifdef CONFIG_SOFTMMU
> #define TCG_TARGET_NEED_LDST_LABELS
> diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc
> index 18ee989f95..f5a44e9852 100644
> --- a/tcg/ppc/tcg-target.c.inc
> +++ b/tcg/ppc/tcg-target.c.inc
> @@ -62,7 +62,7 @@
> #define TCG_CT_CONST_MONE 0x2000
> #define TCG_CT_CONST_WSZ  0x4000
>
> -static tcg_insn_unit *tb_ret_addr;
> +static const tcg_insn_unit *tb_ret_addr;
>
> TCGPowerISA have_isa;
> static bool have_isel;
> @@ -184,35 +184,43 @@ static inline bool in_range_b(tcg_target_long target)
>     return target == sextract64(target, 0, 26);
> }
>
> -static uint32_t reloc_pc24_val(tcg_insn_unit *pc, tcg_insn_unit *target)
> +static uint32_t reloc_pc24_val(const tcg_insn_unit *pc,
> +                               const tcg_insn_unit *target)
> {
>     ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
>     tcg_debug_assert(in_range_b(disp));
>     return disp & 0x3fffffc;
> }
>
> -static bool reloc_pc24(tcg_insn_unit *pc, tcg_insn_unit *target)
> +static bool reloc_pc24(TCGContext *s,
> +                       tcg_insn_unit *pc,
> +                       const tcg_insn_unit *target)
> {
>     ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
>     if (in_range_b(disp)) {
> -        *pc = (*pc & ~0x3fffffc) | (disp & 0x3fffffc);
> +        *TCG_CODE_PTR_RW(s, pc) =
> +            (*TCG_CODE_PTR_RW(s, pc) & ~0x3fffffc) | (disp & 0x3fffffc);
>         return true;
>     }
>     return false;
> }
>
> -static uint16_t reloc_pc14_val(tcg_insn_unit *pc, tcg_insn_unit *target)
> +static uint16_t reloc_pc14_val(const tcg_insn_unit *pc,
> +                               const tcg_insn_unit *target)
> {
>     ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
>     tcg_debug_assert(disp == (int16_t) disp);
>     return disp & 0xfffc;
> }
>
> -static bool reloc_pc14(tcg_insn_unit *pc, tcg_insn_unit *target)
> +static bool reloc_pc14(TCGContext *s,
> +                       tcg_insn_unit *pc,
> +                       const tcg_insn_unit *target)
> {
>     ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
>     if (disp == (int16_t) disp) {
> -        *pc = (*pc & ~0xfffc) | (disp & 0xfffc);
> +        *TCG_CODE_PTR_RW(s, pc) =
> +            (*TCG_CODE_PTR_RW(s, pc) & ~0xfffc) | (disp & 0xfffc);
>         return true;
>     }
>     return false;
> @@ -670,7 +678,7 @@ static const uint32_t tcg_to_isel[] = {
>     [TCG_COND_GTU] = ISEL | BC_(7, CR_GT),
> };
>
> -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
>                         intptr_t value, intptr_t addend)
> {
>     tcg_insn_unit *target;
> @@ -682,9 +690,9 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
>
>     switch (type) {
>     case R_PPC_REL14:
> -        return reloc_pc14(code_ptr, target);
> +        return reloc_pc14(s, code_ptr, target);
>     case R_PPC_REL24:
> -        return reloc_pc24(code_ptr, target);
> +        return reloc_pc24(s, code_ptr, target);
>     case R_PPC_ADDR16:
>         /*
>          * We are (slightly) abusing this relocation type.  In particular,
> @@ -1106,7 +1114,7 @@ static void tcg_out_xori32(TCGContext *s, TCGReg dst, TCGReg src, uint32_t c)
>     tcg_out_zori32(s, dst, src, c, XORI, XORIS);
> }
>
> -static void tcg_out_b(TCGContext *s, int mask, tcg_insn_unit *target)
> +static void tcg_out_b(TCGContext *s, int mask, const tcg_insn_unit *target)
> {
>     ptrdiff_t disp = tcg_pcrel_diff(s, target);
>     if (in_range_b(disp)) {
> @@ -1723,7 +1731,7 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0)
> }
>
> void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
> -                              uintptr_t addr)
> +                              uintptr_t addr, uintptr_t wr_addr)
> {
>     if (TCG_TARGET_REG_BITS == 64) {
>         tcg_insn_unit i1, i2;
> @@ -1752,17 +1760,23 @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
>
>         /* As per the enclosing if, this is ppc64.  Avoid the _Static_assert
>            within qatomic_set that would fail to build a ppc32 host.  */
> -        qatomic_set__nocheck((uint64_t *)jmp_addr, pair);
> +        qatomic_set__nocheck((uint64_t *)wr_addr, pair);
> +#if defined(CONFIG_IOS_JIT)
> +        flush_dcache_range(wr_addr, wr_addr + 8);
> +#endif
>         flush_icache_range(jmp_addr, jmp_addr + 8);
>     } else {
>         intptr_t diff = addr - jmp_addr;
>         tcg_debug_assert(in_range_b(diff));
> -        qatomic_set((uint32_t *)jmp_addr, B | (diff & 0x3fffffc));
> +        qatomic_set((uint32_t *)wr_addr, B | (diff & 0x3fffffc));
> +#if defined(CONFIG_IOS_JIT)
> +        flush_dcache_range(wr_addr, wr_addr + 8);
> +#endif
>         flush_icache_range(jmp_addr, jmp_addr + 4);
>     }
> }
>
> -static void tcg_out_call(TCGContext *s, tcg_insn_unit *target)
> +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target)
> {
> #ifdef _CALL_AIX
>     /* Look through the descriptor.  If the branch is in range, and we
> @@ -1987,7 +2001,8 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, MemOp opc,
> static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
>                                 TCGReg datalo_reg, TCGReg datahi_reg,
>                                 TCGReg addrlo_reg, TCGReg addrhi_reg,
> -                                tcg_insn_unit *raddr, tcg_insn_unit *lptr)
> +                                const tcg_insn_unit *raddr,
> +                                tcg_insn_unit *lptr)
> {
>     TCGLabelQemuLdst *label = new_ldst_label(s);
>
> @@ -2007,7 +2022,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
>     MemOp opc = get_memop(oi);
>     TCGReg hi, lo, arg = TCG_REG_R3;
>
> -    if (!reloc_pc14(lb->label_ptr[0], s->code_ptr)) {
> +    if (!reloc_pc14(s, lb->label_ptr[0], s->code_ptr)) {
>         return false;
>     }
>
> @@ -2055,7 +2070,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
>     MemOp s_bits = opc & MO_SIZE;
>     TCGReg hi, lo, arg = TCG_REG_R3;
>
> -    if (!reloc_pc14(lb->label_ptr[0], s->code_ptr)) {
> +    if (!reloc_pc14(s, lb->label_ptr[0], s->code_ptr)) {
>         return false;
>     }
>
> @@ -2252,11 +2267,11 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
> #endif
> }
>
> -static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
> +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
> {
>     int i;
>     for (i = 0; i < count; ++i) {
> -        p[i] = NOP;
> +        (TCG_CODE_PTR_RW(s, p))[i] = NOP;
>     }
> }
>
> diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
> index be10363956..23d7a337c9 100644
> --- a/tcg/ppc/tcg-target.h
> +++ b/tcg/ppc/tcg-target.h
> @@ -176,7 +176,13 @@ extern bool have_vsx;
> #define TCG_TARGET_HAS_cmpsel_vec       0
>
> void flush_icache_range(uintptr_t start, uintptr_t stop);
> -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
> +void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
> +#if defined(CONFIG_IOS_JIT)
> +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> +{
> +#error "Unimplemented dcache flush function"
> +}
> +#endif
>
> #define TCG_TARGET_DEFAULT_MO (0)
> #define TCG_TARGET_HAS_MEMORY_BSWAP     1
> diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc
> index d536f3ccc1..2d96c83c4b 100644
> --- a/tcg/riscv/tcg-target.c.inc
> +++ b/tcg/riscv/tcg-target.c.inc
> @@ -413,11 +413,11 @@ static void tcg_out_opc_jump(TCGContext *s, RISCVInsn opc,
>     tcg_out32(s, encode_uj(opc, rd, imm));
> }
>
> -static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
> +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
> {
>     int i;
>     for (i = 0; i < count; ++i) {
> -        p[i] = encode_i(OPC_ADDI, TCG_REG_ZERO, TCG_REG_ZERO, 0);
> +        (TCG_CODE_PTR_RW(s, p))[i] = encode_i(OPC_ADDI, TCG_REG_ZERO, TCG_REG_ZERO, 0);
>     }
> }
>
> @@ -425,46 +425,52 @@ static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
>  * Relocations
>  */
>
> -static bool reloc_sbimm12(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
> +static bool reloc_sbimm12(TCGContext *s,
> +                          tcg_insn_unit *code_ptr,
> +                          const tcg_insn_unit *target)
> {
>     intptr_t offset = (intptr_t)target - (intptr_t)code_ptr;
>
>     if (offset == sextreg(offset, 1, 12) << 1) {
> -        code_ptr[0] |= encode_sbimm12(offset);
> +        (TCG_CODE_PTR_RW(s, code_ptr))[0] |= encode_sbimm12(offset);
>         return true;
>     }
>
>     return false;
> }
>
> -static bool reloc_jimm20(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
> +static bool reloc_jimm20(TCGContext *s,
> +                         tcg_insn_unit *code_ptr,
> +                         const tcg_insn_unit *target)
> {
>     intptr_t offset = (intptr_t)target - (intptr_t)code_ptr;
>
>     if (offset == sextreg(offset, 1, 20) << 1) {
> -        code_ptr[0] |= encode_ujimm20(offset);
> +        (TCG_CODE_PTR_RW(s, code_ptr))[0] |= encode_ujimm20(offset);
>         return true;
>     }
>
>     return false;
> }
>
> -static bool reloc_call(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
> +static bool reloc_call(TCGContext *s,
> +                       tcg_insn_unit *code_ptr,
> +                       const tcg_insn_unit *target)
> {
>     intptr_t offset = (intptr_t)target - (intptr_t)code_ptr;
>     int32_t lo = sextreg(offset, 0, 12);
>     int32_t hi = offset - lo;
>
>     if (offset == hi + lo) {
> -        code_ptr[0] |= encode_uimm20(hi);
> -        code_ptr[1] |= encode_imm12(lo);
> +        (TCG_CODE_PTR_RW(s, code_ptr))[0] |= encode_uimm20(hi);
> +        (TCG_CODE_PTR_RW(s, code_ptr))[1] |= encode_imm12(lo);
>         return true;
>     }
>
>     return false;
> }
>
> -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
>                         intptr_t value, intptr_t addend)
> {
>     uint32_t insn = *code_ptr;
> @@ -478,7 +484,7 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
>         diff = value - (uintptr_t)code_ptr;
>         short_jmp = diff == sextreg(diff, 0, 12);
>         if (short_jmp) {
> -            return reloc_sbimm12(code_ptr, (tcg_insn_unit *)value);
> +            return reloc_sbimm12(s, code_ptr, (tcg_insn_unit *)value);
>         } else {
>             /* Invert the condition */
>             insn = insn ^ (1 << 12);
> @@ -499,9 +505,9 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
>         }
>         break;
>     case R_RISCV_JAL:
> -        return reloc_jimm20(code_ptr, (tcg_insn_unit *)value);
> +        return reloc_jimm20(s, code_ptr, (tcg_insn_unit *)value);
>     case R_RISCV_CALL:
> -        return reloc_call(code_ptr, (tcg_insn_unit *)value);
> +        return reloc_call(s, code_ptr, (tcg_insn_unit *)value);
>     default:
>         tcg_abort();
>     }
> @@ -557,7 +563,7 @@ static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd,
>     if (tmp == (int32_t)tmp) {
>         tcg_out_opc_upper(s, OPC_AUIPC, rd, 0);
>         tcg_out_opc_imm(s, OPC_ADDI, rd, rd, 0);
> -        ret = reloc_call(s->code_ptr - 2, (tcg_insn_unit *)val);
> +        ret = reloc_call(s, s->code_ptr - 2, (tcg_insn_unit *)val);
>         tcg_debug_assert(ret == true);
>         return;
>     }
> @@ -854,14 +860,14 @@ static void tcg_out_setcond2(TCGContext *s, TCGCond cond, TCGReg ret,
>     g_assert_not_reached();
> }
>
> -static inline void tcg_out_goto(TCGContext *s, tcg_insn_unit *target)
> +static inline void tcg_out_goto(TCGContext *s, const tcg_insn_unit *target)
> {
>     ptrdiff_t offset = tcg_pcrel_diff(s, target);
>     tcg_debug_assert(offset == sextreg(offset, 1, 20) << 1);
>     tcg_out_opc_jump(s, OPC_JAL, TCG_REG_ZERO, offset);
> }
>
> -static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
> +static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail)
> {
>     TCGReg link = tail ? TCG_REG_ZERO : TCG_REG_RA;
>     ptrdiff_t offset = tcg_pcrel_diff(s, arg);
> @@ -875,7 +881,7 @@ static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
>         /* long jump: -2147483646 to 2147483648 */
>         tcg_out_opc_upper(s, OPC_AUIPC, TCG_REG_TMP0, 0);
>         tcg_out_opc_imm(s, OPC_JALR, link, TCG_REG_TMP0, 0);
> -        ret = reloc_call(s->code_ptr - 2, arg);\
> +        ret = reloc_call(s, s->code_ptr - 2, arg);\
>         tcg_debug_assert(ret == true);
>     } else if (TCG_TARGET_REG_BITS == 64) {
>         /* far jump: 64-bit */
> @@ -888,7 +894,7 @@ static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
>     }
> }
>
> -static void tcg_out_call(TCGContext *s, tcg_insn_unit *arg)
> +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg)
> {
>     tcg_out_call_int(s, arg, false);
> }
> @@ -1022,7 +1028,8 @@ static void add_qemu_ldst_label(TCGContext *s, int is_ld, TCGMemOpIdx oi,
>                                 TCGType ext,
>                                 TCGReg datalo, TCGReg datahi,
>                                 TCGReg addrlo, TCGReg addrhi,
> -                                void *raddr, tcg_insn_unit **label_ptr)
> +                                const tcg_insn_unit *raddr,
> +                                tcg_insn_unit **label_ptr)
> {
>     TCGLabelQemuLdst *label = new_ldst_label(s);
>
> @@ -1052,7 +1059,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
>     }
>
>     /* resolve label address */
> -    if (!patch_reloc(l->label_ptr[0], R_RISCV_BRANCH,
> +    if (!patch_reloc(s, l->label_ptr[0], R_RISCV_BRANCH,
>                      (intptr_t) s->code_ptr, 0)) {
>         return false;
>     }
> @@ -1087,7 +1094,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
>     }
>
>     /* resolve label address */
> -    if (!patch_reloc(l->label_ptr[0], R_RISCV_BRANCH,
> +    if (!patch_reloc(s, l->label_ptr[0], R_RISCV_BRANCH,
>                      (intptr_t) s->code_ptr, 0)) {
>         return false;
>     }
> @@ -1274,7 +1281,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
> #endif
> }
>
> -static tcg_insn_unit *tb_ret_addr;
> +static const tcg_insn_unit *tb_ret_addr;
>
> static void tcg_out_op(TCGContext *s, TCGOpcode opc,
>                        const TCGArg *args, const int *const_args)
> diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h
> index 032439d806..d42b361991 100644
> --- a/tcg/riscv/tcg-target.h
> +++ b/tcg/riscv/tcg-target.h
> @@ -164,8 +164,15 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
>     __builtin___clear_cache((char *)start, (char *)stop);
> }
>
> +#if defined(CONFIG_IOS_JIT)
> +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> +{
> +#error "Unimplemented dcache flush function"
> +}
> +#endif
> +
> /* not defined -- call should be eliminated at compile time */
> -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
> +void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
>
> #define TCG_TARGET_DEFAULT_MO (0)
>
> diff --git a/tcg/s390/tcg-target.c.inc b/tcg/s390/tcg-target.c.inc
> index c5e096449b..49a96ca15f 100644
> --- a/tcg/s390/tcg-target.c.inc
> +++ b/tcg/s390/tcg-target.c.inc
> @@ -363,10 +363,10 @@ static void * const qemu_st_helpers[16] = {
> };
> #endif
>
> -static tcg_insn_unit *tb_ret_addr;
> +static const tcg_insn_unit *tb_ret_addr;
> uint64_t s390_facilities;
>
> -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
>                         intptr_t value, intptr_t addend)
> {
>     intptr_t pcrel2;
> @@ -378,13 +378,13 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
>     switch (type) {
>     case R_390_PC16DBL:
>         if (pcrel2 == (int16_t)pcrel2) {
> -            tcg_patch16(code_ptr, pcrel2);
> +            tcg_patch16(s, code_ptr, pcrel2);
>             return true;
>         }
>         break;
>     case R_390_PC32DBL:
>         if (pcrel2 == (int32_t)pcrel2) {
> -            tcg_patch32(code_ptr, pcrel2);
> +            tcg_patch32(s, code_ptr, pcrel2);
>             return true;
>         }
>         break;
> @@ -392,7 +392,7 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
>         if (value == sextract64(value, 0, 20)) {
>             old = *(uint32_t *)code_ptr & 0xf00000ff;
>             old |= ((value & 0xfff) << 16) | ((value & 0xff000) >> 4);
> -            tcg_patch32(code_ptr, old);
> +            tcg_patch32(s, code_ptr, old);
>             return true;
>         }
>         break;
> @@ -1302,7 +1302,7 @@ static void tgen_extract(TCGContext *s, TCGReg dest, TCGReg src,
>     tcg_out_risbg(s, dest, src, 64 - len, 63, 64 - ofs, 1);
> }
>
> -static void tgen_gotoi(TCGContext *s, int cc, tcg_insn_unit *dest)
> +static void tgen_gotoi(TCGContext *s, int cc, const tcg_insn_unit *dest)
> {
>     ptrdiff_t off = dest - s->code_ptr;
>     if (off == (int16_t)off) {
> @@ -1415,7 +1415,7 @@ static void tgen_brcond(TCGContext *s, TCGType type, TCGCond c,
>     tgen_branch(s, cc, l);
> }
>
> -static void tcg_out_call(TCGContext *s, tcg_insn_unit *dest)
> +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest)
> {
>     ptrdiff_t off = dest - s->code_ptr;
>     if (off == (int32_t)off) {
> @@ -1593,7 +1593,8 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, MemOp opc,
>
> static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
>                                 TCGReg data, TCGReg addr,
> -                                tcg_insn_unit *raddr, tcg_insn_unit *label_ptr)
> +                                const tcg_insn_unit *raddr,
> +                                tcg_insn_unit *label_ptr)
> {
>     TCGLabelQemuLdst *label = new_ldst_label(s);
>
> @@ -1612,7 +1613,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
>     TCGMemOpIdx oi = lb->oi;
>     MemOp opc = get_memop(oi);
>
> -    if (!patch_reloc(lb->label_ptr[0], R_390_PC16DBL,
> +    if (!patch_reloc(s, lb->label_ptr[0], R_390_PC16DBL,
>                      (intptr_t)s->code_ptr, 2)) {
>         return false;
>     }
> @@ -1637,7 +1638,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
>     TCGMemOpIdx oi = lb->oi;
>     MemOp opc = get_memop(oi);
>
> -    if (!patch_reloc(lb->label_ptr[0], R_390_PC16DBL,
> +    if (!patch_reloc(s, lb->label_ptr[0], R_390_PC16DBL,
>                      (intptr_t)s->code_ptr, 2)) {
>         return false;
>     }
> @@ -2575,9 +2576,9 @@ static void tcg_target_qemu_prologue(TCGContext *s)
>     tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_REG_R14);
> }
>
> -static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
> +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
> {
> -    memset(p, 0x07, count * sizeof(tcg_insn_unit));
> +    memset(TCG_CODE_PTR_RW(s, p), 0x07, count * sizeof(tcg_insn_unit));
> }
>
> typedef struct {
> diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h
> index 63c8797bd3..d67632512d 100644
> --- a/tcg/s390/tcg-target.h
> +++ b/tcg/s390/tcg-target.h
> @@ -149,13 +149,24 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
> {
> }
>
> +#if defined(CONFIG_IOS_JIT)
> +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> +{
> +#error "Unimplemented dcache flush function"
> +}
> +#endif
> +
> static inline void tb_target_set_jmp_target(uintptr_t tc_ptr,
> -                                            uintptr_t jmp_addr, uintptr_t addr)
> +                                            uintptr_t jmp_addr, uintptr_t addr,
> +                                            uintptr_t wr_addr)
> {
>     /* patch the branch destination */
>     intptr_t disp = addr - (jmp_addr - 2);
>     qatomic_set((int32_t *)jmp_addr, disp / 2);
>     /* no need to flush icache explicitly */
> +#if defined(CONFIG_IOS_JIT)
> +    flush_dcache_range(wr_addr, wr_addr + 4);
> +#endif
> }
>
> #ifdef CONFIG_SOFTMMU
> diff --git a/tcg/sparc/tcg-target.c.inc b/tcg/sparc/tcg-target.c.inc
> index 6775bd30fc..af97cbdeef 100644
> --- a/tcg/sparc/tcg-target.c.inc
> +++ b/tcg/sparc/tcg-target.c.inc
> @@ -291,14 +291,14 @@ static inline int check_fit_i32(int32_t val, unsigned int bits)
> # define check_fit_ptr  check_fit_i32
> #endif
>
> -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
>                         intptr_t value, intptr_t addend)
> {
>     uint32_t insn = *code_ptr;
>     intptr_t pcrel;
>
>     value += addend;
> -    pcrel = tcg_ptr_byte_diff((tcg_insn_unit *)value, code_ptr);
> +    pcrel = tcg_ptr_byte_diff((const tcg_insn_unit *)value, code_ptr);
>
>     switch (type) {
>     case R_SPARC_WDISP16:
> @@ -840,7 +840,7 @@ static void tcg_out_addsub2_i64(TCGContext *s, TCGReg rl, TCGReg rh,
>     tcg_out_mov(s, TCG_TYPE_I64, rl, tmp);
> }
>
> -static void tcg_out_call_nodelay(TCGContext *s, tcg_insn_unit *dest,
> +static void tcg_out_call_nodelay(TCGContext *s, const tcg_insn_unit *dest,
>                                  bool in_prologue)
> {
>     ptrdiff_t disp = tcg_pcrel_diff(s, dest);
> @@ -855,7 +855,7 @@ static void tcg_out_call_nodelay(TCGContext *s, tcg_insn_unit *dest,
>     }
> }
>
> -static void tcg_out_call(TCGContext *s, tcg_insn_unit *dest)
> +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest)
> {
>     tcg_out_call_nodelay(s, dest, false);
>     tcg_out_nop(s);
> @@ -868,8 +868,8 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0)
> }
>
> #ifdef CONFIG_SOFTMMU
> -static tcg_insn_unit *qemu_ld_trampoline[16];
> -static tcg_insn_unit *qemu_st_trampoline[16];
> +static const tcg_insn_unit *qemu_ld_trampoline[16];
> +static const tcg_insn_unit *qemu_st_trampoline[16];
>
> static void emit_extend(TCGContext *s, TCGReg r, int op)
> {
> @@ -1048,11 +1048,11 @@ static void tcg_target_qemu_prologue(TCGContext *s)
> #endif
> }
>
> -static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
> +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
> {
>     int i;
>     for (i = 0; i < count; ++i) {
> -        p[i] = NOP;
> +        (TCG_CODE_PTR_RW(s, p))[i] = NOP;
>     }
> }
>
> @@ -1163,7 +1163,7 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr,
> #ifdef CONFIG_SOFTMMU
>     unsigned memi = get_mmuidx(oi);
>     TCGReg addrz, param;
> -    tcg_insn_unit *func;
> +    const tcg_insn_unit *func;
>     tcg_insn_unit *label_ptr;
>
>     addrz = tcg_out_tlb_load(s, addr, memi, memop,
> @@ -1226,7 +1226,8 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr,
>         }
>     }
>
> -    *label_ptr |= INSN_OFF19(tcg_ptr_byte_diff(s->code_ptr, label_ptr));
> +    *TCG_CODE_PTR_RW(s, label_ptr) |=
> +        INSN_OFF19(tcg_ptr_byte_diff(s->code_ptr, label_ptr));
> #else
>     if (SPARC64 && TARGET_LONG_BITS == 32) {
>         tcg_out_arithi(s, TCG_REG_T1, addr, 0, SHIFT_SRL);
> @@ -1822,7 +1823,7 @@ void tcg_register_jit(void *buf, size_t buf_size)
> }
>
> void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
> -                              uintptr_t addr)
> +                              uintptr_t addr, uintptr_t wr_addr)
> {
>     intptr_t tb_disp = addr - tc_ptr;
>     intptr_t br_disp = addr - jmp_addr;
> @@ -1834,8 +1835,11 @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
>     tcg_debug_assert(br_disp == (int32_t)br_disp);
>
>     if (!USE_REG_TB) {
> -        qatomic_set((uint32_t *)jmp_addr,
> +        qatomic_set((uint32_t *)wr_addr,
> 		    deposit32(CALL, 0, 30, br_disp >> 2));
> +#if defined(CONFIG_IOS_JIT)
> +        flush_dcache_range(wr_addr, wr_addr + 4);
> +#endif
>         flush_icache_range(jmp_addr, jmp_addr + 4);
>         return;
>     }
> @@ -1859,6 +1863,9 @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
>               | INSN_IMM13((tb_disp & 0x3ff) | -0x400));
>     }
>
> -    qatomic_set((uint64_t *)jmp_addr, deposit64(i2, 32, 32, i1));
> +    qatomic_set((uint64_t *)wr_addr, deposit64(i2, 32, 32, i1));
> +#if defined(CONFIG_IOS_JIT)
> +    flush_dcache_range(wr_addr, wr_addr + 8);
> +#endif
>     flush_icache_range(jmp_addr, jmp_addr + 8);
> }
> diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h
> index 633841ebf2..d102e13692 100644
> --- a/tcg/sparc/tcg-target.h
> +++ b/tcg/sparc/tcg-target.h
> @@ -176,7 +176,13 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
>     }
> }
>
> -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
> +void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
> +#if defined(CONFIG_IOS_JIT)
> +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> +{
> +#error "Unimplemented dcache flush function"
> +}
> +#endif
>
> #define TCG_TARGET_NEED_POOL_LABELS
>
> diff --git a/tcg/tcg-ldst.c.inc b/tcg/tcg-ldst.c.inc
> index 05f9b3ccd6..eaba08700e 100644
> --- a/tcg/tcg-ldst.c.inc
> +++ b/tcg/tcg-ldst.c.inc
> @@ -28,7 +28,7 @@ typedef struct TCGLabelQemuLdst {
>     TCGReg addrhi_reg;      /* reg index for high word of guest virtual addr */
>     TCGReg datalo_reg;      /* reg index for low word to be loaded or stored */
>     TCGReg datahi_reg;      /* reg index for high word to be loaded or stored */
> -    tcg_insn_unit *raddr;   /* gen code addr of the next IR of qemu_ld/st IR */
> +    const tcg_insn_unit *raddr; /* gen code addr of the next IR of qemu_ld/st */
>     tcg_insn_unit *label_ptr[2]; /* label pointers to be updated */
>     QSIMPLEQ_ENTRY(TCGLabelQemuLdst) next;
> } TCGLabelQemuLdst;
> diff --git a/tcg/tcg-pool.c.inc b/tcg/tcg-pool.c.inc
> index 82cbcc89bd..97bb90b7cc 100644
> --- a/tcg/tcg-pool.c.inc
> +++ b/tcg/tcg-pool.c.inc
> @@ -119,7 +119,7 @@ static inline void new_pool_l8(TCGContext *s, int rtype, tcg_insn_unit *label,
> }
>
> /* To be provided by cpu/tcg-target.c.inc.  */
> -static void tcg_out_nop_fill(tcg_insn_unit *p, int count);
> +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count);
>
> static int tcg_out_pool_finalize(TCGContext *s)
> {
> @@ -135,7 +135,7 @@ static int tcg_out_pool_finalize(TCGContext *s)
>        again when allocating the next TranslationBlock structure.  */
>     a = (void *)ROUND_UP((uintptr_t)s->code_ptr,
>                          sizeof(tcg_target_ulong) * p->nlong);
> -    tcg_out_nop_fill(s->code_ptr, (tcg_insn_unit *)a - s->code_ptr);
> +    tcg_out_nop_fill(s, s->code_ptr, (tcg_insn_unit *)a - s->code_ptr);
>     s->data_gen_ptr = a;
>
>     for (; p != NULL; p = p->next) {
> @@ -144,11 +144,12 @@ static int tcg_out_pool_finalize(TCGContext *s)
>             if (unlikely(a > s->code_gen_highwater)) {
>                 return -1;
>             }
> -            memcpy(a, p->data, size);
> +            memcpy(TCG_CODE_PTR_RW(s, a), p->data, size);
>             a += size;
>             l = p;
>         }
> -        if (!patch_reloc(p->label, p->rtype, (intptr_t)a - size, p->addend)) {
> +        if (!patch_reloc(s, p->label, p->rtype,
> +                         (intptr_t)a - size, p->addend)) {
>             return -2;
>         }
>     }
> diff --git a/tcg/tcg.c b/tcg/tcg.c
> index a8c28440e2..ef203a34a6 100644
> --- a/tcg/tcg.c
> +++ b/tcg/tcg.c
> @@ -70,7 +70,7 @@
> static void tcg_target_init(TCGContext *s);
> static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode);
> static void tcg_target_qemu_prologue(TCGContext *s);
> -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
>                         intptr_t value, intptr_t addend);
>
> /* The CIE and FDE header definitions will be common to all hosts.  */
> @@ -148,7 +148,7 @@ static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
>                        intptr_t arg2);
> static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
>                         TCGReg base, intptr_t ofs);
> -static void tcg_out_call(TCGContext *s, tcg_insn_unit *target);
> +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target);
> static int tcg_target_const_match(tcg_target_long val, TCGType type,
>                                   const TCGArgConstraint *arg_ct);
> #ifdef TCG_TARGET_NEED_LDST_LABELS
> @@ -203,13 +203,15 @@ static TCGRegSet tcg_target_call_clobber_regs;
> #if TCG_TARGET_INSN_UNIT_SIZE == 1
> static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
> {
> -    *s->code_ptr++ = v;
> +    *TCG_CODE_PTR_RW(s, s->code_ptr) = v;
> +    s->code_ptr++;
> }
>
> -static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
> +static __attribute__((unused)) inline void tcg_patch8(TCGContext *s,
> +                                                      tcg_insn_unit *p,
>                                                       uint8_t v)
> {
> -    *p = v;
> +    *TCG_CODE_PTR_RW(s, p) = v;
> }
> #endif
>
> @@ -217,21 +219,23 @@ static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
> static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
> {
>     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
> -        *s->code_ptr++ = v;
> +        *TCG_CODE_PTR_RW(s, s->code_ptr) = v;
> +        s->code_ptr++;
>     } else {
>         tcg_insn_unit *p = s->code_ptr;
> -        memcpy(p, &v, sizeof(v));
> +        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
>         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
>     }
> }
>
> -static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
> +static __attribute__((unused)) inline void tcg_patch16(TCGContext *s,
> +                                                       tcg_insn_unit *p,
>                                                        uint16_t v)
> {
>     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
> -        *p = v;
> +        *TCG_CODE_PTR_RW(s, p) = v;
>     } else {
> -        memcpy(p, &v, sizeof(v));
> +        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
>     }
> }
> #endif
> @@ -240,21 +244,23 @@ static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
> static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
> {
>     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
> -        *s->code_ptr++ = v;
> +        *TCG_CODE_PTR_RW(s, s->code_ptr) = v;
> +        s->code_ptr++;
>     } else {
>         tcg_insn_unit *p = s->code_ptr;
> -        memcpy(p, &v, sizeof(v));
> +        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
>         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
>     }
> }
>
> -static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
> +static __attribute__((unused)) inline void tcg_patch32(TCGContext *s,
> +                                                       tcg_insn_unit *p,
>                                                        uint32_t v)
> {
>     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
>         *p = v;
>     } else {
> -        memcpy(p, &v, sizeof(v));
> +        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
>     }
> }
> #endif
> @@ -263,21 +269,23 @@ static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
> static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
> {
>     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
> -        *s->code_ptr++ = v;
> +        *TCG_CODE_PTR_RW(s, s->code_ptr) = v;
> +        s->code_ptr++;
>     } else {
>         tcg_insn_unit *p = s->code_ptr;
> -        memcpy(p, &v, sizeof(v));
> +        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
>         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
>     }
> }
>
> -static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
> +static __attribute__((unused)) inline void tcg_patch64(TCGContext *s,
> +                                                       tcg_insn_unit *p,
>                                                        uint64_t v)
> {
>     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
>         *p = v;
>     } else {
> -        memcpy(p, &v, sizeof(v));
> +        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
>     }
> }
> #endif
> @@ -295,7 +303,7 @@ static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
>     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
> }
>
> -static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr)
> +static void tcg_out_label(TCGContext *s, TCGLabel *l, const tcg_insn_unit *ptr)
> {
>     tcg_debug_assert(!l->has_value);
>     l->has_value = 1;
> @@ -325,7 +333,7 @@ static bool tcg_resolve_relocs(TCGContext *s)
>         uintptr_t value = l->u.value;
>
>         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
> -            if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
> +            if (!patch_reloc(s, r->ptr, r->type, value, r->addend)) {
>                 return false;
>             }
>         }
> @@ -1039,7 +1047,7 @@ TranslationBlock *tcg_tb_alloc(TCGContext *s)
>     }
>     qatomic_set(&s->code_gen_ptr, next);
>     s->data_gen_ptr = NULL;
> -    return tb;
> +    return (TranslationBlock *)TCG_CODE_PTR_RW(s, tb);
> }
>
> void tcg_prologue_init(TCGContext *s)
> @@ -1076,6 +1084,10 @@ void tcg_prologue_init(TCGContext *s)
> #endif
>
>     buf1 = s->code_ptr;
> +#if defined(CONFIG_IOS_JIT)
> +    flush_dcache_range((uintptr_t)TCG_CODE_PTR_RW(s, buf0),
> +                       (uintptr_t)TCG_CODE_PTR_RW(s, buf1));
> +#endif
>     flush_icache_range((uintptr_t)buf0, (uintptr_t)buf1);
>
>     /* Deduct the prologue from the buffer.  */
> @@ -4267,6 +4279,12 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
>         return -2;
>     }
>
> +#if defined(CONFIG_IOS_JIT)
> +    /* flush data cache on mirror */
> +    flush_dcache_range((uintptr_t)TCG_CODE_PTR_RW(s, s->code_buf),
> +                       (uintptr_t)TCG_CODE_PTR_RW(s, s->code_ptr));
> +#endif
> +
>     /* flush instruction cache */
>     flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr);
>
> diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc
> index 231b9b1775..133213be3a 100644
> --- a/tcg/tci/tcg-target.c.inc
> +++ b/tcg/tci/tcg-target.c.inc
> @@ -369,7 +369,7 @@ static const char *const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
> };
> #endif
>
> -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
>                         intptr_t value, intptr_t addend)
> {
>     /* tcg_out_reloc always uses the same type, addend. */
> @@ -377,9 +377,9 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
>     tcg_debug_assert(addend == 0);
>     tcg_debug_assert(value != 0);
>     if (TCG_TARGET_REG_BITS == 32) {
> -        tcg_patch32(code_ptr, value);
> +        tcg_patch32(s, code_ptr, value);
>     } else {
> -        tcg_patch64(code_ptr, value);
> +        tcg_patch64(s, code_ptr, value);
>     }
>     return true;
> }
> @@ -545,7 +545,7 @@ static void tcg_out_movi(TCGContext *s, TCGType type,
>     old_code_ptr[1] = s->code_ptr - old_code_ptr;
> }
>
> -static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *arg)
> +static inline void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg)
> {
>     uint8_t *old_code_ptr = s->code_ptr;
>     tcg_out_op_t(s, INDEX_op_call);
> diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h
> index 8c1c1d265d..2a258ea350 100644
> --- a/tcg/tci/tcg-target.h
> +++ b/tcg/tci/tcg-target.h
> @@ -195,6 +195,12 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
> {
> }
>
> +#if defined(CONFIG_IOS_JIT)
> +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> +{
> +}
> +#endif
> +
> /* We could notice __i386__ or __s390x__ and reduce the barriers depending
>    on the host.  But if you want performance, you use the normal backend.
>    We prefer consistency across hosts on this.  */
> @@ -203,7 +209,8 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
> #define TCG_TARGET_HAS_MEMORY_BSWAP     1
>
> static inline void tb_target_set_jmp_target(uintptr_t tc_ptr,
> -                                            uintptr_t jmp_addr, uintptr_t addr)
> +                                            uintptr_t jmp_addr, uintptr_t addr,
> +                                            uintptr_t wr_addr)
> {
>     /* patch the branch destination */
>     qatomic_set((int32_t *)jmp_addr, addr - (jmp_addr + 4));
>


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 07/10] tcg: implement bulletproof JIT
@ 2020-10-13 14:58     ` BALATON Zoltan
  0 siblings, 0 replies; 47+ messages in thread
From: BALATON Zoltan @ 2020-10-13 14:58 UTC (permalink / raw)
  To: Joelle van Dyne
  Cc: qemu-devel, Aleksandar Rikalo, open list:RISC-V TCG target,
	Stefan Weil, open list:S390 TCG target, Aleksandar Markovic,
	open list:AArch64 TCG target, Palmer Dabbelt, Huacai Chen,
	Paolo Bonzini, Alistair Francis, Aurelien Jarno,
	Richard Henderson

On Mon, 12 Oct 2020, Joelle van Dyne wrote:
> From: osy <osy86@users.noreply.github.com>
>
> On iOS, we cannot allocate RWX pages without special entitlements. As a
> workaround, we can a RX region and then mirror map it to a separate RX

Missing a verb here: "we can a RX region"

> region. Then we can write to one region and execute from the other one.
>
> To better keep track of pointers to RW/RX memory, we mark any tcg_insn_unit
> pointers as `const` if they will never be written to. We also define a new
> macro `TCG_CODE_PTR_RW` that returns a pointer to RW memory. Only the
> difference between the two regions is stored in the TCG context.

Maybe it's easier to review if constification is split off as separate 
patch before other changes.

> To ensure cache coherency, we flush the data cache in the RW mapping and
> then invalidate the instruction cache in the RX mapping (where applicable).
> Because data cache flush is OS defined on some architectures, we do not
> provide implementations for non iOS platforms (ARM/x86).
>
> Signed-off-by: Joelle van Dyne <j@getutm.app>
> ---
> accel/tcg/cpu-exec.c         |  7 +++-
> accel/tcg/translate-all.c    | 78 ++++++++++++++++++++++++++++++++++--
> configure                    |  1 +
> docs/devel/ios.rst           | 40 ++++++++++++++++++
> include/exec/exec-all.h      |  8 ++++
> include/tcg/tcg.h            | 18 +++++++--
> tcg/aarch64/tcg-target.c.inc | 48 +++++++++++++---------
> tcg/aarch64/tcg-target.h     | 13 +++++-
> tcg/arm/tcg-target.c.inc     | 33 ++++++++-------
> tcg/arm/tcg-target.h         |  9 ++++-
> tcg/i386/tcg-target.c.inc    | 28 ++++++-------
> tcg/i386/tcg-target.h        | 24 ++++++++++-
> tcg/mips/tcg-target.c.inc    | 64 +++++++++++++++++------------
> tcg/mips/tcg-target.h        |  8 +++-
> tcg/ppc/tcg-target.c.inc     | 55 ++++++++++++++++---------
> tcg/ppc/tcg-target.h         |  8 +++-
> tcg/riscv/tcg-target.c.inc   | 51 +++++++++++++----------
> tcg/riscv/tcg-target.h       |  9 ++++-
> tcg/s390/tcg-target.c.inc    | 25 ++++++------
> tcg/s390/tcg-target.h        | 13 +++++-
> tcg/sparc/tcg-target.c.inc   | 33 +++++++++------
> tcg/sparc/tcg-target.h       |  8 +++-
> tcg/tcg-ldst.c.inc           |  2 +-
> tcg/tcg-pool.c.inc           |  9 +++--
> tcg/tcg.c                    | 60 +++++++++++++++++----------
> tcg/tci/tcg-target.c.inc     |  8 ++--
> tcg/tci/tcg-target.h         |  9 ++++-
> 27 files changed, 481 insertions(+), 188 deletions(-)
> create mode 100644 docs/devel/ios.rst
>
> diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
> index 58aea605d8..821aefdea2 100644
> --- a/accel/tcg/cpu-exec.c
> +++ b/accel/tcg/cpu-exec.c
> @@ -354,7 +354,12 @@ void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr)
>     if (TCG_TARGET_HAS_direct_jump) {
>         uintptr_t offset = tb->jmp_target_arg[n];
>         uintptr_t tc_ptr = (uintptr_t)tb->tc.ptr;
> -        tb_target_set_jmp_target(tc_ptr, tc_ptr + offset, addr);
> +#if defined(CONFIG_IOS_JIT)
> +        uintptr_t wr_addr = tc_ptr + offset + tb->code_rw_mirror_diff;
> +#else
> +        uintptr_t wr_addr = tc_ptr + offset;
> +#endif
> +        tb_target_set_jmp_target(tc_ptr, tc_ptr + offset, addr, wr_addr);
>     } else {
>         tb->jmp_target_arg[n] = addr;
>     }
> diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
> index d76097296d..76d8dc3d7b 100644
> --- a/accel/tcg/translate-all.c
> +++ b/accel/tcg/translate-all.c
> @@ -60,6 +60,22 @@
> #include "sysemu/cpu-timers.h"
> #include "sysemu/tcg.h"
>
> +#if defined(CONFIG_IOS_JIT)
> +#include <mach/mach.h>
> +extern kern_return_t mach_vm_remap(vm_map_t target_task,
> +                                   mach_vm_address_t *target_address,
> +                                   mach_vm_size_t size,
> +                                   mach_vm_offset_t mask,
> +                                   int flags,
> +                                   vm_map_t src_task,
> +                                   mach_vm_address_t src_address,
> +                                   boolean_t copy,
> +                                   vm_prot_t *cur_protection,
> +                                   vm_prot_t *max_protection,
> +                                   vm_inherit_t inheritance
> +                                  );
> +#endif
> +
> /* #define DEBUG_TB_INVALIDATE */
> /* #define DEBUG_TB_FLUSH */
> /* make various TB consistency checks */
> @@ -302,10 +318,13 @@ static target_long decode_sleb128(uint8_t **pp)
>
> static int encode_search(TranslationBlock *tb, uint8_t *block)
> {
> -    uint8_t *highwater = tcg_ctx->code_gen_highwater;
> -    uint8_t *p = block;
> +    uint8_t *highwater;
> +    uint8_t *p;
>     int i, j, n;
>
> +    highwater = (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx,
> +                                           tcg_ctx->code_gen_highwater);
> +    p = (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx, block);

Why do you need explicit casts here? Can this be avoided by using 
appropriate type or within the macro (I haven't checked this at all just 
dislike casts as they can hide problems otherwise caught by the compiler).

Regards,
BALATON Zoltan

>     for (i = 0, n = tb->icount; i < n; ++i) {
>         target_ulong prev;
>
> @@ -329,7 +348,7 @@ static int encode_search(TranslationBlock *tb, uint8_t *block)
>         }
>     }
>
> -    return p - block;
> +    return p - (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx, block);
> }
>
> /* The cpu state corresponding to 'searched_pc' is restored.
> @@ -1067,7 +1086,11 @@ static inline void *alloc_code_gen_buffer(void)
> #else
> static inline void *alloc_code_gen_buffer(void)
> {
> +#if defined(CONFIG_IOS_JIT)
> +    int prot = PROT_READ | PROT_EXEC;
> +#else
>     int prot = PROT_WRITE | PROT_READ | PROT_EXEC;
> +#endif
>     int flags = MAP_PRIVATE | MAP_ANONYMOUS;
>     size_t size = tcg_ctx->code_gen_buffer_size;
>     void *buf;
> @@ -1118,6 +1141,39 @@ static inline void *alloc_code_gen_buffer(void)
> }
> #endif /* USE_STATIC_CODE_GEN_BUFFER, WIN32, POSIX */
>
> +#if defined(CONFIG_IOS_JIT)
> +static inline void *alloc_jit_rw_mirror(void *base, size_t size)
> +{
> +    kern_return_t ret;
> +    mach_vm_address_t mirror;
> +    vm_prot_t cur_prot, max_prot;
> +
> +    mirror = 0;
> +    ret = mach_vm_remap(mach_task_self(),
> +                        &mirror,
> +                        size,
> +                        0,
> +                        VM_FLAGS_ANYWHERE | VM_FLAGS_RANDOM_ADDR,
> +                        mach_task_self(),
> +                        (mach_vm_address_t)base,
> +                        false,
> +                        &cur_prot,
> +                        &max_prot,
> +                        VM_INHERIT_NONE
> +                       );
> +    if (ret != KERN_SUCCESS) {
> +        return NULL;
> +    }
> +
> +    if (mprotect((void *)mirror, size, PROT_READ | PROT_WRITE) != 0) {
> +        munmap((void *)mirror, size);
> +        return NULL;
> +    }
> +
> +    return (void *)mirror;
> +}
> +#endif /* CONFIG_IOS_JIT */
> +
> static inline void code_gen_alloc(size_t tb_size)
> {
>     tcg_ctx->code_gen_buffer_size = size_code_gen_buffer(tb_size);
> @@ -1126,6 +1182,19 @@ static inline void code_gen_alloc(size_t tb_size)
>         fprintf(stderr, "Could not allocate dynamic translator buffer\n");
>         exit(1);
>     }
> +#if defined(CONFIG_IOS_JIT)
> +    void *mirror;
> +
> +    /* For iOS JIT we need a mirror mapping for code execution */
> +    mirror = alloc_jit_rw_mirror(tcg_ctx->code_gen_buffer,
> +                                 tcg_ctx->code_gen_buffer_size
> +                                );
> +    if (mirror == NULL) {
> +        fprintf(stderr, "Could not remap code buffer mirror\n");
> +        exit(1);
> +    }
> +    tcg_ctx->code_rw_mirror_diff = mirror - tcg_ctx->code_gen_buffer;
> +#endif /* CONFIG_IOS_JIT */
> }
>
> static bool tb_cmp(const void *ap, const void *bp)
> @@ -1721,6 +1790,9 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
>         cpu_loop_exit(cpu);
>     }
>
> +#if defined(CONFIG_IOS_JIT)
> +    tb->code_rw_mirror_diff = tcg_ctx->code_rw_mirror_diff;
> +#endif
>     gen_code_buf = tcg_ctx->code_gen_ptr;
>     tb->tc.ptr = gen_code_buf;
>     tb->pc = pc;
> diff --git a/configure b/configure
> index 16c66b437c..c5a6584683 100755
> --- a/configure
> +++ b/configure
> @@ -6220,6 +6220,7 @@ fi
>
> if test "$ios" = "yes" ; then
>   echo "CONFIG_IOS=y" >> $config_host_mak
> +  echo "CONFIG_IOS_JIT=y" >> $config_host_mak
> fi
>
> if test "$solaris" = "yes" ; then
> diff --git a/docs/devel/ios.rst b/docs/devel/ios.rst
> new file mode 100644
> index 0000000000..dba9fdd868
> --- /dev/null
> +++ b/docs/devel/ios.rst
> @@ -0,0 +1,40 @@
> +===========
> +iOS Support
> +===========
> +
> +To run qemu on the iOS platform, some modifications were required. Most of the
> +modifications are conditioned on the ``CONFIG_IOS`` and ``CONFIG_IOS_JIT``
> +configuration variables.
> +
> +Build support
> +-------------
> +
> +For the code to compile, certain changes in the block driver and the slirp
> +driver had to be made. There is no ``system()`` call, so code requiring it had
> +to be disabled.
> +
> +``ucontext`` support is broken on iOS. The implementation from ``libucontext``
> +is used instead.
> +
> +Because ``fork()`` is not allowed on iOS apps, the option to build qemu and the
> +utilities as shared libraries is added. Note that because qemu does not perform
> +resource cleanup in most cases (open files, allocated memory, etc), it is
> +advisable that the user implements a proxy layer for syscalls so resources can
> +be kept track by the app that uses qemu as a shared library.
> +
> +JIT support
> +-----------
> +
> +On iOS, allocating RWX pages require special entitlements not usually granted to
> +apps. However, it is possible to use `bulletproof JIT`_ with a development
> +certificate. This means that we need to allocate one chunk of memory with RX
> +permissions and then mirror map the same memory with RW permissions. We generate
> +code to the mirror mapping and execute the original mapping.
> +
> +With ``CONFIG_IOS_JIT`` defined, we store inside the TCG context the difference
> +between the two mappings. Then, we make sure that any writes to JIT memory is
> +done to the pointer + the difference (in order to get a pointer to the mirror
> +mapped space). Additionally, we make sure to flush the data cache before we
> +invalidate the instruction cache so the changes are seen in both mappings.
> +
> +.. _bulletproof JIT: https://www.blackhat.com/docs/us-16/materials/us-16-Krstic.pdf
> diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
> index 66f9b4cca6..2db155a772 100644
> --- a/include/exec/exec-all.h
> +++ b/include/exec/exec-all.h
> @@ -483,6 +483,14 @@ struct TranslationBlock {
>     uintptr_t jmp_list_head;
>     uintptr_t jmp_list_next[2];
>     uintptr_t jmp_dest[2];
> +
> +#if defined(CONFIG_IOS_JIT)
> +    /*
> +     * Store difference to writable mirror
> +     * We need this when patching the jump instructions
> +     */
> +    ptrdiff_t code_rw_mirror_diff;
> +#endif
> };
>
> extern bool parallel_cpus;
> diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
> index 8804a8c4a2..40d1a7a85e 100644
> --- a/include/tcg/tcg.h
> +++ b/include/tcg/tcg.h
> @@ -261,7 +261,7 @@ struct TCGLabel {
>     unsigned refs : 16;
>     union {
>         uintptr_t value;
> -        tcg_insn_unit *value_ptr;
> +        const tcg_insn_unit *value_ptr;
>     } u;
>     QSIMPLEQ_HEAD(, TCGRelocation) relocs;
>     QSIMPLEQ_ENTRY(TCGLabel) next;
> @@ -593,7 +593,7 @@ struct TCGContext {
>     int nb_ops;
>
>     /* goto_tb support */
> -    tcg_insn_unit *code_buf;
> +    const tcg_insn_unit *code_buf;
>     uint16_t *tb_jmp_reset_offset; /* tb->jmp_reset_offset */
>     uintptr_t *tb_jmp_insn_offset; /* tb->jmp_target_arg if direct_jump */
>     uintptr_t *tb_jmp_target_addr; /* tb->jmp_target_arg if !direct_jump */
> @@ -627,6 +627,9 @@ struct TCGContext {
>     size_t code_gen_buffer_size;
>     void *code_gen_ptr;
>     void *data_gen_ptr;
> +#if defined(CONFIG_IOS_JIT)
> +    ptrdiff_t code_rw_mirror_diff;
> +#endif
>
>     /* Threshold to flush the translated code buffer.  */
>     void *code_gen_highwater;
> @@ -677,6 +680,13 @@ struct TCGContext {
>     target_ulong gen_insn_data[TCG_MAX_INSNS][TARGET_INSN_START_WORDS];
> };
>
> +#if defined(CONFIG_IOS_JIT)
> +# define TCG_CODE_PTR_RW(s, code_ptr) \
> +    (tcg_insn_unit *)((uintptr_t)(code_ptr) + (s)->code_rw_mirror_diff)
> +#else
> +# define TCG_CODE_PTR_RW(s, code_ptr) (code_ptr)
> +#endif
> +
> extern TCGContext tcg_init_ctx;
> extern __thread TCGContext *tcg_ctx;
> extern TCGv_env cpu_env;
> @@ -1099,7 +1109,7 @@ static inline TCGLabel *arg_label(TCGArg i)
>  * correct result.
>  */
>
> -static inline ptrdiff_t tcg_ptr_byte_diff(void *a, void *b)
> +static inline ptrdiff_t tcg_ptr_byte_diff(const void *a, const void *b)
> {
>     return a - b;
> }
> @@ -1113,7 +1123,7 @@ static inline ptrdiff_t tcg_ptr_byte_diff(void *a, void *b)
>  * to the destination address.
>  */
>
> -static inline ptrdiff_t tcg_pcrel_diff(TCGContext *s, void *target)
> +static inline ptrdiff_t tcg_pcrel_diff(TCGContext *s, const void *target)
> {
>     return tcg_ptr_byte_diff(target, s->code_ptr);
> }
> diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc
> index 26f71cb599..9cfa2703b3 100644
> --- a/tcg/aarch64/tcg-target.c.inc
> +++ b/tcg/aarch64/tcg-target.c.inc
> @@ -78,38 +78,44 @@ static const int tcg_target_call_oarg_regs[1] = {
> #define TCG_REG_GUEST_BASE TCG_REG_X28
> #endif
>
> -static inline bool reloc_pc26(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
> +static inline bool reloc_pc26(TCGContext *s,
> +                              tcg_insn_unit *code_ptr,
> +                              const tcg_insn_unit *target)
> {
>     ptrdiff_t offset = target - code_ptr;
>     if (offset == sextract64(offset, 0, 26)) {
>         /* read instruction, mask away previous PC_REL26 parameter contents,
>            set the proper offset, then write back the instruction. */
> -        *code_ptr = deposit32(*code_ptr, 0, 26, offset);
> +        *TCG_CODE_PTR_RW(s, code_ptr) =
> +            deposit32(*TCG_CODE_PTR_RW(s, code_ptr), 0, 26, offset);
>         return true;
>     }
>     return false;
> }
>
> -static inline bool reloc_pc19(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
> +static inline bool reloc_pc19(TCGContext *s,
> +                              tcg_insn_unit *code_ptr,
> +                              const tcg_insn_unit *target)
> {
>     ptrdiff_t offset = target - code_ptr;
>     if (offset == sextract64(offset, 0, 19)) {
> -        *code_ptr = deposit32(*code_ptr, 5, 19, offset);
> +        *TCG_CODE_PTR_RW(s, code_ptr) =
> +            deposit32(*TCG_CODE_PTR_RW(s, code_ptr), 5, 19, offset);
>         return true;
>     }
>     return false;
> }
>
> -static inline bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> +static inline bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
>                                intptr_t value, intptr_t addend)
> {
>     tcg_debug_assert(addend == 0);
>     switch (type) {
>     case R_AARCH64_JUMP26:
>     case R_AARCH64_CALL26:
> -        return reloc_pc26(code_ptr, (tcg_insn_unit *)value);
> +        return reloc_pc26(s, code_ptr, (tcg_insn_unit *)value);
>     case R_AARCH64_CONDBR19:
> -        return reloc_pc19(code_ptr, (tcg_insn_unit *)value);
> +        return reloc_pc19(s, code_ptr, (tcg_insn_unit *)value);
>     default:
>         g_assert_not_reached();
>     }
> @@ -1306,14 +1312,14 @@ static void tcg_out_cmp(TCGContext *s, TCGType ext, TCGReg a,
>     }
> }
>
> -static inline void tcg_out_goto(TCGContext *s, tcg_insn_unit *target)
> +static inline void tcg_out_goto(TCGContext *s, const tcg_insn_unit *target)
> {
>     ptrdiff_t offset = target - s->code_ptr;
>     tcg_debug_assert(offset == sextract64(offset, 0, 26));
>     tcg_out_insn(s, 3206, B, offset);
> }
>
> -static inline void tcg_out_goto_long(TCGContext *s, tcg_insn_unit *target)
> +static inline void tcg_out_goto_long(TCGContext *s, const tcg_insn_unit *target)
> {
>     ptrdiff_t offset = target - s->code_ptr;
>     if (offset == sextract64(offset, 0, 26)) {
> @@ -1329,7 +1335,7 @@ static inline void tcg_out_callr(TCGContext *s, TCGReg reg)
>     tcg_out_insn(s, 3207, BLR, reg);
> }
>
> -static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *target)
> +static inline void tcg_out_call(TCGContext *s, const tcg_insn_unit *target)
> {
>     ptrdiff_t offset = target - s->code_ptr;
>     if (offset == sextract64(offset, 0, 26)) {
> @@ -1341,7 +1347,7 @@ static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *target)
> }
>
> void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
> -                              uintptr_t addr)
> +                              uintptr_t addr, uintptr_t wr_addr)
> {
>     tcg_insn_unit i1, i2;
>     TCGType rt = TCG_TYPE_I64;
> @@ -1362,7 +1368,10 @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
>         i2 = I3401_ADDI | rt << 31 | (addr & 0xfff) << 10 | rd << 5 | rd;
>     }
>     pair = (uint64_t)i2 << 32 | i1;
> -    qatomic_set((uint64_t *)jmp_addr, pair);
> +    qatomic_set((uint64_t *)wr_addr, pair);
> +#if defined(CONFIG_IOS_JIT)
> +    flush_dcache_range(wr_addr, wr_addr + 8);
> +#endif
>     flush_icache_range(jmp_addr, jmp_addr + 8);
> }
>
> @@ -1568,7 +1577,7 @@ static void * const qemu_st_helpers[16] = {
>     [MO_BEQ]  = helper_be_stq_mmu,
> };
>
> -static inline void tcg_out_adr(TCGContext *s, TCGReg rd, void *target)
> +static inline void tcg_out_adr(TCGContext *s, TCGReg rd, const void *target)
> {
>     ptrdiff_t offset = tcg_pcrel_diff(s, target);
>     tcg_debug_assert(offset == sextract64(offset, 0, 21));
> @@ -1581,7 +1590,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
>     MemOp opc = get_memop(oi);
>     MemOp size = opc & MO_SIZE;
>
> -    if (!reloc_pc19(lb->label_ptr[0], s->code_ptr)) {
> +    if (!reloc_pc19(s, lb->label_ptr[0], s->code_ptr)) {
>         return false;
>     }
>
> @@ -1606,7 +1615,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
>     MemOp opc = get_memop(oi);
>     MemOp size = opc & MO_SIZE;
>
> -    if (!reloc_pc19(lb->label_ptr[0], s->code_ptr)) {
> +    if (!reloc_pc19(s, lb->label_ptr[0], s->code_ptr)) {
>         return false;
>     }
>
> @@ -1622,7 +1631,8 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
>
> static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
>                                 TCGType ext, TCGReg data_reg, TCGReg addr_reg,
> -                                tcg_insn_unit *raddr, tcg_insn_unit *label_ptr)
> +                                const tcg_insn_unit *raddr,
> +                                tcg_insn_unit *label_ptr)
> {
>     TCGLabelQemuLdst *label = new_ldst_label(s);
>
> @@ -1849,7 +1859,7 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg,
> #endif /* CONFIG_SOFTMMU */
> }
>
> -static tcg_insn_unit *tb_ret_addr;
> +static const tcg_insn_unit *tb_ret_addr;
>
> static void tcg_out_op(TCGContext *s, TCGOpcode opc,
>                        const TCGArg args[TCG_MAX_OP_ARGS],
> @@ -2916,11 +2926,11 @@ static void tcg_target_qemu_prologue(TCGContext *s)
>     tcg_out_insn(s, 3207, RET, TCG_REG_LR);
> }
>
> -static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
> +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
> {
>     int i;
>     for (i = 0; i < count; ++i) {
> -        p[i] = NOP;
> +        (TCG_CODE_PTR_RW(s, p))[i] = NOP;
>     }
> }
>
> diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h
> index a2b22b4305..78c97460a1 100644
> --- a/tcg/aarch64/tcg-target.h
> +++ b/tcg/aarch64/tcg-target.h
> @@ -150,6 +150,7 @@ typedef enum {
>
> #if defined(__APPLE__)
> void sys_icache_invalidate(void *start, size_t len);
> +void sys_dcache_flush(void *start, size_t len);
> #endif
>
> static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
> @@ -163,7 +164,17 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
> #endif
> }
>
> -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
> +void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
> +#if defined(CONFIG_IOS_JIT)
> +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> +{
> +#if defined(__APPLE__)
> +    sys_dcache_flush((char *)start, stop - start);
> +#else
> +#error "Missing function to flush data cache"
> +#endif
> +}
> +#endif
>
> #ifdef CONFIG_SOFTMMU
> #define TCG_TARGET_NEED_LDST_LABELS
> diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc
> index 62c37a954b..d27ad851b5 100644
> --- a/tcg/arm/tcg-target.c.inc
> +++ b/tcg/arm/tcg-target.c.inc
> @@ -187,17 +187,22 @@ static const uint8_t tcg_cond_to_arm_cond[] = {
>     [TCG_COND_GTU] = COND_HI,
> };
>
> -static inline bool reloc_pc24(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
> +static inline bool reloc_pc24(TCGContext *s,
> +                              tcg_insn_unit *code_ptr,
> +                              const tcg_insn_unit *target)
> {
>     ptrdiff_t offset = (tcg_ptr_byte_diff(target, code_ptr) - 8) >> 2;
>     if (offset == sextract32(offset, 0, 24)) {
> -        *code_ptr = (*code_ptr & ~0xffffff) | (offset & 0xffffff);
> +        *TCG_CODE_PTR_RW(s, code_ptr) =
> +            (*TCG_CODE_PTR_RW(s, code_ptr) & ~0xffffff) | (offset & 0xffffff);
>         return true;
>     }
>     return false;
> }
>
> -static inline bool reloc_pc13(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
> +static inline bool reloc_pc13(TCGContext *s,
> +                              tcg_insn_unit *code_ptr,
> +                              const tcg_insn_unit *target)
> {
>     ptrdiff_t offset = tcg_ptr_byte_diff(target, code_ptr) - 8;
>
> @@ -209,21 +214,21 @@ static inline bool reloc_pc13(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
>         }
>         insn = deposit32(insn, 23, 1, u);
>         insn = deposit32(insn, 0, 12, offset);
> -        *code_ptr = insn;
> +        *TCG_CODE_PTR_RW(s, code_ptr) = insn;
>         return true;
>     }
>     return false;
> }
>
> -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
>                         intptr_t value, intptr_t addend)
> {
>     tcg_debug_assert(addend == 0);
>
>     if (type == R_ARM_PC24) {
> -        return reloc_pc24(code_ptr, (tcg_insn_unit *)value);
> +        return reloc_pc24(s, code_ptr, (tcg_insn_unit *)value);
>     } else if (type == R_ARM_PC13) {
> -        return reloc_pc13(code_ptr, (tcg_insn_unit *)value);
> +        return reloc_pc13(s, code_ptr, (tcg_insn_unit *)value);
>     } else {
>         g_assert_not_reached();
>     }
> @@ -1019,7 +1024,7 @@ static inline void tcg_out_st8(TCGContext *s, int cond,
>  * with the code buffer limited to 16MB we wouldn't need the long case.
>  * But we also use it for the tail-call to the qemu_ld/st helpers, which does.
>  */
> -static void tcg_out_goto(TCGContext *s, int cond, tcg_insn_unit *addr)
> +static void tcg_out_goto(TCGContext *s, int cond, const tcg_insn_unit *addr)
> {
>     intptr_t addri = (intptr_t)addr;
>     ptrdiff_t disp = tcg_pcrel_diff(s, addr);
> @@ -1033,7 +1038,7 @@ static void tcg_out_goto(TCGContext *s, int cond, tcg_insn_unit *addr)
>
> /* The call case is mostly used for helpers - so it's not unreasonable
>  * for them to be beyond branch range */
> -static void tcg_out_call(TCGContext *s, tcg_insn_unit *addr)
> +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *addr)
> {
>     intptr_t addri = (intptr_t)addr;
>     ptrdiff_t disp = tcg_pcrel_diff(s, addr);
> @@ -1326,7 +1331,7 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addrlo, TCGReg addrhi,
>    helper code.  */
> static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
>                                 TCGReg datalo, TCGReg datahi, TCGReg addrlo,
> -                                TCGReg addrhi, tcg_insn_unit *raddr,
> +                                TCGReg addrhi, const tcg_insn_unit *raddr,
>                                 tcg_insn_unit *label_ptr)
> {
>     TCGLabelQemuLdst *label = new_ldst_label(s);
> @@ -1348,7 +1353,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
>     MemOp opc = get_memop(oi);
>     void *func;
>
> -    if (!reloc_pc24(lb->label_ptr[0], s->code_ptr)) {
> +    if (!reloc_pc24(s, lb->label_ptr[0], s->code_ptr)) {
>         return false;
>     }
>
> @@ -1411,7 +1416,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
>     TCGMemOpIdx oi = lb->oi;
>     MemOp opc = get_memop(oi);
>
> -    if (!reloc_pc24(lb->label_ptr[0], s->code_ptr)) {
> +    if (!reloc_pc24(s, lb->label_ptr[0], s->code_ptr)) {
>         return false;
>     }
>
> @@ -2255,11 +2260,11 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type,
>     tcg_out_movi32(s, COND_AL, ret, arg);
> }
>
> -static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
> +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
> {
>     int i;
>     for (i = 0; i < count; ++i) {
> -        p[i] = INSN_NOP;
> +        (TCG_CODE_PTR_RW(s, p))[i] = INSN_NOP;
>     }
> }
>
> diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
> index 17e771374d..d8d7e7e239 100644
> --- a/tcg/arm/tcg-target.h
> +++ b/tcg/arm/tcg-target.h
> @@ -139,8 +139,15 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
>     __builtin___clear_cache((char *) start, (char *) stop);
> }
>
> +#if defined(CONFIG_IOS_JIT)
> +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> +{
> +#error "Unimplemented dcache flush function"
> +}
> +#endif
> +
> /* not defined -- call should be eliminated at compile time */
> -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
> +void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
>
> #ifdef CONFIG_SOFTMMU
> #define TCG_TARGET_NEED_LDST_LABELS
> diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc
> index d8797ed398..e9c128d9e7 100644
> --- a/tcg/i386/tcg-target.c.inc
> +++ b/tcg/i386/tcg-target.c.inc
> @@ -165,9 +165,9 @@ static bool have_lzcnt;
> # define have_lzcnt 0
> #endif
>
> -static tcg_insn_unit *tb_ret_addr;
> +static const tcg_insn_unit *tb_ret_addr;
>
> -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
>                         intptr_t value, intptr_t addend)
> {
>     value += addend;
> @@ -179,14 +179,14 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
>         }
>         /* FALLTHRU */
>     case R_386_32:
> -        tcg_patch32(code_ptr, value);
> +        tcg_patch32(s, code_ptr, value);
>         break;
>     case R_386_PC8:
>         value -= (uintptr_t)code_ptr;
>         if (value != (int8_t)value) {
>             return false;
>         }
> -        tcg_patch8(code_ptr, value);
> +        tcg_patch8(s, code_ptr, value);
>         break;
>     default:
>         tcg_abort();
> @@ -1591,7 +1591,7 @@ static void tcg_out_clz(TCGContext *s, int rexw, TCGReg dest, TCGReg arg1,
>     }
> }
>
> -static void tcg_out_branch(TCGContext *s, int call, tcg_insn_unit *dest)
> +static void tcg_out_branch(TCGContext *s, int call, const tcg_insn_unit *dest)
> {
>     intptr_t disp = tcg_pcrel_diff(s, dest) - 5;
>
> @@ -1610,12 +1610,12 @@ static void tcg_out_branch(TCGContext *s, int call, tcg_insn_unit *dest)
>     }
> }
>
> -static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *dest)
> +static inline void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest)
> {
>     tcg_out_branch(s, 1, dest);
> }
>
> -static void tcg_out_jmp(TCGContext *s, tcg_insn_unit *dest)
> +static void tcg_out_jmp(TCGContext *s, const tcg_insn_unit *dest)
> {
>     tcg_out_branch(s, 0, dest);
> }
> @@ -1774,7 +1774,7 @@ static void add_qemu_ldst_label(TCGContext *s, bool is_ld, bool is_64,
>                                 TCGMemOpIdx oi,
>                                 TCGReg datalo, TCGReg datahi,
>                                 TCGReg addrlo, TCGReg addrhi,
> -                                tcg_insn_unit *raddr,
> +                                const tcg_insn_unit *raddr,
>                                 tcg_insn_unit **label_ptr)
> {
>     TCGLabelQemuLdst *label = new_ldst_label(s);
> @@ -1805,9 +1805,9 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
>     int rexw = (l->type == TCG_TYPE_I64 ? P_REXW : 0);
>
>     /* resolve label address */
> -    tcg_patch32(label_ptr[0], s->code_ptr - label_ptr[0] - 4);
> +    tcg_patch32(s, label_ptr[0], s->code_ptr - label_ptr[0] - 4);
>     if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
> -        tcg_patch32(label_ptr[1], s->code_ptr - label_ptr[1] - 4);
> +        tcg_patch32(s, label_ptr[1], s->code_ptr - label_ptr[1] - 4);
>     }
>
>     if (TCG_TARGET_REG_BITS == 32) {
> @@ -1890,9 +1890,9 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
>     TCGReg retaddr;
>
>     /* resolve label address */
> -    tcg_patch32(label_ptr[0], s->code_ptr - label_ptr[0] - 4);
> +    tcg_patch32(s, label_ptr[0], s->code_ptr - label_ptr[0] - 4);
>     if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
> -        tcg_patch32(label_ptr[1], s->code_ptr - label_ptr[1] - 4);
> +        tcg_patch32(s, label_ptr[1], s->code_ptr - label_ptr[1] - 4);
>     }
>
>     if (TCG_TARGET_REG_BITS == 32) {
> @@ -3842,9 +3842,9 @@ static void tcg_target_qemu_prologue(TCGContext *s)
>     tcg_out_opc(s, OPC_RET, 0, 0, 0);
> }
>
> -static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
> +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
> {
> -    memset(p, 0x90, count);
> +    memset(TCG_CODE_PTR_RW(s, p), 0x90, count);
> }
>
> static void tcg_target_init(TCGContext *s)
> diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
> index abd4ac7fc0..cdc440ce36 100644
> --- a/tcg/i386/tcg-target.h
> +++ b/tcg/i386/tcg-target.h
> @@ -206,16 +206,36 @@ extern bool have_avx2;
> #define TCG_TARGET_extract_i64_valid(ofs, len) \
>     (((ofs) == 8 && (len) == 8) || ((ofs) + (len)) == 32)
>
> +#ifdef __APPLE__
> +void sys_dcache_flush(void *start, size_t len);
> +#endif
> +
> static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
> {
> }
>
> +#if defined(CONFIG_IOS_JIT)
> +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> +{
> +#if defined(__APPLE__)
> +    sys_dcache_flush((char *)start, stop - start);
> +#else
> +#error "Missing function to flush data cache"
> +#endif
> +}
> +#endif
> +
> static inline void tb_target_set_jmp_target(uintptr_t tc_ptr,
> -                                            uintptr_t jmp_addr, uintptr_t addr)
> +                                            uintptr_t jmp_addr, uintptr_t addr,
> +                                            uintptr_t wr_addr)
> {
>     /* patch the branch destination */
> -    qatomic_set((int32_t *)jmp_addr, addr - (jmp_addr + 4));
> +    qatomic_set((int32_t *)wr_addr, addr - (jmp_addr + 4));
>     /* no need to flush icache explicitly */
> +#if defined(CONFIG_IOS_JIT)
> +    /* we do need to flush mirror dcache */
> +    flush_dcache_range(wr_addr, wr_addr + 4);
> +#endif
> }
>
> /* This defines the natural memory order supported by this
> diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc
> index 41be574e89..e798527437 100644
> --- a/tcg/mips/tcg-target.c.inc
> +++ b/tcg/mips/tcg-target.c.inc
> @@ -139,12 +139,13 @@ static const TCGReg tcg_target_call_oarg_regs[2] = {
>     TCG_REG_V1
> };
>
> -static tcg_insn_unit *tb_ret_addr;
> -static tcg_insn_unit *bswap32_addr;
> -static tcg_insn_unit *bswap32u_addr;
> -static tcg_insn_unit *bswap64_addr;
> +static const tcg_insn_unit *tb_ret_addr;
> +static const tcg_insn_unit *bswap32_addr;
> +static const tcg_insn_unit *bswap32u_addr;
> +static const tcg_insn_unit *bswap64_addr;
>
> -static inline uint32_t reloc_pc16_val(tcg_insn_unit *pc, tcg_insn_unit *target)
> +static inline uint32_t reloc_pc16_val(const tcg_insn_unit *pc,
> +                                      const tcg_insn_unit *target)
> {
>     /* Let the compiler perform the right-shift as part of the arithmetic.  */
>     ptrdiff_t disp = target - (pc + 1);
> @@ -152,28 +153,35 @@ static inline uint32_t reloc_pc16_val(tcg_insn_unit *pc, tcg_insn_unit *target)
>     return disp & 0xffff;
> }
>
> -static inline void reloc_pc16(tcg_insn_unit *pc, tcg_insn_unit *target)
> +static inline void reloc_pc16(TCGContext *s,
> +                              tcg_insn_unit *pc,
> +                              const tcg_insn_unit *target)
> {
> -    *pc = deposit32(*pc, 0, 16, reloc_pc16_val(pc, target));
> +    *TCG_CODE_PTR_RW(s, pc) =
> +        deposit32(*TCG_CODE_PTR_RW(s, pc), 0, 16, reloc_pc16_val(pc, target));
> }
>
> -static inline uint32_t reloc_26_val(tcg_insn_unit *pc, tcg_insn_unit *target)
> +static inline uint32_t reloc_26_val(const tcg_insn_unit *pc,
> +                                    const tcg_insn_unit *target)
> {
>     tcg_debug_assert((((uintptr_t)pc ^ (uintptr_t)target) & 0xf0000000) == 0);
>     return ((uintptr_t)target >> 2) & 0x3ffffff;
> }
>
> -static inline void reloc_26(tcg_insn_unit *pc, tcg_insn_unit *target)
> +static inline void reloc_26(TCGContext *s,
> +                            tcg_insn_unit *pc,
> +                            const tcg_insn_unit *target)
> {
> -    *pc = deposit32(*pc, 0, 26, reloc_26_val(pc, target));
> +    *TCG_CODE_PTR_RW(s, pc) =
> +        deposit32(*TCG_CODE_PTR_RW(s, pc), 0, 26, reloc_26_val(pc, target));
> }
>
> -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
>                         intptr_t value, intptr_t addend)
> {
>     tcg_debug_assert(type == R_MIPS_PC16);
>     tcg_debug_assert(addend == 0);
> -    reloc_pc16(code_ptr, (tcg_insn_unit *)value);
> +    reloc_pc16(s, code_ptr, (tcg_insn_unit *)value);
>     return true;
> }
>
> @@ -516,7 +524,7 @@ static void tcg_out_opc_sa64(TCGContext *s, MIPSInsn opc1, MIPSInsn opc2,
>  * Type jump.
>  * Returns true if the branch was in range and the insn was emitted.
>  */
> -static bool tcg_out_opc_jmp(TCGContext *s, MIPSInsn opc, void *target)
> +static bool tcg_out_opc_jmp(TCGContext *s, MIPSInsn opc, const void *target)
> {
>     uintptr_t dest = (uintptr_t)target;
>     uintptr_t from = (uintptr_t)s->code_ptr + 4;
> @@ -631,7 +639,7 @@ static inline void tcg_out_bswap16s(TCGContext *s, TCGReg ret, TCGReg arg)
>     }
> }
>
> -static void tcg_out_bswap_subr(TCGContext *s, tcg_insn_unit *sub)
> +static void tcg_out_bswap_subr(TCGContext *s, const tcg_insn_unit *sub)
> {
>     bool ok = tcg_out_opc_jmp(s, OPC_JAL, sub);
>     tcg_debug_assert(ok);
> @@ -925,7 +933,7 @@ static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1,
>
>     tcg_out_opc_br(s, b_opc, arg1, arg2);
>     if (l->has_value) {
> -        reloc_pc16(s->code_ptr - 1, l->u.value_ptr);
> +        reloc_pc16(s, s->code_ptr - 1, l->u.value_ptr);
>     } else {
>         tcg_out_reloc(s, s->code_ptr - 1, R_MIPS_PC16, l, 0);
>     }
> @@ -1079,7 +1087,7 @@ static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret,
>     }
> }
>
> -static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
> +static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail)
> {
>     /* Note that the ABI requires the called function's address to be
>        loaded into T9, even if a direct branch is in range.  */
> @@ -1097,7 +1105,7 @@ static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
>     }
> }
>
> -static void tcg_out_call(TCGContext *s, tcg_insn_unit *arg)
> +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg)
> {
>     tcg_out_call_int(s, arg, false);
>     tcg_out_nop(s);
> @@ -1289,7 +1297,8 @@ static void add_qemu_ldst_label(TCGContext *s, int is_ld, TCGMemOpIdx oi,
>                                 TCGType ext,
>                                 TCGReg datalo, TCGReg datahi,
>                                 TCGReg addrlo, TCGReg addrhi,
> -                                void *raddr, tcg_insn_unit *label_ptr[2])
> +                                const tcg_insn_unit *raddr,
> +                                tcg_insn_unit *label_ptr[2])
> {
>     TCGLabelQemuLdst *label = new_ldst_label(s);
>
> @@ -1315,9 +1324,9 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
>     int i;
>
>     /* resolve label address */
> -    reloc_pc16(l->label_ptr[0], s->code_ptr);
> +    reloc_pc16(s, l->label_ptr[0], s->code_ptr);
>     if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) {
> -        reloc_pc16(l->label_ptr[1], s->code_ptr);
> +        reloc_pc16(s, l->label_ptr[1], s->code_ptr);
>     }
>
>     i = 1;
> @@ -1345,7 +1354,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
>     }
>
>     tcg_out_opc_br(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO);
> -    reloc_pc16(s->code_ptr - 1, l->raddr);
> +    reloc_pc16(s, s->code_ptr - 1, l->raddr);
>
>     /* delay slot */
>     if (TCG_TARGET_REG_BITS == 64 && l->type == TCG_TYPE_I32) {
> @@ -1365,9 +1374,9 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
>     int i;
>
>     /* resolve label address */
> -    reloc_pc16(l->label_ptr[0], s->code_ptr);
> +    reloc_pc16(s, l->label_ptr[0], s->code_ptr);
>     if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) {
> -        reloc_pc16(l->label_ptr[1], s->code_ptr);
> +        reloc_pc16(s, l->label_ptr[1], s->code_ptr);
>     }
>
>     i = 1;
> @@ -2430,7 +2439,7 @@ static void tcg_target_detect_isa(void)
>     sigaction(SIGILL, &sa_old, NULL);
> }
>
> -static tcg_insn_unit *align_code_ptr(TCGContext *s)
> +static const tcg_insn_unit *align_code_ptr(TCGContext *s)
> {
>     uintptr_t p = (uintptr_t)s->code_ptr;
>     if (p & 15) {
> @@ -2657,9 +2666,12 @@ static void tcg_target_init(TCGContext *s)
> }
>
> void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
> -                              uintptr_t addr)
> +                              uintptr_t addr, uintptr_t wr_addr)
> {
> -    qatomic_set((uint32_t *)jmp_addr, deposit32(OPC_J, 0, 26, addr >> 2));
> +    qatomic_set((uint32_t *)wr_addr, deposit32(OPC_J, 0, 26, addr >> 2));
> +#if defined(CONFIG_IOS_JIT)
> +    flush_dcache_range(wr_addr, wr_addr + 4);
> +#endif
>     flush_icache_range(jmp_addr, jmp_addr + 4);
> }
>
> diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
> index c6b091d849..80dcba5358 100644
> --- a/tcg/mips/tcg-target.h
> +++ b/tcg/mips/tcg-target.h
> @@ -212,7 +212,13 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
>     cacheflush ((void *)start, stop-start, ICACHE);
> }
>
> -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
> +void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
> +#if defined(CONFIG_IOS_JIT)
> +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> +{
> +#error "Unimplemented dcache flush function"
> +}
> +#endif
>
> #ifdef CONFIG_SOFTMMU
> #define TCG_TARGET_NEED_LDST_LABELS
> diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc
> index 18ee989f95..f5a44e9852 100644
> --- a/tcg/ppc/tcg-target.c.inc
> +++ b/tcg/ppc/tcg-target.c.inc
> @@ -62,7 +62,7 @@
> #define TCG_CT_CONST_MONE 0x2000
> #define TCG_CT_CONST_WSZ  0x4000
>
> -static tcg_insn_unit *tb_ret_addr;
> +static const tcg_insn_unit *tb_ret_addr;
>
> TCGPowerISA have_isa;
> static bool have_isel;
> @@ -184,35 +184,43 @@ static inline bool in_range_b(tcg_target_long target)
>     return target == sextract64(target, 0, 26);
> }
>
> -static uint32_t reloc_pc24_val(tcg_insn_unit *pc, tcg_insn_unit *target)
> +static uint32_t reloc_pc24_val(const tcg_insn_unit *pc,
> +                               const tcg_insn_unit *target)
> {
>     ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
>     tcg_debug_assert(in_range_b(disp));
>     return disp & 0x3fffffc;
> }
>
> -static bool reloc_pc24(tcg_insn_unit *pc, tcg_insn_unit *target)
> +static bool reloc_pc24(TCGContext *s,
> +                       tcg_insn_unit *pc,
> +                       const tcg_insn_unit *target)
> {
>     ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
>     if (in_range_b(disp)) {
> -        *pc = (*pc & ~0x3fffffc) | (disp & 0x3fffffc);
> +        *TCG_CODE_PTR_RW(s, pc) =
> +            (*TCG_CODE_PTR_RW(s, pc) & ~0x3fffffc) | (disp & 0x3fffffc);
>         return true;
>     }
>     return false;
> }
>
> -static uint16_t reloc_pc14_val(tcg_insn_unit *pc, tcg_insn_unit *target)
> +static uint16_t reloc_pc14_val(const tcg_insn_unit *pc,
> +                               const tcg_insn_unit *target)
> {
>     ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
>     tcg_debug_assert(disp == (int16_t) disp);
>     return disp & 0xfffc;
> }
>
> -static bool reloc_pc14(tcg_insn_unit *pc, tcg_insn_unit *target)
> +static bool reloc_pc14(TCGContext *s,
> +                       tcg_insn_unit *pc,
> +                       const tcg_insn_unit *target)
> {
>     ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
>     if (disp == (int16_t) disp) {
> -        *pc = (*pc & ~0xfffc) | (disp & 0xfffc);
> +        *TCG_CODE_PTR_RW(s, pc) =
> +            (*TCG_CODE_PTR_RW(s, pc) & ~0xfffc) | (disp & 0xfffc);
>         return true;
>     }
>     return false;
> @@ -670,7 +678,7 @@ static const uint32_t tcg_to_isel[] = {
>     [TCG_COND_GTU] = ISEL | BC_(7, CR_GT),
> };
>
> -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
>                         intptr_t value, intptr_t addend)
> {
>     tcg_insn_unit *target;
> @@ -682,9 +690,9 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
>
>     switch (type) {
>     case R_PPC_REL14:
> -        return reloc_pc14(code_ptr, target);
> +        return reloc_pc14(s, code_ptr, target);
>     case R_PPC_REL24:
> -        return reloc_pc24(code_ptr, target);
> +        return reloc_pc24(s, code_ptr, target);
>     case R_PPC_ADDR16:
>         /*
>          * We are (slightly) abusing this relocation type.  In particular,
> @@ -1106,7 +1114,7 @@ static void tcg_out_xori32(TCGContext *s, TCGReg dst, TCGReg src, uint32_t c)
>     tcg_out_zori32(s, dst, src, c, XORI, XORIS);
> }
>
> -static void tcg_out_b(TCGContext *s, int mask, tcg_insn_unit *target)
> +static void tcg_out_b(TCGContext *s, int mask, const tcg_insn_unit *target)
> {
>     ptrdiff_t disp = tcg_pcrel_diff(s, target);
>     if (in_range_b(disp)) {
> @@ -1723,7 +1731,7 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0)
> }
>
> void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
> -                              uintptr_t addr)
> +                              uintptr_t addr, uintptr_t wr_addr)
> {
>     if (TCG_TARGET_REG_BITS == 64) {
>         tcg_insn_unit i1, i2;
> @@ -1752,17 +1760,23 @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
>
>         /* As per the enclosing if, this is ppc64.  Avoid the _Static_assert
>            within qatomic_set that would fail to build a ppc32 host.  */
> -        qatomic_set__nocheck((uint64_t *)jmp_addr, pair);
> +        qatomic_set__nocheck((uint64_t *)wr_addr, pair);
> +#if defined(CONFIG_IOS_JIT)
> +        flush_dcache_range(wr_addr, wr_addr + 8);
> +#endif
>         flush_icache_range(jmp_addr, jmp_addr + 8);
>     } else {
>         intptr_t diff = addr - jmp_addr;
>         tcg_debug_assert(in_range_b(diff));
> -        qatomic_set((uint32_t *)jmp_addr, B | (diff & 0x3fffffc));
> +        qatomic_set((uint32_t *)wr_addr, B | (diff & 0x3fffffc));
> +#if defined(CONFIG_IOS_JIT)
> +        flush_dcache_range(wr_addr, wr_addr + 8);
> +#endif
>         flush_icache_range(jmp_addr, jmp_addr + 4);
>     }
> }
>
> -static void tcg_out_call(TCGContext *s, tcg_insn_unit *target)
> +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target)
> {
> #ifdef _CALL_AIX
>     /* Look through the descriptor.  If the branch is in range, and we
> @@ -1987,7 +2001,8 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, MemOp opc,
> static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
>                                 TCGReg datalo_reg, TCGReg datahi_reg,
>                                 TCGReg addrlo_reg, TCGReg addrhi_reg,
> -                                tcg_insn_unit *raddr, tcg_insn_unit *lptr)
> +                                const tcg_insn_unit *raddr,
> +                                tcg_insn_unit *lptr)
> {
>     TCGLabelQemuLdst *label = new_ldst_label(s);
>
> @@ -2007,7 +2022,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
>     MemOp opc = get_memop(oi);
>     TCGReg hi, lo, arg = TCG_REG_R3;
>
> -    if (!reloc_pc14(lb->label_ptr[0], s->code_ptr)) {
> +    if (!reloc_pc14(s, lb->label_ptr[0], s->code_ptr)) {
>         return false;
>     }
>
> @@ -2055,7 +2070,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
>     MemOp s_bits = opc & MO_SIZE;
>     TCGReg hi, lo, arg = TCG_REG_R3;
>
> -    if (!reloc_pc14(lb->label_ptr[0], s->code_ptr)) {
> +    if (!reloc_pc14(s, lb->label_ptr[0], s->code_ptr)) {
>         return false;
>     }
>
> @@ -2252,11 +2267,11 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
> #endif
> }
>
> -static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
> +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
> {
>     int i;
>     for (i = 0; i < count; ++i) {
> -        p[i] = NOP;
> +        (TCG_CODE_PTR_RW(s, p))[i] = NOP;
>     }
> }
>
> diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
> index be10363956..23d7a337c9 100644
> --- a/tcg/ppc/tcg-target.h
> +++ b/tcg/ppc/tcg-target.h
> @@ -176,7 +176,13 @@ extern bool have_vsx;
> #define TCG_TARGET_HAS_cmpsel_vec       0
>
> void flush_icache_range(uintptr_t start, uintptr_t stop);
> -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
> +void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
> +#if defined(CONFIG_IOS_JIT)
> +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> +{
> +#error "Unimplemented dcache flush function"
> +}
> +#endif
>
> #define TCG_TARGET_DEFAULT_MO (0)
> #define TCG_TARGET_HAS_MEMORY_BSWAP     1
> diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc
> index d536f3ccc1..2d96c83c4b 100644
> --- a/tcg/riscv/tcg-target.c.inc
> +++ b/tcg/riscv/tcg-target.c.inc
> @@ -413,11 +413,11 @@ static void tcg_out_opc_jump(TCGContext *s, RISCVInsn opc,
>     tcg_out32(s, encode_uj(opc, rd, imm));
> }
>
> -static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
> +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
> {
>     int i;
>     for (i = 0; i < count; ++i) {
> -        p[i] = encode_i(OPC_ADDI, TCG_REG_ZERO, TCG_REG_ZERO, 0);
> +        (TCG_CODE_PTR_RW(s, p))[i] = encode_i(OPC_ADDI, TCG_REG_ZERO, TCG_REG_ZERO, 0);
>     }
> }
>
> @@ -425,46 +425,52 @@ static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
>  * Relocations
>  */
>
> -static bool reloc_sbimm12(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
> +static bool reloc_sbimm12(TCGContext *s,
> +                          tcg_insn_unit *code_ptr,
> +                          const tcg_insn_unit *target)
> {
>     intptr_t offset = (intptr_t)target - (intptr_t)code_ptr;
>
>     if (offset == sextreg(offset, 1, 12) << 1) {
> -        code_ptr[0] |= encode_sbimm12(offset);
> +        (TCG_CODE_PTR_RW(s, code_ptr))[0] |= encode_sbimm12(offset);
>         return true;
>     }
>
>     return false;
> }
>
> -static bool reloc_jimm20(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
> +static bool reloc_jimm20(TCGContext *s,
> +                         tcg_insn_unit *code_ptr,
> +                         const tcg_insn_unit *target)
> {
>     intptr_t offset = (intptr_t)target - (intptr_t)code_ptr;
>
>     if (offset == sextreg(offset, 1, 20) << 1) {
> -        code_ptr[0] |= encode_ujimm20(offset);
> +        (TCG_CODE_PTR_RW(s, code_ptr))[0] |= encode_ujimm20(offset);
>         return true;
>     }
>
>     return false;
> }
>
> -static bool reloc_call(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
> +static bool reloc_call(TCGContext *s,
> +                       tcg_insn_unit *code_ptr,
> +                       const tcg_insn_unit *target)
> {
>     intptr_t offset = (intptr_t)target - (intptr_t)code_ptr;
>     int32_t lo = sextreg(offset, 0, 12);
>     int32_t hi = offset - lo;
>
>     if (offset == hi + lo) {
> -        code_ptr[0] |= encode_uimm20(hi);
> -        code_ptr[1] |= encode_imm12(lo);
> +        (TCG_CODE_PTR_RW(s, code_ptr))[0] |= encode_uimm20(hi);
> +        (TCG_CODE_PTR_RW(s, code_ptr))[1] |= encode_imm12(lo);
>         return true;
>     }
>
>     return false;
> }
>
> -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
>                         intptr_t value, intptr_t addend)
> {
>     uint32_t insn = *code_ptr;
> @@ -478,7 +484,7 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
>         diff = value - (uintptr_t)code_ptr;
>         short_jmp = diff == sextreg(diff, 0, 12);
>         if (short_jmp) {
> -            return reloc_sbimm12(code_ptr, (tcg_insn_unit *)value);
> +            return reloc_sbimm12(s, code_ptr, (tcg_insn_unit *)value);
>         } else {
>             /* Invert the condition */
>             insn = insn ^ (1 << 12);
> @@ -499,9 +505,9 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
>         }
>         break;
>     case R_RISCV_JAL:
> -        return reloc_jimm20(code_ptr, (tcg_insn_unit *)value);
> +        return reloc_jimm20(s, code_ptr, (tcg_insn_unit *)value);
>     case R_RISCV_CALL:
> -        return reloc_call(code_ptr, (tcg_insn_unit *)value);
> +        return reloc_call(s, code_ptr, (tcg_insn_unit *)value);
>     default:
>         tcg_abort();
>     }
> @@ -557,7 +563,7 @@ static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd,
>     if (tmp == (int32_t)tmp) {
>         tcg_out_opc_upper(s, OPC_AUIPC, rd, 0);
>         tcg_out_opc_imm(s, OPC_ADDI, rd, rd, 0);
> -        ret = reloc_call(s->code_ptr - 2, (tcg_insn_unit *)val);
> +        ret = reloc_call(s, s->code_ptr - 2, (tcg_insn_unit *)val);
>         tcg_debug_assert(ret == true);
>         return;
>     }
> @@ -854,14 +860,14 @@ static void tcg_out_setcond2(TCGContext *s, TCGCond cond, TCGReg ret,
>     g_assert_not_reached();
> }
>
> -static inline void tcg_out_goto(TCGContext *s, tcg_insn_unit *target)
> +static inline void tcg_out_goto(TCGContext *s, const tcg_insn_unit *target)
> {
>     ptrdiff_t offset = tcg_pcrel_diff(s, target);
>     tcg_debug_assert(offset == sextreg(offset, 1, 20) << 1);
>     tcg_out_opc_jump(s, OPC_JAL, TCG_REG_ZERO, offset);
> }
>
> -static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
> +static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail)
> {
>     TCGReg link = tail ? TCG_REG_ZERO : TCG_REG_RA;
>     ptrdiff_t offset = tcg_pcrel_diff(s, arg);
> @@ -875,7 +881,7 @@ static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
>         /* long jump: -2147483646 to 2147483648 */
>         tcg_out_opc_upper(s, OPC_AUIPC, TCG_REG_TMP0, 0);
>         tcg_out_opc_imm(s, OPC_JALR, link, TCG_REG_TMP0, 0);
> -        ret = reloc_call(s->code_ptr - 2, arg);\
> +        ret = reloc_call(s, s->code_ptr - 2, arg);\
>         tcg_debug_assert(ret == true);
>     } else if (TCG_TARGET_REG_BITS == 64) {
>         /* far jump: 64-bit */
> @@ -888,7 +894,7 @@ static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
>     }
> }
>
> -static void tcg_out_call(TCGContext *s, tcg_insn_unit *arg)
> +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg)
> {
>     tcg_out_call_int(s, arg, false);
> }
> @@ -1022,7 +1028,8 @@ static void add_qemu_ldst_label(TCGContext *s, int is_ld, TCGMemOpIdx oi,
>                                 TCGType ext,
>                                 TCGReg datalo, TCGReg datahi,
>                                 TCGReg addrlo, TCGReg addrhi,
> -                                void *raddr, tcg_insn_unit **label_ptr)
> +                                const tcg_insn_unit *raddr,
> +                                tcg_insn_unit **label_ptr)
> {
>     TCGLabelQemuLdst *label = new_ldst_label(s);
>
> @@ -1052,7 +1059,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
>     }
>
>     /* resolve label address */
> -    if (!patch_reloc(l->label_ptr[0], R_RISCV_BRANCH,
> +    if (!patch_reloc(s, l->label_ptr[0], R_RISCV_BRANCH,
>                      (intptr_t) s->code_ptr, 0)) {
>         return false;
>     }
> @@ -1087,7 +1094,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
>     }
>
>     /* resolve label address */
> -    if (!patch_reloc(l->label_ptr[0], R_RISCV_BRANCH,
> +    if (!patch_reloc(s, l->label_ptr[0], R_RISCV_BRANCH,
>                      (intptr_t) s->code_ptr, 0)) {
>         return false;
>     }
> @@ -1274,7 +1281,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
> #endif
> }
>
> -static tcg_insn_unit *tb_ret_addr;
> +static const tcg_insn_unit *tb_ret_addr;
>
> static void tcg_out_op(TCGContext *s, TCGOpcode opc,
>                        const TCGArg *args, const int *const_args)
> diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h
> index 032439d806..d42b361991 100644
> --- a/tcg/riscv/tcg-target.h
> +++ b/tcg/riscv/tcg-target.h
> @@ -164,8 +164,15 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
>     __builtin___clear_cache((char *)start, (char *)stop);
> }
>
> +#if defined(CONFIG_IOS_JIT)
> +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> +{
> +#error "Unimplemented dcache flush function"
> +}
> +#endif
> +
> /* not defined -- call should be eliminated at compile time */
> -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
> +void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
>
> #define TCG_TARGET_DEFAULT_MO (0)
>
> diff --git a/tcg/s390/tcg-target.c.inc b/tcg/s390/tcg-target.c.inc
> index c5e096449b..49a96ca15f 100644
> --- a/tcg/s390/tcg-target.c.inc
> +++ b/tcg/s390/tcg-target.c.inc
> @@ -363,10 +363,10 @@ static void * const qemu_st_helpers[16] = {
> };
> #endif
>
> -static tcg_insn_unit *tb_ret_addr;
> +static const tcg_insn_unit *tb_ret_addr;
> uint64_t s390_facilities;
>
> -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
>                         intptr_t value, intptr_t addend)
> {
>     intptr_t pcrel2;
> @@ -378,13 +378,13 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
>     switch (type) {
>     case R_390_PC16DBL:
>         if (pcrel2 == (int16_t)pcrel2) {
> -            tcg_patch16(code_ptr, pcrel2);
> +            tcg_patch16(s, code_ptr, pcrel2);
>             return true;
>         }
>         break;
>     case R_390_PC32DBL:
>         if (pcrel2 == (int32_t)pcrel2) {
> -            tcg_patch32(code_ptr, pcrel2);
> +            tcg_patch32(s, code_ptr, pcrel2);
>             return true;
>         }
>         break;
> @@ -392,7 +392,7 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
>         if (value == sextract64(value, 0, 20)) {
>             old = *(uint32_t *)code_ptr & 0xf00000ff;
>             old |= ((value & 0xfff) << 16) | ((value & 0xff000) >> 4);
> -            tcg_patch32(code_ptr, old);
> +            tcg_patch32(s, code_ptr, old);
>             return true;
>         }
>         break;
> @@ -1302,7 +1302,7 @@ static void tgen_extract(TCGContext *s, TCGReg dest, TCGReg src,
>     tcg_out_risbg(s, dest, src, 64 - len, 63, 64 - ofs, 1);
> }
>
> -static void tgen_gotoi(TCGContext *s, int cc, tcg_insn_unit *dest)
> +static void tgen_gotoi(TCGContext *s, int cc, const tcg_insn_unit *dest)
> {
>     ptrdiff_t off = dest - s->code_ptr;
>     if (off == (int16_t)off) {
> @@ -1415,7 +1415,7 @@ static void tgen_brcond(TCGContext *s, TCGType type, TCGCond c,
>     tgen_branch(s, cc, l);
> }
>
> -static void tcg_out_call(TCGContext *s, tcg_insn_unit *dest)
> +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest)
> {
>     ptrdiff_t off = dest - s->code_ptr;
>     if (off == (int32_t)off) {
> @@ -1593,7 +1593,8 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, MemOp opc,
>
> static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
>                                 TCGReg data, TCGReg addr,
> -                                tcg_insn_unit *raddr, tcg_insn_unit *label_ptr)
> +                                const tcg_insn_unit *raddr,
> +                                tcg_insn_unit *label_ptr)
> {
>     TCGLabelQemuLdst *label = new_ldst_label(s);
>
> @@ -1612,7 +1613,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
>     TCGMemOpIdx oi = lb->oi;
>     MemOp opc = get_memop(oi);
>
> -    if (!patch_reloc(lb->label_ptr[0], R_390_PC16DBL,
> +    if (!patch_reloc(s, lb->label_ptr[0], R_390_PC16DBL,
>                      (intptr_t)s->code_ptr, 2)) {
>         return false;
>     }
> @@ -1637,7 +1638,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
>     TCGMemOpIdx oi = lb->oi;
>     MemOp opc = get_memop(oi);
>
> -    if (!patch_reloc(lb->label_ptr[0], R_390_PC16DBL,
> +    if (!patch_reloc(s, lb->label_ptr[0], R_390_PC16DBL,
>                      (intptr_t)s->code_ptr, 2)) {
>         return false;
>     }
> @@ -2575,9 +2576,9 @@ static void tcg_target_qemu_prologue(TCGContext *s)
>     tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_REG_R14);
> }
>
> -static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
> +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
> {
> -    memset(p, 0x07, count * sizeof(tcg_insn_unit));
> +    memset(TCG_CODE_PTR_RW(s, p), 0x07, count * sizeof(tcg_insn_unit));
> }
>
> typedef struct {
> diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h
> index 63c8797bd3..d67632512d 100644
> --- a/tcg/s390/tcg-target.h
> +++ b/tcg/s390/tcg-target.h
> @@ -149,13 +149,24 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
> {
> }
>
> +#if defined(CONFIG_IOS_JIT)
> +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> +{
> +#error "Unimplemented dcache flush function"
> +}
> +#endif
> +
> static inline void tb_target_set_jmp_target(uintptr_t tc_ptr,
> -                                            uintptr_t jmp_addr, uintptr_t addr)
> +                                            uintptr_t jmp_addr, uintptr_t addr,
> +                                            uintptr_t wr_addr)
> {
>     /* patch the branch destination */
>     intptr_t disp = addr - (jmp_addr - 2);
>     qatomic_set((int32_t *)jmp_addr, disp / 2);
>     /* no need to flush icache explicitly */
> +#if defined(CONFIG_IOS_JIT)
> +    flush_dcache_range(wr_addr, wr_addr + 4);
> +#endif
> }
>
> #ifdef CONFIG_SOFTMMU
> diff --git a/tcg/sparc/tcg-target.c.inc b/tcg/sparc/tcg-target.c.inc
> index 6775bd30fc..af97cbdeef 100644
> --- a/tcg/sparc/tcg-target.c.inc
> +++ b/tcg/sparc/tcg-target.c.inc
> @@ -291,14 +291,14 @@ static inline int check_fit_i32(int32_t val, unsigned int bits)
> # define check_fit_ptr  check_fit_i32
> #endif
>
> -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
>                         intptr_t value, intptr_t addend)
> {
>     uint32_t insn = *code_ptr;
>     intptr_t pcrel;
>
>     value += addend;
> -    pcrel = tcg_ptr_byte_diff((tcg_insn_unit *)value, code_ptr);
> +    pcrel = tcg_ptr_byte_diff((const tcg_insn_unit *)value, code_ptr);
>
>     switch (type) {
>     case R_SPARC_WDISP16:
> @@ -840,7 +840,7 @@ static void tcg_out_addsub2_i64(TCGContext *s, TCGReg rl, TCGReg rh,
>     tcg_out_mov(s, TCG_TYPE_I64, rl, tmp);
> }
>
> -static void tcg_out_call_nodelay(TCGContext *s, tcg_insn_unit *dest,
> +static void tcg_out_call_nodelay(TCGContext *s, const tcg_insn_unit *dest,
>                                  bool in_prologue)
> {
>     ptrdiff_t disp = tcg_pcrel_diff(s, dest);
> @@ -855,7 +855,7 @@ static void tcg_out_call_nodelay(TCGContext *s, tcg_insn_unit *dest,
>     }
> }
>
> -static void tcg_out_call(TCGContext *s, tcg_insn_unit *dest)
> +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest)
> {
>     tcg_out_call_nodelay(s, dest, false);
>     tcg_out_nop(s);
> @@ -868,8 +868,8 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0)
> }
>
> #ifdef CONFIG_SOFTMMU
> -static tcg_insn_unit *qemu_ld_trampoline[16];
> -static tcg_insn_unit *qemu_st_trampoline[16];
> +static const tcg_insn_unit *qemu_ld_trampoline[16];
> +static const tcg_insn_unit *qemu_st_trampoline[16];
>
> static void emit_extend(TCGContext *s, TCGReg r, int op)
> {
> @@ -1048,11 +1048,11 @@ static void tcg_target_qemu_prologue(TCGContext *s)
> #endif
> }
>
> -static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
> +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
> {
>     int i;
>     for (i = 0; i < count; ++i) {
> -        p[i] = NOP;
> +        (TCG_CODE_PTR_RW(s, p))[i] = NOP;
>     }
> }
>
> @@ -1163,7 +1163,7 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr,
> #ifdef CONFIG_SOFTMMU
>     unsigned memi = get_mmuidx(oi);
>     TCGReg addrz, param;
> -    tcg_insn_unit *func;
> +    const tcg_insn_unit *func;
>     tcg_insn_unit *label_ptr;
>
>     addrz = tcg_out_tlb_load(s, addr, memi, memop,
> @@ -1226,7 +1226,8 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr,
>         }
>     }
>
> -    *label_ptr |= INSN_OFF19(tcg_ptr_byte_diff(s->code_ptr, label_ptr));
> +    *TCG_CODE_PTR_RW(s, label_ptr) |=
> +        INSN_OFF19(tcg_ptr_byte_diff(s->code_ptr, label_ptr));
> #else
>     if (SPARC64 && TARGET_LONG_BITS == 32) {
>         tcg_out_arithi(s, TCG_REG_T1, addr, 0, SHIFT_SRL);
> @@ -1822,7 +1823,7 @@ void tcg_register_jit(void *buf, size_t buf_size)
> }
>
> void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
> -                              uintptr_t addr)
> +                              uintptr_t addr, uintptr_t wr_addr)
> {
>     intptr_t tb_disp = addr - tc_ptr;
>     intptr_t br_disp = addr - jmp_addr;
> @@ -1834,8 +1835,11 @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
>     tcg_debug_assert(br_disp == (int32_t)br_disp);
>
>     if (!USE_REG_TB) {
> -        qatomic_set((uint32_t *)jmp_addr,
> +        qatomic_set((uint32_t *)wr_addr,
> 		    deposit32(CALL, 0, 30, br_disp >> 2));
> +#if defined(CONFIG_IOS_JIT)
> +        flush_dcache_range(wr_addr, wr_addr + 4);
> +#endif
>         flush_icache_range(jmp_addr, jmp_addr + 4);
>         return;
>     }
> @@ -1859,6 +1863,9 @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
>               | INSN_IMM13((tb_disp & 0x3ff) | -0x400));
>     }
>
> -    qatomic_set((uint64_t *)jmp_addr, deposit64(i2, 32, 32, i1));
> +    qatomic_set((uint64_t *)wr_addr, deposit64(i2, 32, 32, i1));
> +#if defined(CONFIG_IOS_JIT)
> +    flush_dcache_range(wr_addr, wr_addr + 8);
> +#endif
>     flush_icache_range(jmp_addr, jmp_addr + 8);
> }
> diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h
> index 633841ebf2..d102e13692 100644
> --- a/tcg/sparc/tcg-target.h
> +++ b/tcg/sparc/tcg-target.h
> @@ -176,7 +176,13 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
>     }
> }
>
> -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
> +void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
> +#if defined(CONFIG_IOS_JIT)
> +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> +{
> +#error "Unimplemented dcache flush function"
> +}
> +#endif
>
> #define TCG_TARGET_NEED_POOL_LABELS
>
> diff --git a/tcg/tcg-ldst.c.inc b/tcg/tcg-ldst.c.inc
> index 05f9b3ccd6..eaba08700e 100644
> --- a/tcg/tcg-ldst.c.inc
> +++ b/tcg/tcg-ldst.c.inc
> @@ -28,7 +28,7 @@ typedef struct TCGLabelQemuLdst {
>     TCGReg addrhi_reg;      /* reg index for high word of guest virtual addr */
>     TCGReg datalo_reg;      /* reg index for low word to be loaded or stored */
>     TCGReg datahi_reg;      /* reg index for high word to be loaded or stored */
> -    tcg_insn_unit *raddr;   /* gen code addr of the next IR of qemu_ld/st IR */
> +    const tcg_insn_unit *raddr; /* gen code addr of the next IR of qemu_ld/st */
>     tcg_insn_unit *label_ptr[2]; /* label pointers to be updated */
>     QSIMPLEQ_ENTRY(TCGLabelQemuLdst) next;
> } TCGLabelQemuLdst;
> diff --git a/tcg/tcg-pool.c.inc b/tcg/tcg-pool.c.inc
> index 82cbcc89bd..97bb90b7cc 100644
> --- a/tcg/tcg-pool.c.inc
> +++ b/tcg/tcg-pool.c.inc
> @@ -119,7 +119,7 @@ static inline void new_pool_l8(TCGContext *s, int rtype, tcg_insn_unit *label,
> }
>
> /* To be provided by cpu/tcg-target.c.inc.  */
> -static void tcg_out_nop_fill(tcg_insn_unit *p, int count);
> +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count);
>
> static int tcg_out_pool_finalize(TCGContext *s)
> {
> @@ -135,7 +135,7 @@ static int tcg_out_pool_finalize(TCGContext *s)
>        again when allocating the next TranslationBlock structure.  */
>     a = (void *)ROUND_UP((uintptr_t)s->code_ptr,
>                          sizeof(tcg_target_ulong) * p->nlong);
> -    tcg_out_nop_fill(s->code_ptr, (tcg_insn_unit *)a - s->code_ptr);
> +    tcg_out_nop_fill(s, s->code_ptr, (tcg_insn_unit *)a - s->code_ptr);
>     s->data_gen_ptr = a;
>
>     for (; p != NULL; p = p->next) {
> @@ -144,11 +144,12 @@ static int tcg_out_pool_finalize(TCGContext *s)
>             if (unlikely(a > s->code_gen_highwater)) {
>                 return -1;
>             }
> -            memcpy(a, p->data, size);
> +            memcpy(TCG_CODE_PTR_RW(s, a), p->data, size);
>             a += size;
>             l = p;
>         }
> -        if (!patch_reloc(p->label, p->rtype, (intptr_t)a - size, p->addend)) {
> +        if (!patch_reloc(s, p->label, p->rtype,
> +                         (intptr_t)a - size, p->addend)) {
>             return -2;
>         }
>     }
> diff --git a/tcg/tcg.c b/tcg/tcg.c
> index a8c28440e2..ef203a34a6 100644
> --- a/tcg/tcg.c
> +++ b/tcg/tcg.c
> @@ -70,7 +70,7 @@
> static void tcg_target_init(TCGContext *s);
> static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode);
> static void tcg_target_qemu_prologue(TCGContext *s);
> -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
>                         intptr_t value, intptr_t addend);
>
> /* The CIE and FDE header definitions will be common to all hosts.  */
> @@ -148,7 +148,7 @@ static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
>                        intptr_t arg2);
> static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
>                         TCGReg base, intptr_t ofs);
> -static void tcg_out_call(TCGContext *s, tcg_insn_unit *target);
> +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target);
> static int tcg_target_const_match(tcg_target_long val, TCGType type,
>                                   const TCGArgConstraint *arg_ct);
> #ifdef TCG_TARGET_NEED_LDST_LABELS
> @@ -203,13 +203,15 @@ static TCGRegSet tcg_target_call_clobber_regs;
> #if TCG_TARGET_INSN_UNIT_SIZE == 1
> static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
> {
> -    *s->code_ptr++ = v;
> +    *TCG_CODE_PTR_RW(s, s->code_ptr) = v;
> +    s->code_ptr++;
> }
>
> -static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
> +static __attribute__((unused)) inline void tcg_patch8(TCGContext *s,
> +                                                      tcg_insn_unit *p,
>                                                       uint8_t v)
> {
> -    *p = v;
> +    *TCG_CODE_PTR_RW(s, p) = v;
> }
> #endif
>
> @@ -217,21 +219,23 @@ static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
> static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
> {
>     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
> -        *s->code_ptr++ = v;
> +        *TCG_CODE_PTR_RW(s, s->code_ptr) = v;
> +        s->code_ptr++;
>     } else {
>         tcg_insn_unit *p = s->code_ptr;
> -        memcpy(p, &v, sizeof(v));
> +        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
>         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
>     }
> }
>
> -static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
> +static __attribute__((unused)) inline void tcg_patch16(TCGContext *s,
> +                                                       tcg_insn_unit *p,
>                                                        uint16_t v)
> {
>     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
> -        *p = v;
> +        *TCG_CODE_PTR_RW(s, p) = v;
>     } else {
> -        memcpy(p, &v, sizeof(v));
> +        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
>     }
> }
> #endif
> @@ -240,21 +244,23 @@ static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
> static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
> {
>     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
> -        *s->code_ptr++ = v;
> +        *TCG_CODE_PTR_RW(s, s->code_ptr) = v;
> +        s->code_ptr++;
>     } else {
>         tcg_insn_unit *p = s->code_ptr;
> -        memcpy(p, &v, sizeof(v));
> +        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
>         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
>     }
> }
>
> -static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
> +static __attribute__((unused)) inline void tcg_patch32(TCGContext *s,
> +                                                       tcg_insn_unit *p,
>                                                        uint32_t v)
> {
>     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
>         *p = v;
>     } else {
> -        memcpy(p, &v, sizeof(v));
> +        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
>     }
> }
> #endif
> @@ -263,21 +269,23 @@ static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
> static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
> {
>     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
> -        *s->code_ptr++ = v;
> +        *TCG_CODE_PTR_RW(s, s->code_ptr) = v;
> +        s->code_ptr++;
>     } else {
>         tcg_insn_unit *p = s->code_ptr;
> -        memcpy(p, &v, sizeof(v));
> +        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
>         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
>     }
> }
>
> -static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
> +static __attribute__((unused)) inline void tcg_patch64(TCGContext *s,
> +                                                       tcg_insn_unit *p,
>                                                        uint64_t v)
> {
>     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
>         *p = v;
>     } else {
> -        memcpy(p, &v, sizeof(v));
> +        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
>     }
> }
> #endif
> @@ -295,7 +303,7 @@ static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
>     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
> }
>
> -static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr)
> +static void tcg_out_label(TCGContext *s, TCGLabel *l, const tcg_insn_unit *ptr)
> {
>     tcg_debug_assert(!l->has_value);
>     l->has_value = 1;
> @@ -325,7 +333,7 @@ static bool tcg_resolve_relocs(TCGContext *s)
>         uintptr_t value = l->u.value;
>
>         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
> -            if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
> +            if (!patch_reloc(s, r->ptr, r->type, value, r->addend)) {
>                 return false;
>             }
>         }
> @@ -1039,7 +1047,7 @@ TranslationBlock *tcg_tb_alloc(TCGContext *s)
>     }
>     qatomic_set(&s->code_gen_ptr, next);
>     s->data_gen_ptr = NULL;
> -    return tb;
> +    return (TranslationBlock *)TCG_CODE_PTR_RW(s, tb);
> }
>
> void tcg_prologue_init(TCGContext *s)
> @@ -1076,6 +1084,10 @@ void tcg_prologue_init(TCGContext *s)
> #endif
>
>     buf1 = s->code_ptr;
> +#if defined(CONFIG_IOS_JIT)
> +    flush_dcache_range((uintptr_t)TCG_CODE_PTR_RW(s, buf0),
> +                       (uintptr_t)TCG_CODE_PTR_RW(s, buf1));
> +#endif
>     flush_icache_range((uintptr_t)buf0, (uintptr_t)buf1);
>
>     /* Deduct the prologue from the buffer.  */
> @@ -4267,6 +4279,12 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
>         return -2;
>     }
>
> +#if defined(CONFIG_IOS_JIT)
> +    /* flush data cache on mirror */
> +    flush_dcache_range((uintptr_t)TCG_CODE_PTR_RW(s, s->code_buf),
> +                       (uintptr_t)TCG_CODE_PTR_RW(s, s->code_ptr));
> +#endif
> +
>     /* flush instruction cache */
>     flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr);
>
> diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc
> index 231b9b1775..133213be3a 100644
> --- a/tcg/tci/tcg-target.c.inc
> +++ b/tcg/tci/tcg-target.c.inc
> @@ -369,7 +369,7 @@ static const char *const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
> };
> #endif
>
> -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
>                         intptr_t value, intptr_t addend)
> {
>     /* tcg_out_reloc always uses the same type, addend. */
> @@ -377,9 +377,9 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
>     tcg_debug_assert(addend == 0);
>     tcg_debug_assert(value != 0);
>     if (TCG_TARGET_REG_BITS == 32) {
> -        tcg_patch32(code_ptr, value);
> +        tcg_patch32(s, code_ptr, value);
>     } else {
> -        tcg_patch64(code_ptr, value);
> +        tcg_patch64(s, code_ptr, value);
>     }
>     return true;
> }
> @@ -545,7 +545,7 @@ static void tcg_out_movi(TCGContext *s, TCGType type,
>     old_code_ptr[1] = s->code_ptr - old_code_ptr;
> }
>
> -static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *arg)
> +static inline void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg)
> {
>     uint8_t *old_code_ptr = s->code_ptr;
>     tcg_out_op_t(s, INDEX_op_call);
> diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h
> index 8c1c1d265d..2a258ea350 100644
> --- a/tcg/tci/tcg-target.h
> +++ b/tcg/tci/tcg-target.h
> @@ -195,6 +195,12 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
> {
> }
>
> +#if defined(CONFIG_IOS_JIT)
> +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> +{
> +}
> +#endif
> +
> /* We could notice __i386__ or __s390x__ and reduce the barriers depending
>    on the host.  But if you want performance, you use the normal backend.
>    We prefer consistency across hosts on this.  */
> @@ -203,7 +209,8 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
> #define TCG_TARGET_HAS_MEMORY_BSWAP     1
>
> static inline void tb_target_set_jmp_target(uintptr_t tc_ptr,
> -                                            uintptr_t jmp_addr, uintptr_t addr)
> +                                            uintptr_t jmp_addr, uintptr_t addr,
> +                                            uintptr_t wr_addr)
> {
>     /* patch the branch destination */
>     qatomic_set((int32_t *)jmp_addr, addr - (jmp_addr + 4));
>


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 05/10] slirp: update for iOS resolv fix
  2020-10-13 14:38     ` Marc-André Lureau
@ 2020-10-13 14:59       ` Philippe Mathieu-Daudé
  2020-10-14 15:54         ` Joelle van Dyne
  0 siblings, 1 reply; 47+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-10-13 14:59 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: Joelle van Dyne, QEMU

On 10/13/20 4:38 PM, Marc-André Lureau wrote:
> Hi
> 
> On Tue, Oct 13, 2020 at 5:34 PM Philippe Mathieu-Daudé 
> <philmd@redhat.com <mailto:philmd@redhat.com>> wrote:
> 
>     On 10/13/20 1:29 AM, Joelle van Dyne wrote:
>      > From: osy <osy86@users.noreply.github.com
>     <mailto:osy86@users.noreply.github.com>>
>      >
>      > We cannot access /etc/resolv.conf on iOS so libslirp is modified
>     to use
>      > libresolv instead.
>      >
>      > Signed-off-by: Joelle van Dyne <j@getutm.app>
>      > ---
>      >   .gitmodules | 2 +-
>      >   meson.build | 2 ++
>      >   slirp       | 2 +-
>      >   3 files changed, 4 insertions(+), 2 deletions(-)
>      >
>      > diff --git a/.gitmodules b/.gitmodules
>      > index 2bdeeacef8..f23e859210 100644
>      > --- a/.gitmodules
>      > +++ b/.gitmodules
>      > @@ -51,7 +51,7 @@
>      >       url = https://git.qemu.org/git/edk2.git
>     <https://git.qemu.org/git/edk2.git>
>      >   [submodule "slirp"]
>      >       path = slirp
>      > -     url = https://git.qemu.org/git/libslirp.git
>     <https://git.qemu.org/git/libslirp.git>
>      > +     url = https://github.com/utmapp/libslirp.git
>     <https://github.com/utmapp/libslirp.git>
> 
>     NAck.
> 
>     You can not take over the SLiRP project submodule that way.
> 
>     I suggest getting your SLiRP changes merged with mainstream
>     instead, see:
>     https://gitlab.freedesktop.org/slirp/libslirp#contributing
>     <https://gitlab.freedesktop.org/slirp/libslirp#contributing>
> 
> 
> I think he did: 
> https://gitlab.freedesktop.org/slirp/libslirp/-/merge_requests/54 
> <https://gitlab.freedesktop.org/slirp/libslirp/-/merge_requests/54>

I am being wary because the series is not posted as RFC.

But from the cover it looks like a RFC series:

* slirp updated to support DNS resolving using libresolv; a separate
   patch will be submitted to the project. To allow for builds to
   succeed, the .gitmodule is temporarily changed. We're not entirely
   sure how cross-project patches should be handled here.

> 
> Btw, I also noticed the coroutine library submodule proposed in this 
> series is a fork from the original library. Not sure what the upstream 
> status is and whether this is fine.
> 
>      >   [submodule "roms/opensbi"]
>      >       path = roms/opensbi
>      >       url = https://git.qemu.org/git/opensbi.git
>     <https://git.qemu.org/git/opensbi.git>
>      > diff --git a/meson.build b/meson.build
>      > index 32cf08619f..da96e296e0 100644
>      > --- a/meson.build
>      > +++ b/meson.build
>      > @@ -996,6 +996,8 @@ if have_system
>      >       slirp_deps = []
>      >       if targetos == 'windows'
>      >         slirp_deps = cc.find_library('iphlpapi')
>      > +    elif targetos == 'darwin'
>      > +      slirp_deps = cc.find_library('resolv')
>      >       endif
>      >       slirp_conf = configuration_data()
>      >       slirp_conf.set('SLIRP_MAJOR_VERSION',
>     meson.project_version().split('.')[0])
>      > diff --git a/slirp b/slirp
>      > index ce94eba204..452c389d82 160000
>      > --- a/slirp
>      > +++ b/slirp
>      > @@ -1 +1 @@
>      > -Subproject commit ce94eba2042d52a0ba3d9e252ebce86715e94275
>      > +Subproject commit 452c389d8288f81ec9d59d983a047d4e54f3194e
> 
> 
> 
> 
> -- 
> Marc-André Lureau



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 08/10] tcg: mirror mapping RWX pages for iOS optional
  2020-10-13 13:52   ` Paolo Bonzini
@ 2020-10-13 15:10     ` Joelle van Dyne
  0 siblings, 0 replies; 47+ messages in thread
From: Joelle van Dyne @ 2020-10-13 15:10 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Laurent Vivier, Richard Henderson, Joelle van Dyne, qemu-devel

There is a slight performance penalty for using "bulletproof JIT".
Since that is not required if you have the proper entitlements (only
if you're Apple or jailbroken on iOS; available to regular developers
on Apple Silicon macOS), we want the flexibility to disable it.

-j

On Tue, Oct 13, 2020 at 6:52 AM Paolo Bonzini <pbonzini@redhat.com> wrote:
>
> On 13/10/20 01:29, Joelle van Dyne wrote:
> > From: osy <osy86@users.noreply.github.com>
> >
> > This allows jailbroken devices with entitlements to switch the option off.
> >
> > Signed-off-by: Joelle van Dyne <j@getutm.app>
> > ---
>
> What is the advantage in doing so?
>
> Paolo
>


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 09/10] tcg: support JIT on Apple Silicon
  2020-10-13 14:09     ` Peter Maydell
@ 2020-10-13 15:13       ` Joelle van Dyne
  0 siblings, 0 replies; 47+ messages in thread
From: Joelle van Dyne @ 2020-10-13 15:13 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Paolo Bonzini, Richard Henderson, Joelle van Dyne, QEMU Developers

The APIs link correctly but are NOPs on Intel machines. I think full
testing would require Apple Silicon or emulation. Is there precedent
for any other platform/feature that requires hardware specific
features?

-j

On Tue, Oct 13, 2020 at 7:09 AM Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On Tue, 13 Oct 2020 at 14:58, Paolo Bonzini <pbonzini@redhat.com> wrote:
> >
> > On 13/10/20 01:29, Joelle van Dyne wrote:
> > > From: osy <osy86@users.noreply.github.com>
> > >
> > > https://developer.apple.com/documentation/apple_silicon/porting_just-in-time_compilers_to_apple_silicon
> > >
> > > For < iOS 14, reverse engineered functions from libsystem_pthread.dylib is
> > > implemented to handle APRR supported SoCs.
> > >
> > > The following rules apply for JIT write protect:
> > >   * JIT write-protect is enabled before tcg_qemu_tb_exec()
> > >   * JIT write-protect is disabled after tcg_qemu_tb_exec() returns
> > >   * JIT write-protect is disabled inside do_tb_phys_invalidate() but if it
> > >     is called inside of tcg_qemu_tb_exec() then write-protect will be
> > >     enabled again before returning.
> > >   * JIT write-protect is disabled by cpu_loop_exit() for interrupt handling.
> > >   * JIT write-protect is disabled everywhere else.
> > >
> > > Signed-off-by: Joelle van Dyne <j@getutm.app>
> >
> > Can this be emulated somehow on other platforms (such as Linux) so that
> > it does not bitrot?
>
> Some of it is write^execute, which we could test via OpenBSD
> I think if we updated our VM image not to mount the disk
> with that protection disabled. Having "generically support
> w^x" be separate from "iOS specifics" might be useful.
>
> The apple.com webpage linked above suggests also that we could
> test some at least of these APIs on our OSX builds if we
> enable the "hardened runtime" on x86 (though that might also
> enable other stuff we don't want to deal with? no idea)
>
> thanks
> -- PMM


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 04/10] meson: option to build as shared library
  2020-10-13 14:46       ` Daniel P. Berrangé
@ 2020-10-13 15:16         ` Joelle van Dyne
  2020-10-13 15:57           ` Daniel P. Berrangé
  2020-10-13 15:23         ` BALATON Zoltan via
  1 sibling, 1 reply; 47+ messages in thread
From: Joelle van Dyne @ 2020-10-13 15:16 UTC (permalink / raw)
  To: Daniel P. Berrangé; +Cc: qemu-devel, Joelle van Dyne

I will start a separate conversation of UTM's license compatibility.

Regarding the patch, would some sort of warning message in configure
(if building as a shared library) regarding the license be wise? Or
would it pollute the output logs?

-j

On Tue, Oct 13, 2020 at 7:46 AM Daniel P. Berrangé <berrange@redhat.com> wrote:
>
> On Tue, Oct 13, 2020 at 04:41:06PM +0200, BALATON Zoltan wrote:
> > On Tue, 13 Oct 2020, Daniel P. Berrangé wrote:
> > > On Mon, Oct 12, 2020 at 04:29:33PM -0700, Joelle van Dyne wrote:
> > > > From: osy <osy86@users.noreply.github.com>
> > > >
> > > > On iOS, we cannot fork() new processes, so the best way to load QEMU into an
> > > > app is through a shared library. We add a new configure option
> > > > `--enable-shared-lib` that will build the bulk of QEMU into a shared lib.
> > > > The usual executables will then link to the library.
> > >
> > > Note that QEMU as a combined work is licensed GPLv2-only, so if an app is
> > > linking to it as a shared library, the application's license has to be
> > > GPLv2 compatible. I fear that shipping as a shared library is an easy way
> > > for apps to get into a license violating situation without realizing.
> >
> > Please don't let that be an obstacle in merging this series. They'll do it
> > anyway as seen here so having it upstream is probably better than having a
> > lot of different/divergent forks.
>
> "They'll violate the license anyway" is not a compelling argument.
>
> > In case of UTM it seems to be licensed under Apache License 2.0:
> >
> > https://github.com/utmapp/UTM/blob/master/LICENSE
> >
> > which FSF says not compatible with GPLv2 but it is with GPLv3:
> >
> > http://www.gnu.org/licenses/license-list.html#apache2
> >
> > Not sure however if that's for using Apache licenced part in GPLv2 code or
> > the other way around like in UTM in which case I think the whole work will
> > effectively become GPLv3 as most parts of QEMU is probably GPLv2+ already or
> > BSD like free that should be possible to combine with only files explicitely
> > GPLv2 in QEMU remaining at that license and UTM parts are Apache 2.0 when
> > separated from QEMU. I have no idea about legal stuff whatsoever but
> > combining two free software components should be legal some way (otherwise
> > it's not possible to combine GPLv2 with GPLv3 either).
>
> You need to distinguish between GPLv2-only and GPLv2-or-later.
>
> GPLv2-or-later is fine as that upgrades to GPLv3 when used in a
> combined work with Apache License or GPLv3 software.
>
> GPLv2-only will, by design, *not* upgrade to newer GPL versions
> when combined - it is simply license incompatible.
>
> QEMU unfortunately has a bunch a GPLv2-only code present that we
> cannot eliminate.
>
> Regards,
> Daniel
> --
> |: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org         -o-            https://fstop138.berrange.com :|
> |: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
>


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 04/10] meson: option to build as shared library
  2020-10-13 14:46       ` Daniel P. Berrangé
  2020-10-13 15:16         ` Joelle van Dyne
@ 2020-10-13 15:23         ` BALATON Zoltan via
  1 sibling, 0 replies; 47+ messages in thread
From: BALATON Zoltan via @ 2020-10-13 15:23 UTC (permalink / raw)
  To: Daniel P. Berrangé; +Cc: Joelle van Dyne, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 2789 bytes --]

On Tue, 13 Oct 2020, Daniel P. Berrangé wrote:
> On Tue, Oct 13, 2020 at 04:41:06PM +0200, BALATON Zoltan wrote:
>> On Tue, 13 Oct 2020, Daniel P. Berrangé wrote:
>>> On Mon, Oct 12, 2020 at 04:29:33PM -0700, Joelle van Dyne wrote:
>>>> From: osy <osy86@users.noreply.github.com>
>>>>
>>>> On iOS, we cannot fork() new processes, so the best way to load QEMU into an
>>>> app is through a shared library. We add a new configure option
>>>> `--enable-shared-lib` that will build the bulk of QEMU into a shared lib.
>>>> The usual executables will then link to the library.
>>>
>>> Note that QEMU as a combined work is licensed GPLv2-only, so if an app is
>>> linking to it as a shared library, the application's license has to be
>>> GPLv2 compatible. I fear that shipping as a shared library is an easy way
>>> for apps to get into a license violating situation without realizing.
>>
>> Please don't let that be an obstacle in merging this series. They'll do it
>> anyway as seen here so having it upstream is probably better than having a
>> lot of different/divergent forks.
>
> "They'll violate the license anyway" is not a compelling argument.

I meant they'll use it in other projects anyway and will maintain a fork 
instead of contributing to upstream so I think keeping this out of QEMU 
master does not help prevent that and would only promotes fragmentation. 
So avoiding possibly breaking license to not accept this series is not a 
compelling argument in my opinion.

Regards,
BALATON Zoltan

>
>> In case of UTM it seems to be licensed under Apache License 2.0:
>>
>> https://github.com/utmapp/UTM/blob/master/LICENSE
>>
>> which FSF says not compatible with GPLv2 but it is with GPLv3:
>>
>> http://www.gnu.org/licenses/license-list.html#apache2
>>
>> Not sure however if that's for using Apache licenced part in GPLv2 code or
>> the other way around like in UTM in which case I think the whole work will
>> effectively become GPLv3 as most parts of QEMU is probably GPLv2+ already or
>> BSD like free that should be possible to combine with only files explicitely
>> GPLv2 in QEMU remaining at that license and UTM parts are Apache 2.0 when
>> separated from QEMU. I have no idea about legal stuff whatsoever but
>> combining two free software components should be legal some way (otherwise
>> it's not possible to combine GPLv2 with GPLv3 either).
>
> You need to distinguish between GPLv2-only and GPLv2-or-later.
>
> GPLv2-or-later is fine as that upgrades to GPLv3 when used in a
> combined work with Apache License or GPLv3 software.
>
> GPLv2-only will, by design, *not* upgrade to newer GPL versions
> when combined - it is simply license incompatible.
>
> QEMU unfortunately has a bunch a GPLv2-only code present that we
> cannot eliminate.
>
> Regards,
> Daniel
>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 06/10] coroutine: add libucontext as external library
  2020-10-13 14:49     ` BALATON Zoltan via
@ 2020-10-13 15:25       ` Joelle van Dyne
  2020-10-13 16:18       ` Daniel P. Berrangé
  1 sibling, 0 replies; 47+ messages in thread
From: Joelle van Dyne @ 2020-10-13 15:25 UTC (permalink / raw)
  To: BALATON Zoltan; +Cc: Kevin Wolf, Joelle van Dyne, Stefan Hajnoczi, qemu-devel

Thanks for providing the link.

I'm not sure what license that is/if it is compatible with GPLv2. Can
someone provide guidance on what to update in QEMU's license? I am not
too familiar with all this license stuff.

Regarding building for iOS, as Balaton said it is possible with an OSX
host. However, it does require some work to set up all the right
environment variables (Apple does not follow standard conventions for
cross compiling). You can see the build script we use for UTM:
https://github.com/utmapp/UTM/blob/master/scripts/build_dependencies.sh

However, a lot of the changes does work on other platforms
(libucontext and bulletproof (mirror mapped) JIT are two major ones).
We used iOS build to guard these features because they are only useful
for iOS, but we can make it a configure option if that's desired?

-j

On Tue, Oct 13, 2020 at 7:49 AM BALATON Zoltan <balaton@eik.bme.hu> wrote:
>
> On Tue, 13 Oct 2020, Stefan Hajnoczi wrote:
> > On Mon, Oct 12, 2020 at 04:29:35PM -0700, Joelle van Dyne wrote:
> >> From: osy <osy86@users.noreply.github.com>
> >>
> >> iOS does not support ucontext natively for aarch64 and the sigaltstack is
> >> also unsupported (even worse, it fails silently, see:
> >> https://openradar.appspot.com/13002712 )
> >>
> >> As a workaround we include a library implementation of ucontext and add it
> >> as a build option.
> >>
> >> Signed-off-by: Joelle van Dyne <j@getutm.app>
> >
> > Hi,
> > Thanks for sending posting this!
> >
> > Please indicate what license libucontext is under, that it is compatible
> > with QEMU's overall GPL v2 license, and update QEMU license
>
> https://github.com/utmapp/libucontext/blob/master/LICENSE
>
> Maybe the submodule repo should be mirrored in qemu.git eventually.
>
> > documentation (LICENSE, etc), if necessary.
> >
> > Please update .gitlab-ci.yml with build tests. Is there a way to test
> > building QEMU for iOS? If not, then it's difficult for the upstream QEMU
> > project to carry iOS-specific features since we cannot test them.
>
> Build testing should be possible on OS X host that I think we already have
> provided it has the right XCode version installed. (Running it is
> difficult due to app deployment requirements of iOS devices.) But I don't
> know much about these, just trying to point at some possible directions to
> solve this.
>
> Regards,
> BALATON Zoltan


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 04/10] meson: option to build as shared library
  2020-10-13 15:16         ` Joelle van Dyne
@ 2020-10-13 15:57           ` Daniel P. Berrangé
  2020-10-13 16:40             ` BALATON Zoltan via
  0 siblings, 1 reply; 47+ messages in thread
From: Daniel P. Berrangé @ 2020-10-13 15:57 UTC (permalink / raw)
  To: Joelle van Dyne; +Cc: qemu-devel

On Tue, Oct 13, 2020 at 08:16:46AM -0700, Joelle van Dyne wrote:
> I will start a separate conversation of UTM's license compatibility.
> 
> Regarding the patch, would some sort of warning message in configure
> (if building as a shared library) regarding the license be wise? Or
> would it pollute the output logs?

I think there's also a more fundamental question of whether this is
a concept we actually want to support at all.

IIUC, this shared library just exposes a "qemu_main" method which
the external app has to jump into. IOW, the "char **argv" parameter
to qemu_main becomes the ELF library ABI.  Declaring this a shared
library interface is a non-negligible commitment for QEMU maintainers,
especially given that there is alot about QMEU's command line parsing
that maintainers do not like and wish to change.

There is a further question about whether we want to commit to an
architectural model where  fork() is not something we can use. A
significant area of development for QEMU right now is around the
modularization of the device model such that QEMU is no longer a
single process, but rather a collection of processes, each proc
responsible for some specific hardware emulation. Thus far all the
device modularization stuff is strictly optional, but we have the
freedom to make it mandatory and use it transparently behind the
scenes. If we declare this shared library model supported in order
to avoid use of fork, then we're restricting our future options
wrt device modularization.

So including the license issue, that's three major questionmarks
around desirability of supporting use of QEMU as a shared library.


Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 06/10] coroutine: add libucontext as external library
  2020-10-13 14:49     ` BALATON Zoltan via
  2020-10-13 15:25       ` Joelle van Dyne
@ 2020-10-13 16:18       ` Daniel P. Berrangé
  1 sibling, 0 replies; 47+ messages in thread
From: Daniel P. Berrangé @ 2020-10-13 16:18 UTC (permalink / raw)
  To: BALATON Zoltan; +Cc: Kevin Wolf, Joelle van Dyne, Stefan Hajnoczi, qemu-devel

On Tue, Oct 13, 2020 at 04:49:26PM +0200, BALATON Zoltan via wrote:
> On Tue, 13 Oct 2020, Stefan Hajnoczi wrote:
> > On Mon, Oct 12, 2020 at 04:29:35PM -0700, Joelle van Dyne wrote:
> > > From: osy <osy86@users.noreply.github.com>
> > > 
> > > iOS does not support ucontext natively for aarch64 and the sigaltstack is
> > > also unsupported (even worse, it fails silently, see:
> > > https://openradar.appspot.com/13002712 )
> > > 
> > > As a workaround we include a library implementation of ucontext and add it
> > > as a build option.
> > > 
> > > Signed-off-by: Joelle van Dyne <j@getutm.app>
> > 
> > Hi,
> > Thanks for sending posting this!
> > 
> > Please indicate what license libucontext is under, that it is compatible
> > with QEMU's overall GPL v2 license, and update QEMU license
> 
> https://github.com/utmapp/libucontext/blob/master/LICENSE

I don't recognise that license text as being an exact match for any
common open source license.

As best I can tell, it is closest to being yet another variant of the
MIT license, of which there are ridiculously many

  https://fedoraproject.org/wiki/Licensing:MIT


Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 04/10] meson: option to build as shared library
  2020-10-13 15:57           ` Daniel P. Berrangé
@ 2020-10-13 16:40             ` BALATON Zoltan via
  2020-10-14 16:09               ` Joelle van Dyne
  0 siblings, 1 reply; 47+ messages in thread
From: BALATON Zoltan via @ 2020-10-13 16:40 UTC (permalink / raw)
  To: Daniel P. Berrangé; +Cc: Joelle van Dyne, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 2728 bytes --]

On Tue, 13 Oct 2020, Daniel P. Berrangé wrote:
> On Tue, Oct 13, 2020 at 08:16:46AM -0700, Joelle van Dyne wrote:
>> I will start a separate conversation of UTM's license compatibility.
>>
>> Regarding the patch, would some sort of warning message in configure
>> (if building as a shared library) regarding the license be wise? Or
>> would it pollute the output logs?
>
> I think there's also a more fundamental question of whether this is
> a concept we actually want to support at all.

Discussing other compelling reasons for doubt is OK, just wanted to avoid 
having this dismissed on possible licensing problems only. I still think 
it would be a good idea to support QEMU on iOS but due to the (mostly 
security related) limitations of that platform some compromises my be 
needed. Please consider it instead of being quick to decide to avoid these 
problems by not taking the patches upstream which is a convenient solution 
from QEMU viewpoint but not helping other projects. (Other platforms may 
come up in the future with similar limitations that iOS has as more 
desktop OSes also move in the same direction to increase security so these 
may need to be handled anyway at one point, iOS is a good test case for 
that.)

> IIUC, this shared library just exposes a "qemu_main" method which
> the external app has to jump into. IOW, the "char **argv" parameter
> to qemu_main becomes the ELF library ABI.  Declaring this a shared
> library interface is a non-negligible commitment for QEMU maintainers,
> especially given that there is alot about QMEU's command line parsing
> that maintainers do not like and wish to change.

Given that libvirt uses the command line instead of a proper API 
currently, this is not worse than that. If there was a better API or there 
will be one in the future, the shared lib API can be changed the same way 
as libvirt will need to be adapted for that but it's not reasonable to 
demand these patches to come up with that API now. So for now this seems 
to be acceptable and does not prevent cleaning it up later together with 
the planned changes you mentioned. Compatibility for the command line will 
have to be maintained until a better API is devised for use by other 
software like libvirt and anyone intending to use it as dll so this does 
not seem like added commitment.

> There is a further question about whether we want to commit to an
> architectural model where  fork() is not something we can use. A

Does Windows support fork()? I think we're already committed to support 
Windows so any solution you'll come up with will have the same problem 
anyway. So I think this does not add additional restriction that we don't 
already have either.

Regards,
BALATON Zoltan

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 05/10] slirp: update for iOS resolv fix
  2020-10-13 14:59       ` Philippe Mathieu-Daudé
@ 2020-10-14 15:54         ` Joelle van Dyne
  0 siblings, 0 replies; 47+ messages in thread
From: Joelle van Dyne @ 2020-10-14 15:54 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé; +Cc: Marc-André Lureau, QEMU

[-- Attachment #1: Type: text/plain, Size: 3890 bytes --]

Sorry, I was not aware of the rules for RFC. I will remove this one from
the v2 patch set. If and when the libslirp changes are in, what are the
procedures for sending the QEMU side changes?

-j

On Tue, Oct 13, 2020 at 7:59 AM Philippe Mathieu-Daudé <philmd@redhat.com>
wrote:

> On 10/13/20 4:38 PM, Marc-André Lureau wrote:
> > Hi
> >
> > On Tue, Oct 13, 2020 at 5:34 PM Philippe Mathieu-Daudé
> > <philmd@redhat.com <mailto:philmd@redhat.com>> wrote:
> >
> >     On 10/13/20 1:29 AM, Joelle van Dyne wrote:
> >      > From: osy <osy86@users.noreply.github.com
> >     <mailto:osy86@users.noreply.github.com>>
> >      >
> >      > We cannot access /etc/resolv.conf on iOS so libslirp is modified
> >     to use
> >      > libresolv instead.
> >      >
> >      > Signed-off-by: Joelle van Dyne <j@getutm.app>
> >      > ---
> >      >   .gitmodules | 2 +-
> >      >   meson.build | 2 ++
> >      >   slirp       | 2 +-
> >      >   3 files changed, 4 insertions(+), 2 deletions(-)
> >      >
> >      > diff --git a/.gitmodules b/.gitmodules
> >      > index 2bdeeacef8..f23e859210 100644
> >      > --- a/.gitmodules
> >      > +++ b/.gitmodules
> >      > @@ -51,7 +51,7 @@
> >      >       url = https://git.qemu.org/git/edk2.git
> >     <https://git.qemu.org/git/edk2.git>
> >      >   [submodule "slirp"]
> >      >       path = slirp
> >      > -     url = https://git.qemu.org/git/libslirp.git
> >     <https://git.qemu.org/git/libslirp.git>
> >      > +     url = https://github.com/utmapp/libslirp.git
> >     <https://github.com/utmapp/libslirp.git>
> >
> >     NAck.
> >
> >     You can not take over the SLiRP project submodule that way.
> >
> >     I suggest getting your SLiRP changes merged with mainstream
> >     instead, see:
> >     https://gitlab.freedesktop.org/slirp/libslirp#contributing
> >     <https://gitlab.freedesktop.org/slirp/libslirp#contributing>
> >
> >
> > I think he did:
> > https://gitlab.freedesktop.org/slirp/libslirp/-/merge_requests/54
> > <https://gitlab.freedesktop.org/slirp/libslirp/-/merge_requests/54>
>
> I am being wary because the series is not posted as RFC.
>
> But from the cover it looks like a RFC series:
>
> * slirp updated to support DNS resolving using libresolv; a separate
>    patch will be submitted to the project. To allow for builds to
>    succeed, the .gitmodule is temporarily changed. We're not entirely
>    sure how cross-project patches should be handled here.
>
> >
> > Btw, I also noticed the coroutine library submodule proposed in this
> > series is a fork from the original library. Not sure what the upstream
> > status is and whether this is fine.
> >
> >      >   [submodule "roms/opensbi"]
> >      >       path = roms/opensbi
> >      >       url = https://git.qemu.org/git/opensbi.git
> >     <https://git.qemu.org/git/opensbi.git>
> >      > diff --git a/meson.build b/meson.build
> >      > index 32cf08619f..da96e296e0 100644
> >      > --- a/meson.build
> >      > +++ b/meson.build
> >      > @@ -996,6 +996,8 @@ if have_system
> >      >       slirp_deps = []
> >      >       if targetos == 'windows'
> >      >         slirp_deps = cc.find_library('iphlpapi')
> >      > +    elif targetos == 'darwin'
> >      > +      slirp_deps = cc.find_library('resolv')
> >      >       endif
> >      >       slirp_conf = configuration_data()
> >      >       slirp_conf.set('SLIRP_MAJOR_VERSION',
> >     meson.project_version().split('.')[0])
> >      > diff --git a/slirp b/slirp
> >      > index ce94eba204..452c389d82 160000
> >      > --- a/slirp
> >      > +++ b/slirp
> >      > @@ -1 +1 @@
> >      > -Subproject commit ce94eba2042d52a0ba3d9e252ebce86715e94275
> >      > +Subproject commit 452c389d8288f81ec9d59d983a047d4e54f3194e
> >
> >
> >
> >
> > --
> > Marc-André Lureau
>
>
>

[-- Attachment #2: Type: text/html, Size: 6568 bytes --]

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 07/10] tcg: implement bulletproof JIT
  2020-10-13 14:58     ` BALATON Zoltan
  (?)
@ 2020-10-14 16:03     ` Joelle van Dyne
  2020-10-14 20:35       ` Richard Henderson
  -1 siblings, 1 reply; 47+ messages in thread
From: Joelle van Dyne @ 2020-10-14 16:03 UTC (permalink / raw)
  To: BALATON Zoltan; +Cc: Philippe Mathieu-Daudé, QEMU

Hi Philippe,

Will work on splitting the patch for v2. Thanks for the tip on git.orderfile

Hi Balaton,

Reply inline.

-j


On Tue, Oct 13, 2020 at 7:58 AM BALATON Zoltan <balaton@eik.bme.hu> wrote:
>
> On Mon, 12 Oct 2020, Joelle van Dyne wrote:
> > From: osy <osy86@users.noreply.github.com>
> >
> > On iOS, we cannot allocate RWX pages without special entitlements. As a
> > workaround, we can a RX region and then mirror map it to a separate RX
>
> Missing a verb here: "we can a RX region"
Good catch.

>
> > region. Then we can write to one region and execute from the other one.
> >
> > To better keep track of pointers to RW/RX memory, we mark any tcg_insn_unit
> > pointers as `const` if they will never be written to. We also define a new
> > macro `TCG_CODE_PTR_RW` that returns a pointer to RW memory. Only the
> > difference between the two regions is stored in the TCG context.
>
> Maybe it's easier to review if constification is split off as separate
> patch before other changes.
Will do.

>
> > To ensure cache coherency, we flush the data cache in the RW mapping and
> > then invalidate the instruction cache in the RX mapping (where applicable).
> > Because data cache flush is OS defined on some architectures, we do not
> > provide implementations for non iOS platforms (ARM/x86).
> >
> > Signed-off-by: Joelle van Dyne <j@getutm.app>
> > ---
> > accel/tcg/cpu-exec.c         |  7 +++-
> > accel/tcg/translate-all.c    | 78 ++++++++++++++++++++++++++++++++++--
> > configure                    |  1 +
> > docs/devel/ios.rst           | 40 ++++++++++++++++++
> > include/exec/exec-all.h      |  8 ++++
> > include/tcg/tcg.h            | 18 +++++++--
> > tcg/aarch64/tcg-target.c.inc | 48 +++++++++++++---------
> > tcg/aarch64/tcg-target.h     | 13 +++++-
> > tcg/arm/tcg-target.c.inc     | 33 ++++++++-------
> > tcg/arm/tcg-target.h         |  9 ++++-
> > tcg/i386/tcg-target.c.inc    | 28 ++++++-------
> > tcg/i386/tcg-target.h        | 24 ++++++++++-
> > tcg/mips/tcg-target.c.inc    | 64 +++++++++++++++++------------
> > tcg/mips/tcg-target.h        |  8 +++-
> > tcg/ppc/tcg-target.c.inc     | 55 ++++++++++++++++---------
> > tcg/ppc/tcg-target.h         |  8 +++-
> > tcg/riscv/tcg-target.c.inc   | 51 +++++++++++++----------
> > tcg/riscv/tcg-target.h       |  9 ++++-
> > tcg/s390/tcg-target.c.inc    | 25 ++++++------
> > tcg/s390/tcg-target.h        | 13 +++++-
> > tcg/sparc/tcg-target.c.inc   | 33 +++++++++------
> > tcg/sparc/tcg-target.h       |  8 +++-
> > tcg/tcg-ldst.c.inc           |  2 +-
> > tcg/tcg-pool.c.inc           |  9 +++--
> > tcg/tcg.c                    | 60 +++++++++++++++++----------
> > tcg/tci/tcg-target.c.inc     |  8 ++--
> > tcg/tci/tcg-target.h         |  9 ++++-
> > 27 files changed, 481 insertions(+), 188 deletions(-)
> > create mode 100644 docs/devel/ios.rst
> >
> > diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
> > index 58aea605d8..821aefdea2 100644
> > --- a/accel/tcg/cpu-exec.c
> > +++ b/accel/tcg/cpu-exec.c
> > @@ -354,7 +354,12 @@ void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr)
> >     if (TCG_TARGET_HAS_direct_jump) {
> >         uintptr_t offset = tb->jmp_target_arg[n];
> >         uintptr_t tc_ptr = (uintptr_t)tb->tc.ptr;
> > -        tb_target_set_jmp_target(tc_ptr, tc_ptr + offset, addr);
> > +#if defined(CONFIG_IOS_JIT)
> > +        uintptr_t wr_addr = tc_ptr + offset + tb->code_rw_mirror_diff;
> > +#else
> > +        uintptr_t wr_addr = tc_ptr + offset;
> > +#endif
> > +        tb_target_set_jmp_target(tc_ptr, tc_ptr + offset, addr, wr_addr);
> >     } else {
> >         tb->jmp_target_arg[n] = addr;
> >     }
> > diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
> > index d76097296d..76d8dc3d7b 100644
> > --- a/accel/tcg/translate-all.c
> > +++ b/accel/tcg/translate-all.c
> > @@ -60,6 +60,22 @@
> > #include "sysemu/cpu-timers.h"
> > #include "sysemu/tcg.h"
> >
> > +#if defined(CONFIG_IOS_JIT)
> > +#include <mach/mach.h>
> > +extern kern_return_t mach_vm_remap(vm_map_t target_task,
> > +                                   mach_vm_address_t *target_address,
> > +                                   mach_vm_size_t size,
> > +                                   mach_vm_offset_t mask,
> > +                                   int flags,
> > +                                   vm_map_t src_task,
> > +                                   mach_vm_address_t src_address,
> > +                                   boolean_t copy,
> > +                                   vm_prot_t *cur_protection,
> > +                                   vm_prot_t *max_protection,
> > +                                   vm_inherit_t inheritance
> > +                                  );
> > +#endif
> > +
> > /* #define DEBUG_TB_INVALIDATE */
> > /* #define DEBUG_TB_FLUSH */
> > /* make various TB consistency checks */
> > @@ -302,10 +318,13 @@ static target_long decode_sleb128(uint8_t **pp)
> >
> > static int encode_search(TranslationBlock *tb, uint8_t *block)
> > {
> > -    uint8_t *highwater = tcg_ctx->code_gen_highwater;
> > -    uint8_t *p = block;
> > +    uint8_t *highwater;
> > +    uint8_t *p;
> >     int i, j, n;
> >
> > +    highwater = (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx,
> > +                                           tcg_ctx->code_gen_highwater);
> > +    p = (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx, block);
>
> Why do you need explicit casts here? Can this be avoided by using
> appropriate type or within the macro (I haven't checked this at all just
> dislike casts as they can hide problems otherwise caught by the compiler).
There's the choice between tcg_insn_unit * and uint8_t *. Since it's
used much more widely in tcg-target.inc.c, it seemed like
tcg_insn_unit * was a better choice.

>
> Regards,
> BALATON Zoltan
>
> >     for (i = 0, n = tb->icount; i < n; ++i) {
> >         target_ulong prev;
> >
> > @@ -329,7 +348,7 @@ static int encode_search(TranslationBlock *tb, uint8_t *block)
> >         }
> >     }
> >
> > -    return p - block;
> > +    return p - (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx, block);
> > }
> >
> > /* The cpu state corresponding to 'searched_pc' is restored.
> > @@ -1067,7 +1086,11 @@ static inline void *alloc_code_gen_buffer(void)
> > #else
> > static inline void *alloc_code_gen_buffer(void)
> > {
> > +#if defined(CONFIG_IOS_JIT)
> > +    int prot = PROT_READ | PROT_EXEC;
> > +#else
> >     int prot = PROT_WRITE | PROT_READ | PROT_EXEC;
> > +#endif
> >     int flags = MAP_PRIVATE | MAP_ANONYMOUS;
> >     size_t size = tcg_ctx->code_gen_buffer_size;
> >     void *buf;
> > @@ -1118,6 +1141,39 @@ static inline void *alloc_code_gen_buffer(void)
> > }
> > #endif /* USE_STATIC_CODE_GEN_BUFFER, WIN32, POSIX */
> >
> > +#if defined(CONFIG_IOS_JIT)
> > +static inline void *alloc_jit_rw_mirror(void *base, size_t size)
> > +{
> > +    kern_return_t ret;
> > +    mach_vm_address_t mirror;
> > +    vm_prot_t cur_prot, max_prot;
> > +
> > +    mirror = 0;
> > +    ret = mach_vm_remap(mach_task_self(),
> > +                        &mirror,
> > +                        size,
> > +                        0,
> > +                        VM_FLAGS_ANYWHERE | VM_FLAGS_RANDOM_ADDR,
> > +                        mach_task_self(),
> > +                        (mach_vm_address_t)base,
> > +                        false,
> > +                        &cur_prot,
> > +                        &max_prot,
> > +                        VM_INHERIT_NONE
> > +                       );
> > +    if (ret != KERN_SUCCESS) {
> > +        return NULL;
> > +    }
> > +
> > +    if (mprotect((void *)mirror, size, PROT_READ | PROT_WRITE) != 0) {
> > +        munmap((void *)mirror, size);
> > +        return NULL;
> > +    }
> > +
> > +    return (void *)mirror;
> > +}
> > +#endif /* CONFIG_IOS_JIT */
> > +
> > static inline void code_gen_alloc(size_t tb_size)
> > {
> >     tcg_ctx->code_gen_buffer_size = size_code_gen_buffer(tb_size);
> > @@ -1126,6 +1182,19 @@ static inline void code_gen_alloc(size_t tb_size)
> >         fprintf(stderr, "Could not allocate dynamic translator buffer\n");
> >         exit(1);
> >     }
> > +#if defined(CONFIG_IOS_JIT)
> > +    void *mirror;
> > +
> > +    /* For iOS JIT we need a mirror mapping for code execution */
> > +    mirror = alloc_jit_rw_mirror(tcg_ctx->code_gen_buffer,
> > +                                 tcg_ctx->code_gen_buffer_size
> > +                                );
> > +    if (mirror == NULL) {
> > +        fprintf(stderr, "Could not remap code buffer mirror\n");
> > +        exit(1);
> > +    }
> > +    tcg_ctx->code_rw_mirror_diff = mirror - tcg_ctx->code_gen_buffer;
> > +#endif /* CONFIG_IOS_JIT */
> > }
> >
> > static bool tb_cmp(const void *ap, const void *bp)
> > @@ -1721,6 +1790,9 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
> >         cpu_loop_exit(cpu);
> >     }
> >
> > +#if defined(CONFIG_IOS_JIT)
> > +    tb->code_rw_mirror_diff = tcg_ctx->code_rw_mirror_diff;
> > +#endif
> >     gen_code_buf = tcg_ctx->code_gen_ptr;
> >     tb->tc.ptr = gen_code_buf;
> >     tb->pc = pc;
> > diff --git a/configure b/configure
> > index 16c66b437c..c5a6584683 100755
> > --- a/configure
> > +++ b/configure
> > @@ -6220,6 +6220,7 @@ fi
> >
> > if test "$ios" = "yes" ; then
> >   echo "CONFIG_IOS=y" >> $config_host_mak
> > +  echo "CONFIG_IOS_JIT=y" >> $config_host_mak
> > fi
> >
> > if test "$solaris" = "yes" ; then
> > diff --git a/docs/devel/ios.rst b/docs/devel/ios.rst
> > new file mode 100644
> > index 0000000000..dba9fdd868
> > --- /dev/null
> > +++ b/docs/devel/ios.rst
> > @@ -0,0 +1,40 @@
> > +===========
> > +iOS Support
> > +===========
> > +
> > +To run qemu on the iOS platform, some modifications were required. Most of the
> > +modifications are conditioned on the ``CONFIG_IOS`` and ``CONFIG_IOS_JIT``
> > +configuration variables.
> > +
> > +Build support
> > +-------------
> > +
> > +For the code to compile, certain changes in the block driver and the slirp
> > +driver had to be made. There is no ``system()`` call, so code requiring it had
> > +to be disabled.
> > +
> > +``ucontext`` support is broken on iOS. The implementation from ``libucontext``
> > +is used instead.
> > +
> > +Because ``fork()`` is not allowed on iOS apps, the option to build qemu and the
> > +utilities as shared libraries is added. Note that because qemu does not perform
> > +resource cleanup in most cases (open files, allocated memory, etc), it is
> > +advisable that the user implements a proxy layer for syscalls so resources can
> > +be kept track by the app that uses qemu as a shared library.
> > +
> > +JIT support
> > +-----------
> > +
> > +On iOS, allocating RWX pages require special entitlements not usually granted to
> > +apps. However, it is possible to use `bulletproof JIT`_ with a development
> > +certificate. This means that we need to allocate one chunk of memory with RX
> > +permissions and then mirror map the same memory with RW permissions. We generate
> > +code to the mirror mapping and execute the original mapping.
> > +
> > +With ``CONFIG_IOS_JIT`` defined, we store inside the TCG context the difference
> > +between the two mappings. Then, we make sure that any writes to JIT memory is
> > +done to the pointer + the difference (in order to get a pointer to the mirror
> > +mapped space). Additionally, we make sure to flush the data cache before we
> > +invalidate the instruction cache so the changes are seen in both mappings.
> > +
> > +.. _bulletproof JIT: https://www.blackhat.com/docs/us-16/materials/us-16-Krstic.pdf
> > diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
> > index 66f9b4cca6..2db155a772 100644
> > --- a/include/exec/exec-all.h
> > +++ b/include/exec/exec-all.h
> > @@ -483,6 +483,14 @@ struct TranslationBlock {
> >     uintptr_t jmp_list_head;
> >     uintptr_t jmp_list_next[2];
> >     uintptr_t jmp_dest[2];
> > +
> > +#if defined(CONFIG_IOS_JIT)
> > +    /*
> > +     * Store difference to writable mirror
> > +     * We need this when patching the jump instructions
> > +     */
> > +    ptrdiff_t code_rw_mirror_diff;
> > +#endif
> > };
> >
> > extern bool parallel_cpus;
> > diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
> > index 8804a8c4a2..40d1a7a85e 100644
> > --- a/include/tcg/tcg.h
> > +++ b/include/tcg/tcg.h
> > @@ -261,7 +261,7 @@ struct TCGLabel {
> >     unsigned refs : 16;
> >     union {
> >         uintptr_t value;
> > -        tcg_insn_unit *value_ptr;
> > +        const tcg_insn_unit *value_ptr;
> >     } u;
> >     QSIMPLEQ_HEAD(, TCGRelocation) relocs;
> >     QSIMPLEQ_ENTRY(TCGLabel) next;
> > @@ -593,7 +593,7 @@ struct TCGContext {
> >     int nb_ops;
> >
> >     /* goto_tb support */
> > -    tcg_insn_unit *code_buf;
> > +    const tcg_insn_unit *code_buf;
> >     uint16_t *tb_jmp_reset_offset; /* tb->jmp_reset_offset */
> >     uintptr_t *tb_jmp_insn_offset; /* tb->jmp_target_arg if direct_jump */
> >     uintptr_t *tb_jmp_target_addr; /* tb->jmp_target_arg if !direct_jump */
> > @@ -627,6 +627,9 @@ struct TCGContext {
> >     size_t code_gen_buffer_size;
> >     void *code_gen_ptr;
> >     void *data_gen_ptr;
> > +#if defined(CONFIG_IOS_JIT)
> > +    ptrdiff_t code_rw_mirror_diff;
> > +#endif
> >
> >     /* Threshold to flush the translated code buffer.  */
> >     void *code_gen_highwater;
> > @@ -677,6 +680,13 @@ struct TCGContext {
> >     target_ulong gen_insn_data[TCG_MAX_INSNS][TARGET_INSN_START_WORDS];
> > };
> >
> > +#if defined(CONFIG_IOS_JIT)
> > +# define TCG_CODE_PTR_RW(s, code_ptr) \
> > +    (tcg_insn_unit *)((uintptr_t)(code_ptr) + (s)->code_rw_mirror_diff)
> > +#else
> > +# define TCG_CODE_PTR_RW(s, code_ptr) (code_ptr)
> > +#endif
> > +
> > extern TCGContext tcg_init_ctx;
> > extern __thread TCGContext *tcg_ctx;
> > extern TCGv_env cpu_env;
> > @@ -1099,7 +1109,7 @@ static inline TCGLabel *arg_label(TCGArg i)
> >  * correct result.
> >  */
> >
> > -static inline ptrdiff_t tcg_ptr_byte_diff(void *a, void *b)
> > +static inline ptrdiff_t tcg_ptr_byte_diff(const void *a, const void *b)
> > {
> >     return a - b;
> > }
> > @@ -1113,7 +1123,7 @@ static inline ptrdiff_t tcg_ptr_byte_diff(void *a, void *b)
> >  * to the destination address.
> >  */
> >
> > -static inline ptrdiff_t tcg_pcrel_diff(TCGContext *s, void *target)
> > +static inline ptrdiff_t tcg_pcrel_diff(TCGContext *s, const void *target)
> > {
> >     return tcg_ptr_byte_diff(target, s->code_ptr);
> > }
> > diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc
> > index 26f71cb599..9cfa2703b3 100644
> > --- a/tcg/aarch64/tcg-target.c.inc
> > +++ b/tcg/aarch64/tcg-target.c.inc
> > @@ -78,38 +78,44 @@ static const int tcg_target_call_oarg_regs[1] = {
> > #define TCG_REG_GUEST_BASE TCG_REG_X28
> > #endif
> >
> > -static inline bool reloc_pc26(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
> > +static inline bool reloc_pc26(TCGContext *s,
> > +                              tcg_insn_unit *code_ptr,
> > +                              const tcg_insn_unit *target)
> > {
> >     ptrdiff_t offset = target - code_ptr;
> >     if (offset == sextract64(offset, 0, 26)) {
> >         /* read instruction, mask away previous PC_REL26 parameter contents,
> >            set the proper offset, then write back the instruction. */
> > -        *code_ptr = deposit32(*code_ptr, 0, 26, offset);
> > +        *TCG_CODE_PTR_RW(s, code_ptr) =
> > +            deposit32(*TCG_CODE_PTR_RW(s, code_ptr), 0, 26, offset);
> >         return true;
> >     }
> >     return false;
> > }
> >
> > -static inline bool reloc_pc19(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
> > +static inline bool reloc_pc19(TCGContext *s,
> > +                              tcg_insn_unit *code_ptr,
> > +                              const tcg_insn_unit *target)
> > {
> >     ptrdiff_t offset = target - code_ptr;
> >     if (offset == sextract64(offset, 0, 19)) {
> > -        *code_ptr = deposit32(*code_ptr, 5, 19, offset);
> > +        *TCG_CODE_PTR_RW(s, code_ptr) =
> > +            deposit32(*TCG_CODE_PTR_RW(s, code_ptr), 5, 19, offset);
> >         return true;
> >     }
> >     return false;
> > }
> >
> > -static inline bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> > +static inline bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
> >                                intptr_t value, intptr_t addend)
> > {
> >     tcg_debug_assert(addend == 0);
> >     switch (type) {
> >     case R_AARCH64_JUMP26:
> >     case R_AARCH64_CALL26:
> > -        return reloc_pc26(code_ptr, (tcg_insn_unit *)value);
> > +        return reloc_pc26(s, code_ptr, (tcg_insn_unit *)value);
> >     case R_AARCH64_CONDBR19:
> > -        return reloc_pc19(code_ptr, (tcg_insn_unit *)value);
> > +        return reloc_pc19(s, code_ptr, (tcg_insn_unit *)value);
> >     default:
> >         g_assert_not_reached();
> >     }
> > @@ -1306,14 +1312,14 @@ static void tcg_out_cmp(TCGContext *s, TCGType ext, TCGReg a,
> >     }
> > }
> >
> > -static inline void tcg_out_goto(TCGContext *s, tcg_insn_unit *target)
> > +static inline void tcg_out_goto(TCGContext *s, const tcg_insn_unit *target)
> > {
> >     ptrdiff_t offset = target - s->code_ptr;
> >     tcg_debug_assert(offset == sextract64(offset, 0, 26));
> >     tcg_out_insn(s, 3206, B, offset);
> > }
> >
> > -static inline void tcg_out_goto_long(TCGContext *s, tcg_insn_unit *target)
> > +static inline void tcg_out_goto_long(TCGContext *s, const tcg_insn_unit *target)
> > {
> >     ptrdiff_t offset = target - s->code_ptr;
> >     if (offset == sextract64(offset, 0, 26)) {
> > @@ -1329,7 +1335,7 @@ static inline void tcg_out_callr(TCGContext *s, TCGReg reg)
> >     tcg_out_insn(s, 3207, BLR, reg);
> > }
> >
> > -static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *target)
> > +static inline void tcg_out_call(TCGContext *s, const tcg_insn_unit *target)
> > {
> >     ptrdiff_t offset = target - s->code_ptr;
> >     if (offset == sextract64(offset, 0, 26)) {
> > @@ -1341,7 +1347,7 @@ static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *target)
> > }
> >
> > void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
> > -                              uintptr_t addr)
> > +                              uintptr_t addr, uintptr_t wr_addr)
> > {
> >     tcg_insn_unit i1, i2;
> >     TCGType rt = TCG_TYPE_I64;
> > @@ -1362,7 +1368,10 @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
> >         i2 = I3401_ADDI | rt << 31 | (addr & 0xfff) << 10 | rd << 5 | rd;
> >     }
> >     pair = (uint64_t)i2 << 32 | i1;
> > -    qatomic_set((uint64_t *)jmp_addr, pair);
> > +    qatomic_set((uint64_t *)wr_addr, pair);
> > +#if defined(CONFIG_IOS_JIT)
> > +    flush_dcache_range(wr_addr, wr_addr + 8);
> > +#endif
> >     flush_icache_range(jmp_addr, jmp_addr + 8);
> > }
> >
> > @@ -1568,7 +1577,7 @@ static void * const qemu_st_helpers[16] = {
> >     [MO_BEQ]  = helper_be_stq_mmu,
> > };
> >
> > -static inline void tcg_out_adr(TCGContext *s, TCGReg rd, void *target)
> > +static inline void tcg_out_adr(TCGContext *s, TCGReg rd, const void *target)
> > {
> >     ptrdiff_t offset = tcg_pcrel_diff(s, target);
> >     tcg_debug_assert(offset == sextract64(offset, 0, 21));
> > @@ -1581,7 +1590,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
> >     MemOp opc = get_memop(oi);
> >     MemOp size = opc & MO_SIZE;
> >
> > -    if (!reloc_pc19(lb->label_ptr[0], s->code_ptr)) {
> > +    if (!reloc_pc19(s, lb->label_ptr[0], s->code_ptr)) {
> >         return false;
> >     }
> >
> > @@ -1606,7 +1615,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
> >     MemOp opc = get_memop(oi);
> >     MemOp size = opc & MO_SIZE;
> >
> > -    if (!reloc_pc19(lb->label_ptr[0], s->code_ptr)) {
> > +    if (!reloc_pc19(s, lb->label_ptr[0], s->code_ptr)) {
> >         return false;
> >     }
> >
> > @@ -1622,7 +1631,8 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
> >
> > static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
> >                                 TCGType ext, TCGReg data_reg, TCGReg addr_reg,
> > -                                tcg_insn_unit *raddr, tcg_insn_unit *label_ptr)
> > +                                const tcg_insn_unit *raddr,
> > +                                tcg_insn_unit *label_ptr)
> > {
> >     TCGLabelQemuLdst *label = new_ldst_label(s);
> >
> > @@ -1849,7 +1859,7 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg,
> > #endif /* CONFIG_SOFTMMU */
> > }
> >
> > -static tcg_insn_unit *tb_ret_addr;
> > +static const tcg_insn_unit *tb_ret_addr;
> >
> > static void tcg_out_op(TCGContext *s, TCGOpcode opc,
> >                        const TCGArg args[TCG_MAX_OP_ARGS],
> > @@ -2916,11 +2926,11 @@ static void tcg_target_qemu_prologue(TCGContext *s)
> >     tcg_out_insn(s, 3207, RET, TCG_REG_LR);
> > }
> >
> > -static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
> > +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
> > {
> >     int i;
> >     for (i = 0; i < count; ++i) {
> > -        p[i] = NOP;
> > +        (TCG_CODE_PTR_RW(s, p))[i] = NOP;
> >     }
> > }
> >
> > diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h
> > index a2b22b4305..78c97460a1 100644
> > --- a/tcg/aarch64/tcg-target.h
> > +++ b/tcg/aarch64/tcg-target.h
> > @@ -150,6 +150,7 @@ typedef enum {
> >
> > #if defined(__APPLE__)
> > void sys_icache_invalidate(void *start, size_t len);
> > +void sys_dcache_flush(void *start, size_t len);
> > #endif
> >
> > static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
> > @@ -163,7 +164,17 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
> > #endif
> > }
> >
> > -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
> > +void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
> > +#if defined(CONFIG_IOS_JIT)
> > +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> > +{
> > +#if defined(__APPLE__)
> > +    sys_dcache_flush((char *)start, stop - start);
> > +#else
> > +#error "Missing function to flush data cache"
> > +#endif
> > +}
> > +#endif
> >
> > #ifdef CONFIG_SOFTMMU
> > #define TCG_TARGET_NEED_LDST_LABELS
> > diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc
> > index 62c37a954b..d27ad851b5 100644
> > --- a/tcg/arm/tcg-target.c.inc
> > +++ b/tcg/arm/tcg-target.c.inc
> > @@ -187,17 +187,22 @@ static const uint8_t tcg_cond_to_arm_cond[] = {
> >     [TCG_COND_GTU] = COND_HI,
> > };
> >
> > -static inline bool reloc_pc24(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
> > +static inline bool reloc_pc24(TCGContext *s,
> > +                              tcg_insn_unit *code_ptr,
> > +                              const tcg_insn_unit *target)
> > {
> >     ptrdiff_t offset = (tcg_ptr_byte_diff(target, code_ptr) - 8) >> 2;
> >     if (offset == sextract32(offset, 0, 24)) {
> > -        *code_ptr = (*code_ptr & ~0xffffff) | (offset & 0xffffff);
> > +        *TCG_CODE_PTR_RW(s, code_ptr) =
> > +            (*TCG_CODE_PTR_RW(s, code_ptr) & ~0xffffff) | (offset & 0xffffff);
> >         return true;
> >     }
> >     return false;
> > }
> >
> > -static inline bool reloc_pc13(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
> > +static inline bool reloc_pc13(TCGContext *s,
> > +                              tcg_insn_unit *code_ptr,
> > +                              const tcg_insn_unit *target)
> > {
> >     ptrdiff_t offset = tcg_ptr_byte_diff(target, code_ptr) - 8;
> >
> > @@ -209,21 +214,21 @@ static inline bool reloc_pc13(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
> >         }
> >         insn = deposit32(insn, 23, 1, u);
> >         insn = deposit32(insn, 0, 12, offset);
> > -        *code_ptr = insn;
> > +        *TCG_CODE_PTR_RW(s, code_ptr) = insn;
> >         return true;
> >     }
> >     return false;
> > }
> >
> > -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> > +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
> >                         intptr_t value, intptr_t addend)
> > {
> >     tcg_debug_assert(addend == 0);
> >
> >     if (type == R_ARM_PC24) {
> > -        return reloc_pc24(code_ptr, (tcg_insn_unit *)value);
> > +        return reloc_pc24(s, code_ptr, (tcg_insn_unit *)value);
> >     } else if (type == R_ARM_PC13) {
> > -        return reloc_pc13(code_ptr, (tcg_insn_unit *)value);
> > +        return reloc_pc13(s, code_ptr, (tcg_insn_unit *)value);
> >     } else {
> >         g_assert_not_reached();
> >     }
> > @@ -1019,7 +1024,7 @@ static inline void tcg_out_st8(TCGContext *s, int cond,
> >  * with the code buffer limited to 16MB we wouldn't need the long case.
> >  * But we also use it for the tail-call to the qemu_ld/st helpers, which does.
> >  */
> > -static void tcg_out_goto(TCGContext *s, int cond, tcg_insn_unit *addr)
> > +static void tcg_out_goto(TCGContext *s, int cond, const tcg_insn_unit *addr)
> > {
> >     intptr_t addri = (intptr_t)addr;
> >     ptrdiff_t disp = tcg_pcrel_diff(s, addr);
> > @@ -1033,7 +1038,7 @@ static void tcg_out_goto(TCGContext *s, int cond, tcg_insn_unit *addr)
> >
> > /* The call case is mostly used for helpers - so it's not unreasonable
> >  * for them to be beyond branch range */
> > -static void tcg_out_call(TCGContext *s, tcg_insn_unit *addr)
> > +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *addr)
> > {
> >     intptr_t addri = (intptr_t)addr;
> >     ptrdiff_t disp = tcg_pcrel_diff(s, addr);
> > @@ -1326,7 +1331,7 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addrlo, TCGReg addrhi,
> >    helper code.  */
> > static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
> >                                 TCGReg datalo, TCGReg datahi, TCGReg addrlo,
> > -                                TCGReg addrhi, tcg_insn_unit *raddr,
> > +                                TCGReg addrhi, const tcg_insn_unit *raddr,
> >                                 tcg_insn_unit *label_ptr)
> > {
> >     TCGLabelQemuLdst *label = new_ldst_label(s);
> > @@ -1348,7 +1353,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
> >     MemOp opc = get_memop(oi);
> >     void *func;
> >
> > -    if (!reloc_pc24(lb->label_ptr[0], s->code_ptr)) {
> > +    if (!reloc_pc24(s, lb->label_ptr[0], s->code_ptr)) {
> >         return false;
> >     }
> >
> > @@ -1411,7 +1416,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
> >     TCGMemOpIdx oi = lb->oi;
> >     MemOp opc = get_memop(oi);
> >
> > -    if (!reloc_pc24(lb->label_ptr[0], s->code_ptr)) {
> > +    if (!reloc_pc24(s, lb->label_ptr[0], s->code_ptr)) {
> >         return false;
> >     }
> >
> > @@ -2255,11 +2260,11 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type,
> >     tcg_out_movi32(s, COND_AL, ret, arg);
> > }
> >
> > -static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
> > +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
> > {
> >     int i;
> >     for (i = 0; i < count; ++i) {
> > -        p[i] = INSN_NOP;
> > +        (TCG_CODE_PTR_RW(s, p))[i] = INSN_NOP;
> >     }
> > }
> >
> > diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
> > index 17e771374d..d8d7e7e239 100644
> > --- a/tcg/arm/tcg-target.h
> > +++ b/tcg/arm/tcg-target.h
> > @@ -139,8 +139,15 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
> >     __builtin___clear_cache((char *) start, (char *) stop);
> > }
> >
> > +#if defined(CONFIG_IOS_JIT)
> > +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> > +{
> > +#error "Unimplemented dcache flush function"
> > +}
> > +#endif
> > +
> > /* not defined -- call should be eliminated at compile time */
> > -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
> > +void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
> >
> > #ifdef CONFIG_SOFTMMU
> > #define TCG_TARGET_NEED_LDST_LABELS
> > diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc
> > index d8797ed398..e9c128d9e7 100644
> > --- a/tcg/i386/tcg-target.c.inc
> > +++ b/tcg/i386/tcg-target.c.inc
> > @@ -165,9 +165,9 @@ static bool have_lzcnt;
> > # define have_lzcnt 0
> > #endif
> >
> > -static tcg_insn_unit *tb_ret_addr;
> > +static const tcg_insn_unit *tb_ret_addr;
> >
> > -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> > +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
> >                         intptr_t value, intptr_t addend)
> > {
> >     value += addend;
> > @@ -179,14 +179,14 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> >         }
> >         /* FALLTHRU */
> >     case R_386_32:
> > -        tcg_patch32(code_ptr, value);
> > +        tcg_patch32(s, code_ptr, value);
> >         break;
> >     case R_386_PC8:
> >         value -= (uintptr_t)code_ptr;
> >         if (value != (int8_t)value) {
> >             return false;
> >         }
> > -        tcg_patch8(code_ptr, value);
> > +        tcg_patch8(s, code_ptr, value);
> >         break;
> >     default:
> >         tcg_abort();
> > @@ -1591,7 +1591,7 @@ static void tcg_out_clz(TCGContext *s, int rexw, TCGReg dest, TCGReg arg1,
> >     }
> > }
> >
> > -static void tcg_out_branch(TCGContext *s, int call, tcg_insn_unit *dest)
> > +static void tcg_out_branch(TCGContext *s, int call, const tcg_insn_unit *dest)
> > {
> >     intptr_t disp = tcg_pcrel_diff(s, dest) - 5;
> >
> > @@ -1610,12 +1610,12 @@ static void tcg_out_branch(TCGContext *s, int call, tcg_insn_unit *dest)
> >     }
> > }
> >
> > -static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *dest)
> > +static inline void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest)
> > {
> >     tcg_out_branch(s, 1, dest);
> > }
> >
> > -static void tcg_out_jmp(TCGContext *s, tcg_insn_unit *dest)
> > +static void tcg_out_jmp(TCGContext *s, const tcg_insn_unit *dest)
> > {
> >     tcg_out_branch(s, 0, dest);
> > }
> > @@ -1774,7 +1774,7 @@ static void add_qemu_ldst_label(TCGContext *s, bool is_ld, bool is_64,
> >                                 TCGMemOpIdx oi,
> >                                 TCGReg datalo, TCGReg datahi,
> >                                 TCGReg addrlo, TCGReg addrhi,
> > -                                tcg_insn_unit *raddr,
> > +                                const tcg_insn_unit *raddr,
> >                                 tcg_insn_unit **label_ptr)
> > {
> >     TCGLabelQemuLdst *label = new_ldst_label(s);
> > @@ -1805,9 +1805,9 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
> >     int rexw = (l->type == TCG_TYPE_I64 ? P_REXW : 0);
> >
> >     /* resolve label address */
> > -    tcg_patch32(label_ptr[0], s->code_ptr - label_ptr[0] - 4);
> > +    tcg_patch32(s, label_ptr[0], s->code_ptr - label_ptr[0] - 4);
> >     if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
> > -        tcg_patch32(label_ptr[1], s->code_ptr - label_ptr[1] - 4);
> > +        tcg_patch32(s, label_ptr[1], s->code_ptr - label_ptr[1] - 4);
> >     }
> >
> >     if (TCG_TARGET_REG_BITS == 32) {
> > @@ -1890,9 +1890,9 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
> >     TCGReg retaddr;
> >
> >     /* resolve label address */
> > -    tcg_patch32(label_ptr[0], s->code_ptr - label_ptr[0] - 4);
> > +    tcg_patch32(s, label_ptr[0], s->code_ptr - label_ptr[0] - 4);
> >     if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
> > -        tcg_patch32(label_ptr[1], s->code_ptr - label_ptr[1] - 4);
> > +        tcg_patch32(s, label_ptr[1], s->code_ptr - label_ptr[1] - 4);
> >     }
> >
> >     if (TCG_TARGET_REG_BITS == 32) {
> > @@ -3842,9 +3842,9 @@ static void tcg_target_qemu_prologue(TCGContext *s)
> >     tcg_out_opc(s, OPC_RET, 0, 0, 0);
> > }
> >
> > -static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
> > +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
> > {
> > -    memset(p, 0x90, count);
> > +    memset(TCG_CODE_PTR_RW(s, p), 0x90, count);
> > }
> >
> > static void tcg_target_init(TCGContext *s)
> > diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
> > index abd4ac7fc0..cdc440ce36 100644
> > --- a/tcg/i386/tcg-target.h
> > +++ b/tcg/i386/tcg-target.h
> > @@ -206,16 +206,36 @@ extern bool have_avx2;
> > #define TCG_TARGET_extract_i64_valid(ofs, len) \
> >     (((ofs) == 8 && (len) == 8) || ((ofs) + (len)) == 32)
> >
> > +#ifdef __APPLE__
> > +void sys_dcache_flush(void *start, size_t len);
> > +#endif
> > +
> > static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
> > {
> > }
> >
> > +#if defined(CONFIG_IOS_JIT)
> > +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> > +{
> > +#if defined(__APPLE__)
> > +    sys_dcache_flush((char *)start, stop - start);
> > +#else
> > +#error "Missing function to flush data cache"
> > +#endif
> > +}
> > +#endif
> > +
> > static inline void tb_target_set_jmp_target(uintptr_t tc_ptr,
> > -                                            uintptr_t jmp_addr, uintptr_t addr)
> > +                                            uintptr_t jmp_addr, uintptr_t addr,
> > +                                            uintptr_t wr_addr)
> > {
> >     /* patch the branch destination */
> > -    qatomic_set((int32_t *)jmp_addr, addr - (jmp_addr + 4));
> > +    qatomic_set((int32_t *)wr_addr, addr - (jmp_addr + 4));
> >     /* no need to flush icache explicitly */
> > +#if defined(CONFIG_IOS_JIT)
> > +    /* we do need to flush mirror dcache */
> > +    flush_dcache_range(wr_addr, wr_addr + 4);
> > +#endif
> > }
> >
> > /* This defines the natural memory order supported by this
> > diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc
> > index 41be574e89..e798527437 100644
> > --- a/tcg/mips/tcg-target.c.inc
> > +++ b/tcg/mips/tcg-target.c.inc
> > @@ -139,12 +139,13 @@ static const TCGReg tcg_target_call_oarg_regs[2] = {
> >     TCG_REG_V1
> > };
> >
> > -static tcg_insn_unit *tb_ret_addr;
> > -static tcg_insn_unit *bswap32_addr;
> > -static tcg_insn_unit *bswap32u_addr;
> > -static tcg_insn_unit *bswap64_addr;
> > +static const tcg_insn_unit *tb_ret_addr;
> > +static const tcg_insn_unit *bswap32_addr;
> > +static const tcg_insn_unit *bswap32u_addr;
> > +static const tcg_insn_unit *bswap64_addr;
> >
> > -static inline uint32_t reloc_pc16_val(tcg_insn_unit *pc, tcg_insn_unit *target)
> > +static inline uint32_t reloc_pc16_val(const tcg_insn_unit *pc,
> > +                                      const tcg_insn_unit *target)
> > {
> >     /* Let the compiler perform the right-shift as part of the arithmetic.  */
> >     ptrdiff_t disp = target - (pc + 1);
> > @@ -152,28 +153,35 @@ static inline uint32_t reloc_pc16_val(tcg_insn_unit *pc, tcg_insn_unit *target)
> >     return disp & 0xffff;
> > }
> >
> > -static inline void reloc_pc16(tcg_insn_unit *pc, tcg_insn_unit *target)
> > +static inline void reloc_pc16(TCGContext *s,
> > +                              tcg_insn_unit *pc,
> > +                              const tcg_insn_unit *target)
> > {
> > -    *pc = deposit32(*pc, 0, 16, reloc_pc16_val(pc, target));
> > +    *TCG_CODE_PTR_RW(s, pc) =
> > +        deposit32(*TCG_CODE_PTR_RW(s, pc), 0, 16, reloc_pc16_val(pc, target));
> > }
> >
> > -static inline uint32_t reloc_26_val(tcg_insn_unit *pc, tcg_insn_unit *target)
> > +static inline uint32_t reloc_26_val(const tcg_insn_unit *pc,
> > +                                    const tcg_insn_unit *target)
> > {
> >     tcg_debug_assert((((uintptr_t)pc ^ (uintptr_t)target) & 0xf0000000) == 0);
> >     return ((uintptr_t)target >> 2) & 0x3ffffff;
> > }
> >
> > -static inline void reloc_26(tcg_insn_unit *pc, tcg_insn_unit *target)
> > +static inline void reloc_26(TCGContext *s,
> > +                            tcg_insn_unit *pc,
> > +                            const tcg_insn_unit *target)
> > {
> > -    *pc = deposit32(*pc, 0, 26, reloc_26_val(pc, target));
> > +    *TCG_CODE_PTR_RW(s, pc) =
> > +        deposit32(*TCG_CODE_PTR_RW(s, pc), 0, 26, reloc_26_val(pc, target));
> > }
> >
> > -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> > +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
> >                         intptr_t value, intptr_t addend)
> > {
> >     tcg_debug_assert(type == R_MIPS_PC16);
> >     tcg_debug_assert(addend == 0);
> > -    reloc_pc16(code_ptr, (tcg_insn_unit *)value);
> > +    reloc_pc16(s, code_ptr, (tcg_insn_unit *)value);
> >     return true;
> > }
> >
> > @@ -516,7 +524,7 @@ static void tcg_out_opc_sa64(TCGContext *s, MIPSInsn opc1, MIPSInsn opc2,
> >  * Type jump.
> >  * Returns true if the branch was in range and the insn was emitted.
> >  */
> > -static bool tcg_out_opc_jmp(TCGContext *s, MIPSInsn opc, void *target)
> > +static bool tcg_out_opc_jmp(TCGContext *s, MIPSInsn opc, const void *target)
> > {
> >     uintptr_t dest = (uintptr_t)target;
> >     uintptr_t from = (uintptr_t)s->code_ptr + 4;
> > @@ -631,7 +639,7 @@ static inline void tcg_out_bswap16s(TCGContext *s, TCGReg ret, TCGReg arg)
> >     }
> > }
> >
> > -static void tcg_out_bswap_subr(TCGContext *s, tcg_insn_unit *sub)
> > +static void tcg_out_bswap_subr(TCGContext *s, const tcg_insn_unit *sub)
> > {
> >     bool ok = tcg_out_opc_jmp(s, OPC_JAL, sub);
> >     tcg_debug_assert(ok);
> > @@ -925,7 +933,7 @@ static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1,
> >
> >     tcg_out_opc_br(s, b_opc, arg1, arg2);
> >     if (l->has_value) {
> > -        reloc_pc16(s->code_ptr - 1, l->u.value_ptr);
> > +        reloc_pc16(s, s->code_ptr - 1, l->u.value_ptr);
> >     } else {
> >         tcg_out_reloc(s, s->code_ptr - 1, R_MIPS_PC16, l, 0);
> >     }
> > @@ -1079,7 +1087,7 @@ static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret,
> >     }
> > }
> >
> > -static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
> > +static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail)
> > {
> >     /* Note that the ABI requires the called function's address to be
> >        loaded into T9, even if a direct branch is in range.  */
> > @@ -1097,7 +1105,7 @@ static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
> >     }
> > }
> >
> > -static void tcg_out_call(TCGContext *s, tcg_insn_unit *arg)
> > +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg)
> > {
> >     tcg_out_call_int(s, arg, false);
> >     tcg_out_nop(s);
> > @@ -1289,7 +1297,8 @@ static void add_qemu_ldst_label(TCGContext *s, int is_ld, TCGMemOpIdx oi,
> >                                 TCGType ext,
> >                                 TCGReg datalo, TCGReg datahi,
> >                                 TCGReg addrlo, TCGReg addrhi,
> > -                                void *raddr, tcg_insn_unit *label_ptr[2])
> > +                                const tcg_insn_unit *raddr,
> > +                                tcg_insn_unit *label_ptr[2])
> > {
> >     TCGLabelQemuLdst *label = new_ldst_label(s);
> >
> > @@ -1315,9 +1324,9 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
> >     int i;
> >
> >     /* resolve label address */
> > -    reloc_pc16(l->label_ptr[0], s->code_ptr);
> > +    reloc_pc16(s, l->label_ptr[0], s->code_ptr);
> >     if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) {
> > -        reloc_pc16(l->label_ptr[1], s->code_ptr);
> > +        reloc_pc16(s, l->label_ptr[1], s->code_ptr);
> >     }
> >
> >     i = 1;
> > @@ -1345,7 +1354,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
> >     }
> >
> >     tcg_out_opc_br(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO);
> > -    reloc_pc16(s->code_ptr - 1, l->raddr);
> > +    reloc_pc16(s, s->code_ptr - 1, l->raddr);
> >
> >     /* delay slot */
> >     if (TCG_TARGET_REG_BITS == 64 && l->type == TCG_TYPE_I32) {
> > @@ -1365,9 +1374,9 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
> >     int i;
> >
> >     /* resolve label address */
> > -    reloc_pc16(l->label_ptr[0], s->code_ptr);
> > +    reloc_pc16(s, l->label_ptr[0], s->code_ptr);
> >     if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) {
> > -        reloc_pc16(l->label_ptr[1], s->code_ptr);
> > +        reloc_pc16(s, l->label_ptr[1], s->code_ptr);
> >     }
> >
> >     i = 1;
> > @@ -2430,7 +2439,7 @@ static void tcg_target_detect_isa(void)
> >     sigaction(SIGILL, &sa_old, NULL);
> > }
> >
> > -static tcg_insn_unit *align_code_ptr(TCGContext *s)
> > +static const tcg_insn_unit *align_code_ptr(TCGContext *s)
> > {
> >     uintptr_t p = (uintptr_t)s->code_ptr;
> >     if (p & 15) {
> > @@ -2657,9 +2666,12 @@ static void tcg_target_init(TCGContext *s)
> > }
> >
> > void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
> > -                              uintptr_t addr)
> > +                              uintptr_t addr, uintptr_t wr_addr)
> > {
> > -    qatomic_set((uint32_t *)jmp_addr, deposit32(OPC_J, 0, 26, addr >> 2));
> > +    qatomic_set((uint32_t *)wr_addr, deposit32(OPC_J, 0, 26, addr >> 2));
> > +#if defined(CONFIG_IOS_JIT)
> > +    flush_dcache_range(wr_addr, wr_addr + 4);
> > +#endif
> >     flush_icache_range(jmp_addr, jmp_addr + 4);
> > }
> >
> > diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
> > index c6b091d849..80dcba5358 100644
> > --- a/tcg/mips/tcg-target.h
> > +++ b/tcg/mips/tcg-target.h
> > @@ -212,7 +212,13 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
> >     cacheflush ((void *)start, stop-start, ICACHE);
> > }
> >
> > -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
> > +void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
> > +#if defined(CONFIG_IOS_JIT)
> > +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> > +{
> > +#error "Unimplemented dcache flush function"
> > +}
> > +#endif
> >
> > #ifdef CONFIG_SOFTMMU
> > #define TCG_TARGET_NEED_LDST_LABELS
> > diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc
> > index 18ee989f95..f5a44e9852 100644
> > --- a/tcg/ppc/tcg-target.c.inc
> > +++ b/tcg/ppc/tcg-target.c.inc
> > @@ -62,7 +62,7 @@
> > #define TCG_CT_CONST_MONE 0x2000
> > #define TCG_CT_CONST_WSZ  0x4000
> >
> > -static tcg_insn_unit *tb_ret_addr;
> > +static const tcg_insn_unit *tb_ret_addr;
> >
> > TCGPowerISA have_isa;
> > static bool have_isel;
> > @@ -184,35 +184,43 @@ static inline bool in_range_b(tcg_target_long target)
> >     return target == sextract64(target, 0, 26);
> > }
> >
> > -static uint32_t reloc_pc24_val(tcg_insn_unit *pc, tcg_insn_unit *target)
> > +static uint32_t reloc_pc24_val(const tcg_insn_unit *pc,
> > +                               const tcg_insn_unit *target)
> > {
> >     ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
> >     tcg_debug_assert(in_range_b(disp));
> >     return disp & 0x3fffffc;
> > }
> >
> > -static bool reloc_pc24(tcg_insn_unit *pc, tcg_insn_unit *target)
> > +static bool reloc_pc24(TCGContext *s,
> > +                       tcg_insn_unit *pc,
> > +                       const tcg_insn_unit *target)
> > {
> >     ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
> >     if (in_range_b(disp)) {
> > -        *pc = (*pc & ~0x3fffffc) | (disp & 0x3fffffc);
> > +        *TCG_CODE_PTR_RW(s, pc) =
> > +            (*TCG_CODE_PTR_RW(s, pc) & ~0x3fffffc) | (disp & 0x3fffffc);
> >         return true;
> >     }
> >     return false;
> > }
> >
> > -static uint16_t reloc_pc14_val(tcg_insn_unit *pc, tcg_insn_unit *target)
> > +static uint16_t reloc_pc14_val(const tcg_insn_unit *pc,
> > +                               const tcg_insn_unit *target)
> > {
> >     ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
> >     tcg_debug_assert(disp == (int16_t) disp);
> >     return disp & 0xfffc;
> > }
> >
> > -static bool reloc_pc14(tcg_insn_unit *pc, tcg_insn_unit *target)
> > +static bool reloc_pc14(TCGContext *s,
> > +                       tcg_insn_unit *pc,
> > +                       const tcg_insn_unit *target)
> > {
> >     ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
> >     if (disp == (int16_t) disp) {
> > -        *pc = (*pc & ~0xfffc) | (disp & 0xfffc);
> > +        *TCG_CODE_PTR_RW(s, pc) =
> > +            (*TCG_CODE_PTR_RW(s, pc) & ~0xfffc) | (disp & 0xfffc);
> >         return true;
> >     }
> >     return false;
> > @@ -670,7 +678,7 @@ static const uint32_t tcg_to_isel[] = {
> >     [TCG_COND_GTU] = ISEL | BC_(7, CR_GT),
> > };
> >
> > -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> > +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
> >                         intptr_t value, intptr_t addend)
> > {
> >     tcg_insn_unit *target;
> > @@ -682,9 +690,9 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> >
> >     switch (type) {
> >     case R_PPC_REL14:
> > -        return reloc_pc14(code_ptr, target);
> > +        return reloc_pc14(s, code_ptr, target);
> >     case R_PPC_REL24:
> > -        return reloc_pc24(code_ptr, target);
> > +        return reloc_pc24(s, code_ptr, target);
> >     case R_PPC_ADDR16:
> >         /*
> >          * We are (slightly) abusing this relocation type.  In particular,
> > @@ -1106,7 +1114,7 @@ static void tcg_out_xori32(TCGContext *s, TCGReg dst, TCGReg src, uint32_t c)
> >     tcg_out_zori32(s, dst, src, c, XORI, XORIS);
> > }
> >
> > -static void tcg_out_b(TCGContext *s, int mask, tcg_insn_unit *target)
> > +static void tcg_out_b(TCGContext *s, int mask, const tcg_insn_unit *target)
> > {
> >     ptrdiff_t disp = tcg_pcrel_diff(s, target);
> >     if (in_range_b(disp)) {
> > @@ -1723,7 +1731,7 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0)
> > }
> >
> > void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
> > -                              uintptr_t addr)
> > +                              uintptr_t addr, uintptr_t wr_addr)
> > {
> >     if (TCG_TARGET_REG_BITS == 64) {
> >         tcg_insn_unit i1, i2;
> > @@ -1752,17 +1760,23 @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
> >
> >         /* As per the enclosing if, this is ppc64.  Avoid the _Static_assert
> >            within qatomic_set that would fail to build a ppc32 host.  */
> > -        qatomic_set__nocheck((uint64_t *)jmp_addr, pair);
> > +        qatomic_set__nocheck((uint64_t *)wr_addr, pair);
> > +#if defined(CONFIG_IOS_JIT)
> > +        flush_dcache_range(wr_addr, wr_addr + 8);
> > +#endif
> >         flush_icache_range(jmp_addr, jmp_addr + 8);
> >     } else {
> >         intptr_t diff = addr - jmp_addr;
> >         tcg_debug_assert(in_range_b(diff));
> > -        qatomic_set((uint32_t *)jmp_addr, B | (diff & 0x3fffffc));
> > +        qatomic_set((uint32_t *)wr_addr, B | (diff & 0x3fffffc));
> > +#if defined(CONFIG_IOS_JIT)
> > +        flush_dcache_range(wr_addr, wr_addr + 8);
> > +#endif
> >         flush_icache_range(jmp_addr, jmp_addr + 4);
> >     }
> > }
> >
> > -static void tcg_out_call(TCGContext *s, tcg_insn_unit *target)
> > +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target)
> > {
> > #ifdef _CALL_AIX
> >     /* Look through the descriptor.  If the branch is in range, and we
> > @@ -1987,7 +2001,8 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, MemOp opc,
> > static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
> >                                 TCGReg datalo_reg, TCGReg datahi_reg,
> >                                 TCGReg addrlo_reg, TCGReg addrhi_reg,
> > -                                tcg_insn_unit *raddr, tcg_insn_unit *lptr)
> > +                                const tcg_insn_unit *raddr,
> > +                                tcg_insn_unit *lptr)
> > {
> >     TCGLabelQemuLdst *label = new_ldst_label(s);
> >
> > @@ -2007,7 +2022,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
> >     MemOp opc = get_memop(oi);
> >     TCGReg hi, lo, arg = TCG_REG_R3;
> >
> > -    if (!reloc_pc14(lb->label_ptr[0], s->code_ptr)) {
> > +    if (!reloc_pc14(s, lb->label_ptr[0], s->code_ptr)) {
> >         return false;
> >     }
> >
> > @@ -2055,7 +2070,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
> >     MemOp s_bits = opc & MO_SIZE;
> >     TCGReg hi, lo, arg = TCG_REG_R3;
> >
> > -    if (!reloc_pc14(lb->label_ptr[0], s->code_ptr)) {
> > +    if (!reloc_pc14(s, lb->label_ptr[0], s->code_ptr)) {
> >         return false;
> >     }
> >
> > @@ -2252,11 +2267,11 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
> > #endif
> > }
> >
> > -static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
> > +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
> > {
> >     int i;
> >     for (i = 0; i < count; ++i) {
> > -        p[i] = NOP;
> > +        (TCG_CODE_PTR_RW(s, p))[i] = NOP;
> >     }
> > }
> >
> > diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
> > index be10363956..23d7a337c9 100644
> > --- a/tcg/ppc/tcg-target.h
> > +++ b/tcg/ppc/tcg-target.h
> > @@ -176,7 +176,13 @@ extern bool have_vsx;
> > #define TCG_TARGET_HAS_cmpsel_vec       0
> >
> > void flush_icache_range(uintptr_t start, uintptr_t stop);
> > -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
> > +void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
> > +#if defined(CONFIG_IOS_JIT)
> > +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> > +{
> > +#error "Unimplemented dcache flush function"
> > +}
> > +#endif
> >
> > #define TCG_TARGET_DEFAULT_MO (0)
> > #define TCG_TARGET_HAS_MEMORY_BSWAP     1
> > diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc
> > index d536f3ccc1..2d96c83c4b 100644
> > --- a/tcg/riscv/tcg-target.c.inc
> > +++ b/tcg/riscv/tcg-target.c.inc
> > @@ -413,11 +413,11 @@ static void tcg_out_opc_jump(TCGContext *s, RISCVInsn opc,
> >     tcg_out32(s, encode_uj(opc, rd, imm));
> > }
> >
> > -static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
> > +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
> > {
> >     int i;
> >     for (i = 0; i < count; ++i) {
> > -        p[i] = encode_i(OPC_ADDI, TCG_REG_ZERO, TCG_REG_ZERO, 0);
> > +        (TCG_CODE_PTR_RW(s, p))[i] = encode_i(OPC_ADDI, TCG_REG_ZERO, TCG_REG_ZERO, 0);
> >     }
> > }
> >
> > @@ -425,46 +425,52 @@ static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
> >  * Relocations
> >  */
> >
> > -static bool reloc_sbimm12(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
> > +static bool reloc_sbimm12(TCGContext *s,
> > +                          tcg_insn_unit *code_ptr,
> > +                          const tcg_insn_unit *target)
> > {
> >     intptr_t offset = (intptr_t)target - (intptr_t)code_ptr;
> >
> >     if (offset == sextreg(offset, 1, 12) << 1) {
> > -        code_ptr[0] |= encode_sbimm12(offset);
> > +        (TCG_CODE_PTR_RW(s, code_ptr))[0] |= encode_sbimm12(offset);
> >         return true;
> >     }
> >
> >     return false;
> > }
> >
> > -static bool reloc_jimm20(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
> > +static bool reloc_jimm20(TCGContext *s,
> > +                         tcg_insn_unit *code_ptr,
> > +                         const tcg_insn_unit *target)
> > {
> >     intptr_t offset = (intptr_t)target - (intptr_t)code_ptr;
> >
> >     if (offset == sextreg(offset, 1, 20) << 1) {
> > -        code_ptr[0] |= encode_ujimm20(offset);
> > +        (TCG_CODE_PTR_RW(s, code_ptr))[0] |= encode_ujimm20(offset);
> >         return true;
> >     }
> >
> >     return false;
> > }
> >
> > -static bool reloc_call(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
> > +static bool reloc_call(TCGContext *s,
> > +                       tcg_insn_unit *code_ptr,
> > +                       const tcg_insn_unit *target)
> > {
> >     intptr_t offset = (intptr_t)target - (intptr_t)code_ptr;
> >     int32_t lo = sextreg(offset, 0, 12);
> >     int32_t hi = offset - lo;
> >
> >     if (offset == hi + lo) {
> > -        code_ptr[0] |= encode_uimm20(hi);
> > -        code_ptr[1] |= encode_imm12(lo);
> > +        (TCG_CODE_PTR_RW(s, code_ptr))[0] |= encode_uimm20(hi);
> > +        (TCG_CODE_PTR_RW(s, code_ptr))[1] |= encode_imm12(lo);
> >         return true;
> >     }
> >
> >     return false;
> > }
> >
> > -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> > +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
> >                         intptr_t value, intptr_t addend)
> > {
> >     uint32_t insn = *code_ptr;
> > @@ -478,7 +484,7 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> >         diff = value - (uintptr_t)code_ptr;
> >         short_jmp = diff == sextreg(diff, 0, 12);
> >         if (short_jmp) {
> > -            return reloc_sbimm12(code_ptr, (tcg_insn_unit *)value);
> > +            return reloc_sbimm12(s, code_ptr, (tcg_insn_unit *)value);
> >         } else {
> >             /* Invert the condition */
> >             insn = insn ^ (1 << 12);
> > @@ -499,9 +505,9 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> >         }
> >         break;
> >     case R_RISCV_JAL:
> > -        return reloc_jimm20(code_ptr, (tcg_insn_unit *)value);
> > +        return reloc_jimm20(s, code_ptr, (tcg_insn_unit *)value);
> >     case R_RISCV_CALL:
> > -        return reloc_call(code_ptr, (tcg_insn_unit *)value);
> > +        return reloc_call(s, code_ptr, (tcg_insn_unit *)value);
> >     default:
> >         tcg_abort();
> >     }
> > @@ -557,7 +563,7 @@ static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd,
> >     if (tmp == (int32_t)tmp) {
> >         tcg_out_opc_upper(s, OPC_AUIPC, rd, 0);
> >         tcg_out_opc_imm(s, OPC_ADDI, rd, rd, 0);
> > -        ret = reloc_call(s->code_ptr - 2, (tcg_insn_unit *)val);
> > +        ret = reloc_call(s, s->code_ptr - 2, (tcg_insn_unit *)val);
> >         tcg_debug_assert(ret == true);
> >         return;
> >     }
> > @@ -854,14 +860,14 @@ static void tcg_out_setcond2(TCGContext *s, TCGCond cond, TCGReg ret,
> >     g_assert_not_reached();
> > }
> >
> > -static inline void tcg_out_goto(TCGContext *s, tcg_insn_unit *target)
> > +static inline void tcg_out_goto(TCGContext *s, const tcg_insn_unit *target)
> > {
> >     ptrdiff_t offset = tcg_pcrel_diff(s, target);
> >     tcg_debug_assert(offset == sextreg(offset, 1, 20) << 1);
> >     tcg_out_opc_jump(s, OPC_JAL, TCG_REG_ZERO, offset);
> > }
> >
> > -static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
> > +static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail)
> > {
> >     TCGReg link = tail ? TCG_REG_ZERO : TCG_REG_RA;
> >     ptrdiff_t offset = tcg_pcrel_diff(s, arg);
> > @@ -875,7 +881,7 @@ static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
> >         /* long jump: -2147483646 to 2147483648 */
> >         tcg_out_opc_upper(s, OPC_AUIPC, TCG_REG_TMP0, 0);
> >         tcg_out_opc_imm(s, OPC_JALR, link, TCG_REG_TMP0, 0);
> > -        ret = reloc_call(s->code_ptr - 2, arg);\
> > +        ret = reloc_call(s, s->code_ptr - 2, arg);\
> >         tcg_debug_assert(ret == true);
> >     } else if (TCG_TARGET_REG_BITS == 64) {
> >         /* far jump: 64-bit */
> > @@ -888,7 +894,7 @@ static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
> >     }
> > }
> >
> > -static void tcg_out_call(TCGContext *s, tcg_insn_unit *arg)
> > +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg)
> > {
> >     tcg_out_call_int(s, arg, false);
> > }
> > @@ -1022,7 +1028,8 @@ static void add_qemu_ldst_label(TCGContext *s, int is_ld, TCGMemOpIdx oi,
> >                                 TCGType ext,
> >                                 TCGReg datalo, TCGReg datahi,
> >                                 TCGReg addrlo, TCGReg addrhi,
> > -                                void *raddr, tcg_insn_unit **label_ptr)
> > +                                const tcg_insn_unit *raddr,
> > +                                tcg_insn_unit **label_ptr)
> > {
> >     TCGLabelQemuLdst *label = new_ldst_label(s);
> >
> > @@ -1052,7 +1059,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
> >     }
> >
> >     /* resolve label address */
> > -    if (!patch_reloc(l->label_ptr[0], R_RISCV_BRANCH,
> > +    if (!patch_reloc(s, l->label_ptr[0], R_RISCV_BRANCH,
> >                      (intptr_t) s->code_ptr, 0)) {
> >         return false;
> >     }
> > @@ -1087,7 +1094,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
> >     }
> >
> >     /* resolve label address */
> > -    if (!patch_reloc(l->label_ptr[0], R_RISCV_BRANCH,
> > +    if (!patch_reloc(s, l->label_ptr[0], R_RISCV_BRANCH,
> >                      (intptr_t) s->code_ptr, 0)) {
> >         return false;
> >     }
> > @@ -1274,7 +1281,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
> > #endif
> > }
> >
> > -static tcg_insn_unit *tb_ret_addr;
> > +static const tcg_insn_unit *tb_ret_addr;
> >
> > static void tcg_out_op(TCGContext *s, TCGOpcode opc,
> >                        const TCGArg *args, const int *const_args)
> > diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h
> > index 032439d806..d42b361991 100644
> > --- a/tcg/riscv/tcg-target.h
> > +++ b/tcg/riscv/tcg-target.h
> > @@ -164,8 +164,15 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
> >     __builtin___clear_cache((char *)start, (char *)stop);
> > }
> >
> > +#if defined(CONFIG_IOS_JIT)
> > +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> > +{
> > +#error "Unimplemented dcache flush function"
> > +}
> > +#endif
> > +
> > /* not defined -- call should be eliminated at compile time */
> > -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
> > +void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
> >
> > #define TCG_TARGET_DEFAULT_MO (0)
> >
> > diff --git a/tcg/s390/tcg-target.c.inc b/tcg/s390/tcg-target.c.inc
> > index c5e096449b..49a96ca15f 100644
> > --- a/tcg/s390/tcg-target.c.inc
> > +++ b/tcg/s390/tcg-target.c.inc
> > @@ -363,10 +363,10 @@ static void * const qemu_st_helpers[16] = {
> > };
> > #endif
> >
> > -static tcg_insn_unit *tb_ret_addr;
> > +static const tcg_insn_unit *tb_ret_addr;
> > uint64_t s390_facilities;
> >
> > -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> > +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
> >                         intptr_t value, intptr_t addend)
> > {
> >     intptr_t pcrel2;
> > @@ -378,13 +378,13 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> >     switch (type) {
> >     case R_390_PC16DBL:
> >         if (pcrel2 == (int16_t)pcrel2) {
> > -            tcg_patch16(code_ptr, pcrel2);
> > +            tcg_patch16(s, code_ptr, pcrel2);
> >             return true;
> >         }
> >         break;
> >     case R_390_PC32DBL:
> >         if (pcrel2 == (int32_t)pcrel2) {
> > -            tcg_patch32(code_ptr, pcrel2);
> > +            tcg_patch32(s, code_ptr, pcrel2);
> >             return true;
> >         }
> >         break;
> > @@ -392,7 +392,7 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> >         if (value == sextract64(value, 0, 20)) {
> >             old = *(uint32_t *)code_ptr & 0xf00000ff;
> >             old |= ((value & 0xfff) << 16) | ((value & 0xff000) >> 4);
> > -            tcg_patch32(code_ptr, old);
> > +            tcg_patch32(s, code_ptr, old);
> >             return true;
> >         }
> >         break;
> > @@ -1302,7 +1302,7 @@ static void tgen_extract(TCGContext *s, TCGReg dest, TCGReg src,
> >     tcg_out_risbg(s, dest, src, 64 - len, 63, 64 - ofs, 1);
> > }
> >
> > -static void tgen_gotoi(TCGContext *s, int cc, tcg_insn_unit *dest)
> > +static void tgen_gotoi(TCGContext *s, int cc, const tcg_insn_unit *dest)
> > {
> >     ptrdiff_t off = dest - s->code_ptr;
> >     if (off == (int16_t)off) {
> > @@ -1415,7 +1415,7 @@ static void tgen_brcond(TCGContext *s, TCGType type, TCGCond c,
> >     tgen_branch(s, cc, l);
> > }
> >
> > -static void tcg_out_call(TCGContext *s, tcg_insn_unit *dest)
> > +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest)
> > {
> >     ptrdiff_t off = dest - s->code_ptr;
> >     if (off == (int32_t)off) {
> > @@ -1593,7 +1593,8 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, MemOp opc,
> >
> > static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
> >                                 TCGReg data, TCGReg addr,
> > -                                tcg_insn_unit *raddr, tcg_insn_unit *label_ptr)
> > +                                const tcg_insn_unit *raddr,
> > +                                tcg_insn_unit *label_ptr)
> > {
> >     TCGLabelQemuLdst *label = new_ldst_label(s);
> >
> > @@ -1612,7 +1613,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
> >     TCGMemOpIdx oi = lb->oi;
> >     MemOp opc = get_memop(oi);
> >
> > -    if (!patch_reloc(lb->label_ptr[0], R_390_PC16DBL,
> > +    if (!patch_reloc(s, lb->label_ptr[0], R_390_PC16DBL,
> >                      (intptr_t)s->code_ptr, 2)) {
> >         return false;
> >     }
> > @@ -1637,7 +1638,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
> >     TCGMemOpIdx oi = lb->oi;
> >     MemOp opc = get_memop(oi);
> >
> > -    if (!patch_reloc(lb->label_ptr[0], R_390_PC16DBL,
> > +    if (!patch_reloc(s, lb->label_ptr[0], R_390_PC16DBL,
> >                      (intptr_t)s->code_ptr, 2)) {
> >         return false;
> >     }
> > @@ -2575,9 +2576,9 @@ static void tcg_target_qemu_prologue(TCGContext *s)
> >     tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_REG_R14);
> > }
> >
> > -static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
> > +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
> > {
> > -    memset(p, 0x07, count * sizeof(tcg_insn_unit));
> > +    memset(TCG_CODE_PTR_RW(s, p), 0x07, count * sizeof(tcg_insn_unit));
> > }
> >
> > typedef struct {
> > diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h
> > index 63c8797bd3..d67632512d 100644
> > --- a/tcg/s390/tcg-target.h
> > +++ b/tcg/s390/tcg-target.h
> > @@ -149,13 +149,24 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
> > {
> > }
> >
> > +#if defined(CONFIG_IOS_JIT)
> > +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> > +{
> > +#error "Unimplemented dcache flush function"
> > +}
> > +#endif
> > +
> > static inline void tb_target_set_jmp_target(uintptr_t tc_ptr,
> > -                                            uintptr_t jmp_addr, uintptr_t addr)
> > +                                            uintptr_t jmp_addr, uintptr_t addr,
> > +                                            uintptr_t wr_addr)
> > {
> >     /* patch the branch destination */
> >     intptr_t disp = addr - (jmp_addr - 2);
> >     qatomic_set((int32_t *)jmp_addr, disp / 2);
> >     /* no need to flush icache explicitly */
> > +#if defined(CONFIG_IOS_JIT)
> > +    flush_dcache_range(wr_addr, wr_addr + 4);
> > +#endif
> > }
> >
> > #ifdef CONFIG_SOFTMMU
> > diff --git a/tcg/sparc/tcg-target.c.inc b/tcg/sparc/tcg-target.c.inc
> > index 6775bd30fc..af97cbdeef 100644
> > --- a/tcg/sparc/tcg-target.c.inc
> > +++ b/tcg/sparc/tcg-target.c.inc
> > @@ -291,14 +291,14 @@ static inline int check_fit_i32(int32_t val, unsigned int bits)
> > # define check_fit_ptr  check_fit_i32
> > #endif
> >
> > -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> > +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
> >                         intptr_t value, intptr_t addend)
> > {
> >     uint32_t insn = *code_ptr;
> >     intptr_t pcrel;
> >
> >     value += addend;
> > -    pcrel = tcg_ptr_byte_diff((tcg_insn_unit *)value, code_ptr);
> > +    pcrel = tcg_ptr_byte_diff((const tcg_insn_unit *)value, code_ptr);
> >
> >     switch (type) {
> >     case R_SPARC_WDISP16:
> > @@ -840,7 +840,7 @@ static void tcg_out_addsub2_i64(TCGContext *s, TCGReg rl, TCGReg rh,
> >     tcg_out_mov(s, TCG_TYPE_I64, rl, tmp);
> > }
> >
> > -static void tcg_out_call_nodelay(TCGContext *s, tcg_insn_unit *dest,
> > +static void tcg_out_call_nodelay(TCGContext *s, const tcg_insn_unit *dest,
> >                                  bool in_prologue)
> > {
> >     ptrdiff_t disp = tcg_pcrel_diff(s, dest);
> > @@ -855,7 +855,7 @@ static void tcg_out_call_nodelay(TCGContext *s, tcg_insn_unit *dest,
> >     }
> > }
> >
> > -static void tcg_out_call(TCGContext *s, tcg_insn_unit *dest)
> > +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest)
> > {
> >     tcg_out_call_nodelay(s, dest, false);
> >     tcg_out_nop(s);
> > @@ -868,8 +868,8 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0)
> > }
> >
> > #ifdef CONFIG_SOFTMMU
> > -static tcg_insn_unit *qemu_ld_trampoline[16];
> > -static tcg_insn_unit *qemu_st_trampoline[16];
> > +static const tcg_insn_unit *qemu_ld_trampoline[16];
> > +static const tcg_insn_unit *qemu_st_trampoline[16];
> >
> > static void emit_extend(TCGContext *s, TCGReg r, int op)
> > {
> > @@ -1048,11 +1048,11 @@ static void tcg_target_qemu_prologue(TCGContext *s)
> > #endif
> > }
> >
> > -static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
> > +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count)
> > {
> >     int i;
> >     for (i = 0; i < count; ++i) {
> > -        p[i] = NOP;
> > +        (TCG_CODE_PTR_RW(s, p))[i] = NOP;
> >     }
> > }
> >
> > @@ -1163,7 +1163,7 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr,
> > #ifdef CONFIG_SOFTMMU
> >     unsigned memi = get_mmuidx(oi);
> >     TCGReg addrz, param;
> > -    tcg_insn_unit *func;
> > +    const tcg_insn_unit *func;
> >     tcg_insn_unit *label_ptr;
> >
> >     addrz = tcg_out_tlb_load(s, addr, memi, memop,
> > @@ -1226,7 +1226,8 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr,
> >         }
> >     }
> >
> > -    *label_ptr |= INSN_OFF19(tcg_ptr_byte_diff(s->code_ptr, label_ptr));
> > +    *TCG_CODE_PTR_RW(s, label_ptr) |=
> > +        INSN_OFF19(tcg_ptr_byte_diff(s->code_ptr, label_ptr));
> > #else
> >     if (SPARC64 && TARGET_LONG_BITS == 32) {
> >         tcg_out_arithi(s, TCG_REG_T1, addr, 0, SHIFT_SRL);
> > @@ -1822,7 +1823,7 @@ void tcg_register_jit(void *buf, size_t buf_size)
> > }
> >
> > void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
> > -                              uintptr_t addr)
> > +                              uintptr_t addr, uintptr_t wr_addr)
> > {
> >     intptr_t tb_disp = addr - tc_ptr;
> >     intptr_t br_disp = addr - jmp_addr;
> > @@ -1834,8 +1835,11 @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
> >     tcg_debug_assert(br_disp == (int32_t)br_disp);
> >
> >     if (!USE_REG_TB) {
> > -        qatomic_set((uint32_t *)jmp_addr,
> > +        qatomic_set((uint32_t *)wr_addr,
> >                   deposit32(CALL, 0, 30, br_disp >> 2));
> > +#if defined(CONFIG_IOS_JIT)
> > +        flush_dcache_range(wr_addr, wr_addr + 4);
> > +#endif
> >         flush_icache_range(jmp_addr, jmp_addr + 4);
> >         return;
> >     }
> > @@ -1859,6 +1863,9 @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
> >               | INSN_IMM13((tb_disp & 0x3ff) | -0x400));
> >     }
> >
> > -    qatomic_set((uint64_t *)jmp_addr, deposit64(i2, 32, 32, i1));
> > +    qatomic_set((uint64_t *)wr_addr, deposit64(i2, 32, 32, i1));
> > +#if defined(CONFIG_IOS_JIT)
> > +    flush_dcache_range(wr_addr, wr_addr + 8);
> > +#endif
> >     flush_icache_range(jmp_addr, jmp_addr + 8);
> > }
> > diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h
> > index 633841ebf2..d102e13692 100644
> > --- a/tcg/sparc/tcg-target.h
> > +++ b/tcg/sparc/tcg-target.h
> > @@ -176,7 +176,13 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
> >     }
> > }
> >
> > -void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
> > +void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
> > +#if defined(CONFIG_IOS_JIT)
> > +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> > +{
> > +#error "Unimplemented dcache flush function"
> > +}
> > +#endif
> >
> > #define TCG_TARGET_NEED_POOL_LABELS
> >
> > diff --git a/tcg/tcg-ldst.c.inc b/tcg/tcg-ldst.c.inc
> > index 05f9b3ccd6..eaba08700e 100644
> > --- a/tcg/tcg-ldst.c.inc
> > +++ b/tcg/tcg-ldst.c.inc
> > @@ -28,7 +28,7 @@ typedef struct TCGLabelQemuLdst {
> >     TCGReg addrhi_reg;      /* reg index for high word of guest virtual addr */
> >     TCGReg datalo_reg;      /* reg index for low word to be loaded or stored */
> >     TCGReg datahi_reg;      /* reg index for high word to be loaded or stored */
> > -    tcg_insn_unit *raddr;   /* gen code addr of the next IR of qemu_ld/st IR */
> > +    const tcg_insn_unit *raddr; /* gen code addr of the next IR of qemu_ld/st */
> >     tcg_insn_unit *label_ptr[2]; /* label pointers to be updated */
> >     QSIMPLEQ_ENTRY(TCGLabelQemuLdst) next;
> > } TCGLabelQemuLdst;
> > diff --git a/tcg/tcg-pool.c.inc b/tcg/tcg-pool.c.inc
> > index 82cbcc89bd..97bb90b7cc 100644
> > --- a/tcg/tcg-pool.c.inc
> > +++ b/tcg/tcg-pool.c.inc
> > @@ -119,7 +119,7 @@ static inline void new_pool_l8(TCGContext *s, int rtype, tcg_insn_unit *label,
> > }
> >
> > /* To be provided by cpu/tcg-target.c.inc.  */
> > -static void tcg_out_nop_fill(tcg_insn_unit *p, int count);
> > +static void tcg_out_nop_fill(TCGContext *s, tcg_insn_unit *p, int count);
> >
> > static int tcg_out_pool_finalize(TCGContext *s)
> > {
> > @@ -135,7 +135,7 @@ static int tcg_out_pool_finalize(TCGContext *s)
> >        again when allocating the next TranslationBlock structure.  */
> >     a = (void *)ROUND_UP((uintptr_t)s->code_ptr,
> >                          sizeof(tcg_target_ulong) * p->nlong);
> > -    tcg_out_nop_fill(s->code_ptr, (tcg_insn_unit *)a - s->code_ptr);
> > +    tcg_out_nop_fill(s, s->code_ptr, (tcg_insn_unit *)a - s->code_ptr);
> >     s->data_gen_ptr = a;
> >
> >     for (; p != NULL; p = p->next) {
> > @@ -144,11 +144,12 @@ static int tcg_out_pool_finalize(TCGContext *s)
> >             if (unlikely(a > s->code_gen_highwater)) {
> >                 return -1;
> >             }
> > -            memcpy(a, p->data, size);
> > +            memcpy(TCG_CODE_PTR_RW(s, a), p->data, size);
> >             a += size;
> >             l = p;
> >         }
> > -        if (!patch_reloc(p->label, p->rtype, (intptr_t)a - size, p->addend)) {
> > +        if (!patch_reloc(s, p->label, p->rtype,
> > +                         (intptr_t)a - size, p->addend)) {
> >             return -2;
> >         }
> >     }
> > diff --git a/tcg/tcg.c b/tcg/tcg.c
> > index a8c28440e2..ef203a34a6 100644
> > --- a/tcg/tcg.c
> > +++ b/tcg/tcg.c
> > @@ -70,7 +70,7 @@
> > static void tcg_target_init(TCGContext *s);
> > static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode);
> > static void tcg_target_qemu_prologue(TCGContext *s);
> > -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> > +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
> >                         intptr_t value, intptr_t addend);
> >
> > /* The CIE and FDE header definitions will be common to all hosts.  */
> > @@ -148,7 +148,7 @@ static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
> >                        intptr_t arg2);
> > static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
> >                         TCGReg base, intptr_t ofs);
> > -static void tcg_out_call(TCGContext *s, tcg_insn_unit *target);
> > +static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target);
> > static int tcg_target_const_match(tcg_target_long val, TCGType type,
> >                                   const TCGArgConstraint *arg_ct);
> > #ifdef TCG_TARGET_NEED_LDST_LABELS
> > @@ -203,13 +203,15 @@ static TCGRegSet tcg_target_call_clobber_regs;
> > #if TCG_TARGET_INSN_UNIT_SIZE == 1
> > static __attribute__((unused)) inline void tcg_out8(TCGContext *s, uint8_t v)
> > {
> > -    *s->code_ptr++ = v;
> > +    *TCG_CODE_PTR_RW(s, s->code_ptr) = v;
> > +    s->code_ptr++;
> > }
> >
> > -static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
> > +static __attribute__((unused)) inline void tcg_patch8(TCGContext *s,
> > +                                                      tcg_insn_unit *p,
> >                                                       uint8_t v)
> > {
> > -    *p = v;
> > +    *TCG_CODE_PTR_RW(s, p) = v;
> > }
> > #endif
> >
> > @@ -217,21 +219,23 @@ static __attribute__((unused)) inline void tcg_patch8(tcg_insn_unit *p,
> > static __attribute__((unused)) inline void tcg_out16(TCGContext *s, uint16_t v)
> > {
> >     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
> > -        *s->code_ptr++ = v;
> > +        *TCG_CODE_PTR_RW(s, s->code_ptr) = v;
> > +        s->code_ptr++;
> >     } else {
> >         tcg_insn_unit *p = s->code_ptr;
> > -        memcpy(p, &v, sizeof(v));
> > +        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
> >         s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE);
> >     }
> > }
> >
> > -static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
> > +static __attribute__((unused)) inline void tcg_patch16(TCGContext *s,
> > +                                                       tcg_insn_unit *p,
> >                                                        uint16_t v)
> > {
> >     if (TCG_TARGET_INSN_UNIT_SIZE == 2) {
> > -        *p = v;
> > +        *TCG_CODE_PTR_RW(s, p) = v;
> >     } else {
> > -        memcpy(p, &v, sizeof(v));
> > +        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
> >     }
> > }
> > #endif
> > @@ -240,21 +244,23 @@ static __attribute__((unused)) inline void tcg_patch16(tcg_insn_unit *p,
> > static __attribute__((unused)) inline void tcg_out32(TCGContext *s, uint32_t v)
> > {
> >     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
> > -        *s->code_ptr++ = v;
> > +        *TCG_CODE_PTR_RW(s, s->code_ptr) = v;
> > +        s->code_ptr++;
> >     } else {
> >         tcg_insn_unit *p = s->code_ptr;
> > -        memcpy(p, &v, sizeof(v));
> > +        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
> >         s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE);
> >     }
> > }
> >
> > -static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
> > +static __attribute__((unused)) inline void tcg_patch32(TCGContext *s,
> > +                                                       tcg_insn_unit *p,
> >                                                        uint32_t v)
> > {
> >     if (TCG_TARGET_INSN_UNIT_SIZE == 4) {
> >         *p = v;
> >     } else {
> > -        memcpy(p, &v, sizeof(v));
> > +        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
> >     }
> > }
> > #endif
> > @@ -263,21 +269,23 @@ static __attribute__((unused)) inline void tcg_patch32(tcg_insn_unit *p,
> > static __attribute__((unused)) inline void tcg_out64(TCGContext *s, uint64_t v)
> > {
> >     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
> > -        *s->code_ptr++ = v;
> > +        *TCG_CODE_PTR_RW(s, s->code_ptr) = v;
> > +        s->code_ptr++;
> >     } else {
> >         tcg_insn_unit *p = s->code_ptr;
> > -        memcpy(p, &v, sizeof(v));
> > +        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
> >         s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE);
> >     }
> > }
> >
> > -static __attribute__((unused)) inline void tcg_patch64(tcg_insn_unit *p,
> > +static __attribute__((unused)) inline void tcg_patch64(TCGContext *s,
> > +                                                       tcg_insn_unit *p,
> >                                                        uint64_t v)
> > {
> >     if (TCG_TARGET_INSN_UNIT_SIZE == 8) {
> >         *p = v;
> >     } else {
> > -        memcpy(p, &v, sizeof(v));
> > +        memcpy(TCG_CODE_PTR_RW(s, p), &v, sizeof(v));
> >     }
> > }
> > #endif
> > @@ -295,7 +303,7 @@ static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
> >     QSIMPLEQ_INSERT_TAIL(&l->relocs, r, next);
> > }
> >
> > -static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr)
> > +static void tcg_out_label(TCGContext *s, TCGLabel *l, const tcg_insn_unit *ptr)
> > {
> >     tcg_debug_assert(!l->has_value);
> >     l->has_value = 1;
> > @@ -325,7 +333,7 @@ static bool tcg_resolve_relocs(TCGContext *s)
> >         uintptr_t value = l->u.value;
> >
> >         QSIMPLEQ_FOREACH(r, &l->relocs, next) {
> > -            if (!patch_reloc(r->ptr, r->type, value, r->addend)) {
> > +            if (!patch_reloc(s, r->ptr, r->type, value, r->addend)) {
> >                 return false;
> >             }
> >         }
> > @@ -1039,7 +1047,7 @@ TranslationBlock *tcg_tb_alloc(TCGContext *s)
> >     }
> >     qatomic_set(&s->code_gen_ptr, next);
> >     s->data_gen_ptr = NULL;
> > -    return tb;
> > +    return (TranslationBlock *)TCG_CODE_PTR_RW(s, tb);
> > }
> >
> > void tcg_prologue_init(TCGContext *s)
> > @@ -1076,6 +1084,10 @@ void tcg_prologue_init(TCGContext *s)
> > #endif
> >
> >     buf1 = s->code_ptr;
> > +#if defined(CONFIG_IOS_JIT)
> > +    flush_dcache_range((uintptr_t)TCG_CODE_PTR_RW(s, buf0),
> > +                       (uintptr_t)TCG_CODE_PTR_RW(s, buf1));
> > +#endif
> >     flush_icache_range((uintptr_t)buf0, (uintptr_t)buf1);
> >
> >     /* Deduct the prologue from the buffer.  */
> > @@ -4267,6 +4279,12 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
> >         return -2;
> >     }
> >
> > +#if defined(CONFIG_IOS_JIT)
> > +    /* flush data cache on mirror */
> > +    flush_dcache_range((uintptr_t)TCG_CODE_PTR_RW(s, s->code_buf),
> > +                       (uintptr_t)TCG_CODE_PTR_RW(s, s->code_ptr));
> > +#endif
> > +
> >     /* flush instruction cache */
> >     flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr);
> >
> > diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc
> > index 231b9b1775..133213be3a 100644
> > --- a/tcg/tci/tcg-target.c.inc
> > +++ b/tcg/tci/tcg-target.c.inc
> > @@ -369,7 +369,7 @@ static const char *const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
> > };
> > #endif
> >
> > -static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> > +static bool patch_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
> >                         intptr_t value, intptr_t addend)
> > {
> >     /* tcg_out_reloc always uses the same type, addend. */
> > @@ -377,9 +377,9 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
> >     tcg_debug_assert(addend == 0);
> >     tcg_debug_assert(value != 0);
> >     if (TCG_TARGET_REG_BITS == 32) {
> > -        tcg_patch32(code_ptr, value);
> > +        tcg_patch32(s, code_ptr, value);
> >     } else {
> > -        tcg_patch64(code_ptr, value);
> > +        tcg_patch64(s, code_ptr, value);
> >     }
> >     return true;
> > }
> > @@ -545,7 +545,7 @@ static void tcg_out_movi(TCGContext *s, TCGType type,
> >     old_code_ptr[1] = s->code_ptr - old_code_ptr;
> > }
> >
> > -static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *arg)
> > +static inline void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg)
> > {
> >     uint8_t *old_code_ptr = s->code_ptr;
> >     tcg_out_op_t(s, INDEX_op_call);
> > diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h
> > index 8c1c1d265d..2a258ea350 100644
> > --- a/tcg/tci/tcg-target.h
> > +++ b/tcg/tci/tcg-target.h
> > @@ -195,6 +195,12 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
> > {
> > }
> >
> > +#if defined(CONFIG_IOS_JIT)
> > +static inline void flush_dcache_range(uintptr_t start, uintptr_t stop)
> > +{
> > +}
> > +#endif
> > +
> > /* We could notice __i386__ or __s390x__ and reduce the barriers depending
> >    on the host.  But if you want performance, you use the normal backend.
> >    We prefer consistency across hosts on this.  */
> > @@ -203,7 +209,8 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
> > #define TCG_TARGET_HAS_MEMORY_BSWAP     1
> >
> > static inline void tb_target_set_jmp_target(uintptr_t tc_ptr,
> > -                                            uintptr_t jmp_addr, uintptr_t addr)
> > +                                            uintptr_t jmp_addr, uintptr_t addr,
> > +                                            uintptr_t wr_addr)
> > {
> >     /* patch the branch destination */
> >     qatomic_set((int32_t *)jmp_addr, addr - (jmp_addr + 4));
> >
>


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 04/10] meson: option to build as shared library
  2020-10-13 16:40             ` BALATON Zoltan via
@ 2020-10-14 16:09               ` Joelle van Dyne
  0 siblings, 0 replies; 47+ messages in thread
From: Joelle van Dyne @ 2020-10-14 16:09 UTC (permalink / raw)
  To: BALATON Zoltan; +Cc: Daniel P. Berrangé, QEMU

Since there seems to be some more push back on this one, I will remove
this patch from the v2 submission and submit it as a separate patch

-j

On Tue, Oct 13, 2020 at 9:40 AM BALATON Zoltan <balaton@eik.bme.hu> wrote:
>
> On Tue, 13 Oct 2020, Daniel P. Berrangé wrote:
> > On Tue, Oct 13, 2020 at 08:16:46AM -0700, Joelle van Dyne wrote:
> >> I will start a separate conversation of UTM's license compatibility.
> >>
> >> Regarding the patch, would some sort of warning message in configure
> >> (if building as a shared library) regarding the license be wise? Or
> >> would it pollute the output logs?
> >
> > I think there's also a more fundamental question of whether this is
> > a concept we actually want to support at all.
>
> Discussing other compelling reasons for doubt is OK, just wanted to avoid
> having this dismissed on possible licensing problems only. I still think
> it would be a good idea to support QEMU on iOS but due to the (mostly
> security related) limitations of that platform some compromises my be
> needed. Please consider it instead of being quick to decide to avoid these
> problems by not taking the patches upstream which is a convenient solution
> from QEMU viewpoint but not helping other projects. (Other platforms may
> come up in the future with similar limitations that iOS has as more
> desktop OSes also move in the same direction to increase security so these
> may need to be handled anyway at one point, iOS is a good test case for
> that.)
>
> > IIUC, this shared library just exposes a "qemu_main" method which
> > the external app has to jump into. IOW, the "char **argv" parameter
> > to qemu_main becomes the ELF library ABI.  Declaring this a shared
> > library interface is a non-negligible commitment for QEMU maintainers,
> > especially given that there is alot about QMEU's command line parsing
> > that maintainers do not like and wish to change.
>
> Given that libvirt uses the command line instead of a proper API
> currently, this is not worse than that. If there was a better API or there
> will be one in the future, the shared lib API can be changed the same way
> as libvirt will need to be adapted for that but it's not reasonable to
> demand these patches to come up with that API now. So for now this seems
> to be acceptable and does not prevent cleaning it up later together with
> the planned changes you mentioned. Compatibility for the command line will
> have to be maintained until a better API is devised for use by other
> software like libvirt and anyone intending to use it as dll so this does
> not seem like added commitment.
>
> > There is a further question about whether we want to commit to an
> > architectural model where  fork() is not something we can use. A
>
> Does Windows support fork()? I think we're already committed to support
> Windows so any solution you'll come up with will have the same problem
> anyway. So I think this does not add additional restriction that we don't
> already have either.
>
> Regards,
> BALATON Zoltan


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 07/10] tcg: implement bulletproof JIT
  2020-10-14 16:03     ` Joelle van Dyne
@ 2020-10-14 20:35       ` Richard Henderson
  2020-10-14 20:54         ` BALATON Zoltan via
  2020-10-14 20:58         ` Joelle van Dyne
  0 siblings, 2 replies; 47+ messages in thread
From: Richard Henderson @ 2020-10-14 20:35 UTC (permalink / raw)
  To: Joelle van Dyne, BALATON Zoltan; +Cc: Philippe Mathieu-Daudé, QEMU

On 10/14/20 9:03 AM, Joelle van Dyne wrote:
>>> static int encode_search(TranslationBlock *tb, uint8_t *block)
>>> {
>>> -    uint8_t *highwater = tcg_ctx->code_gen_highwater;
>>> -    uint8_t *p = block;
>>> +    uint8_t *highwater;
>>> +    uint8_t *p;
>>>     int i, j, n;
>>>
>>> +    highwater = (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx,
>>> +                                           tcg_ctx->code_gen_highwater);
>>> +    p = (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx, block);
>>
>> Why do you need explicit casts here? Can this be avoided by using
>> appropriate type or within the macro (I haven't checked this at all just
>> dislike casts as they can hide problems otherwise caught by the compiler).
> There's the choice between tcg_insn_unit * and uint8_t *. Since it's
> used much more widely in tcg-target.inc.c, it seemed like
> tcg_insn_unit * was a better choice.

False choice.  This is why tcg_ctx->code_gen_highwater is void*.

>>> +#if defined(CONFIG_IOS_JIT)
>>> +# define TCG_CODE_PTR_RW(s, code_ptr) \
>>> +    (tcg_insn_unit *)((uintptr_t)(code_ptr) + (s)->code_rw_mirror_diff)

Better as

static inline void *tcg_code_ptr_rw(TCGContext *s, void *rx)
{
#ifdef CONFIG_IOS_JIT
    return rx + s->code_rw_mirror_diff;
#else
    return rx;
#endif
}


r~


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 07/10] tcg: implement bulletproof JIT
  2020-10-14 20:35       ` Richard Henderson
@ 2020-10-14 20:54         ` BALATON Zoltan via
  2020-10-14 21:40           ` Richard Henderson
  2020-10-14 20:58         ` Joelle van Dyne
  1 sibling, 1 reply; 47+ messages in thread
From: BALATON Zoltan via @ 2020-10-14 20:54 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Philippe Mathieu-Daudé, Joelle van Dyne, QEMU

On Wed, 14 Oct 2020, Richard Henderson wrote:
> On 10/14/20 9:03 AM, Joelle van Dyne wrote:
>>>> static int encode_search(TranslationBlock *tb, uint8_t *block)
>>>> {
>>>> -    uint8_t *highwater = tcg_ctx->code_gen_highwater;
>>>> -    uint8_t *p = block;
>>>> +    uint8_t *highwater;
>>>> +    uint8_t *p;
>>>>     int i, j, n;
>>>>
>>>> +    highwater = (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx,
>>>> +                                           tcg_ctx->code_gen_highwater);
>>>> +    p = (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx, block);
>>>
>>> Why do you need explicit casts here? Can this be avoided by using
>>> appropriate type or within the macro (I haven't checked this at all just
>>> dislike casts as they can hide problems otherwise caught by the compiler).
>> There's the choice between tcg_insn_unit * and uint8_t *. Since it's
>> used much more widely in tcg-target.inc.c, it seemed like
>> tcg_insn_unit * was a better choice.
>
> False choice.  This is why tcg_ctx->code_gen_highwater is void*.
>
>>>> +#if defined(CONFIG_IOS_JIT)
>>>> +# define TCG_CODE_PTR_RW(s, code_ptr) \
>>>> +    (tcg_insn_unit *)((uintptr_t)(code_ptr) + (s)->code_rw_mirror_diff)
>
> Better as
>
> static inline void *tcg_code_ptr_rw(TCGContext *s, void *rx)
> {
> #ifdef CONFIG_IOS_JIT
>    return rx + s->code_rw_mirror_diff;

This looks better but can you add to void *? I think some compilers may 
complain about that so may need to cast here to uint8_t * then back to 
void * but that's at least within this func or maybe declare rx as uint_t 
* and return void *? Or is rx promoted to the type of 
s->code_rw_mirror_diff and that avoids the warning? If the gcc and clang 
versions we care about don't mind then it's simpler without a cast as you 
suggest.

Regards,
BALATON Zoltan

> #else
>    return rx;
> #endif
> }
>
>
> r~
>
>


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 07/10] tcg: implement bulletproof JIT
  2020-10-14 20:35       ` Richard Henderson
  2020-10-14 20:54         ` BALATON Zoltan via
@ 2020-10-14 20:58         ` Joelle van Dyne
  2020-10-14 21:08           ` BALATON Zoltan via
  2020-10-14 21:49           ` Richard Henderson
  1 sibling, 2 replies; 47+ messages in thread
From: Joelle van Dyne @ 2020-10-14 20:58 UTC (permalink / raw)
  To: Richard Henderson; +Cc: QEMU, Philippe Mathieu-Daudé, Joelle van Dyne

Much of the code that uses the macro is like the following (from
aarch64/tcg-include.inc.c)

        *TCG_CODE_PTR_RW(s, code_ptr) =
            deposit32(*TCG_CODE_PTR_RW(s, code_ptr), 0, 26, offset);

Before the change, it was just *code_ptr. I'm saying the alternative
was to have to write "tcg_insn_unit *rw_code_ptr = (tcg_insn_unit
*)TCG_CODE_PTR_RW(s, code_ptr)" everywhere or else inline cast it.
Whereas making it return tcg_insn_unit * means only three instances of
casting to uint8_t *. Using void * means casting at every instance.

Not opposed to using an inline function over a macro but "inline" is
not ANSI C. Not sure what this project thinks about that considering
the style checker prohibits C99 style comments. Personally I don't
care much.

-j

On Wed, Oct 14, 2020 at 1:35 PM Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> On 10/14/20 9:03 AM, Joelle van Dyne wrote:
> >>> static int encode_search(TranslationBlock *tb, uint8_t *block)
> >>> {
> >>> -    uint8_t *highwater = tcg_ctx->code_gen_highwater;
> >>> -    uint8_t *p = block;
> >>> +    uint8_t *highwater;
> >>> +    uint8_t *p;
> >>>     int i, j, n;
> >>>
> >>> +    highwater = (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx,
> >>> +                                           tcg_ctx->code_gen_highwater);
> >>> +    p = (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx, block);
> >>
> >> Why do you need explicit casts here? Can this be avoided by using
> >> appropriate type or within the macro (I haven't checked this at all just
> >> dislike casts as they can hide problems otherwise caught by the compiler).
> > There's the choice between tcg_insn_unit * and uint8_t *. Since it's
> > used much more widely in tcg-target.inc.c, it seemed like
> > tcg_insn_unit * was a better choice.
>
> False choice.  This is why tcg_ctx->code_gen_highwater is void*.
>
> >>> +#if defined(CONFIG_IOS_JIT)
> >>> +# define TCG_CODE_PTR_RW(s, code_ptr) \
> >>> +    (tcg_insn_unit *)((uintptr_t)(code_ptr) + (s)->code_rw_mirror_diff)
>
> Better as
>
> static inline void *tcg_code_ptr_rw(TCGContext *s, void *rx)
> {
> #ifdef CONFIG_IOS_JIT
>     return rx + s->code_rw_mirror_diff;
> #else
>     return rx;
> #endif
> }
>
>
> r~


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 07/10] tcg: implement bulletproof JIT
  2020-10-14 20:58         ` Joelle van Dyne
@ 2020-10-14 21:08           ` BALATON Zoltan via
  2020-10-14 21:49           ` Richard Henderson
  1 sibling, 0 replies; 47+ messages in thread
From: BALATON Zoltan via @ 2020-10-14 21:08 UTC (permalink / raw)
  To: Joelle van Dyne; +Cc: Philippe Mathieu-Daudé, Richard Henderson, QEMU

On Wed, 14 Oct 2020, Joelle van Dyne wrote:
> Much of the code that uses the macro is like the following (from
> aarch64/tcg-include.inc.c)
>
>        *TCG_CODE_PTR_RW(s, code_ptr) =
>            deposit32(*TCG_CODE_PTR_RW(s, code_ptr), 0, 26, offset);
>
> Before the change, it was just *code_ptr. I'm saying the alternative
> was to have to write "tcg_insn_unit *rw_code_ptr = (tcg_insn_unit
> *)TCG_CODE_PTR_RW(s, code_ptr)" everywhere or else inline cast it.
> Whereas making it return tcg_insn_unit * means only three instances of
> casting to uint8_t *. Using void * means casting at every instance.

It's not C++ so void * does not need to be cast when assigned to some 
other pointer.

> Not opposed to using an inline function over a macro but "inline" is
> not ANSI C. Not sure what this project thinks about that considering
> the style checker prohibits C99 style comments. Personally I don't
> care much.

QEMU has some compiler dependencies, I think only some recent versions of 
gcc and clang are supported and static inline is used elsewhere in the 
code. Richard is an expert on TCG so you can take his advice.

Regards,
BALATON Zoltan

>
> -j
>
> On Wed, Oct 14, 2020 at 1:35 PM Richard Henderson
> <richard.henderson@linaro.org> wrote:
>>
>> On 10/14/20 9:03 AM, Joelle van Dyne wrote:
>>>>> static int encode_search(TranslationBlock *tb, uint8_t *block)
>>>>> {
>>>>> -    uint8_t *highwater = tcg_ctx->code_gen_highwater;
>>>>> -    uint8_t *p = block;
>>>>> +    uint8_t *highwater;
>>>>> +    uint8_t *p;
>>>>>     int i, j, n;
>>>>>
>>>>> +    highwater = (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx,
>>>>> +                                           tcg_ctx->code_gen_highwater);
>>>>> +    p = (uint8_t *)TCG_CODE_PTR_RW(tcg_ctx, block);
>>>>
>>>> Why do you need explicit casts here? Can this be avoided by using
>>>> appropriate type or within the macro (I haven't checked this at all just
>>>> dislike casts as they can hide problems otherwise caught by the compiler).
>>> There's the choice between tcg_insn_unit * and uint8_t *. Since it's
>>> used much more widely in tcg-target.inc.c, it seemed like
>>> tcg_insn_unit * was a better choice.
>>
>> False choice.  This is why tcg_ctx->code_gen_highwater is void*.
>>
>>>>> +#if defined(CONFIG_IOS_JIT)
>>>>> +# define TCG_CODE_PTR_RW(s, code_ptr) \
>>>>> +    (tcg_insn_unit *)((uintptr_t)(code_ptr) + (s)->code_rw_mirror_diff)
>>
>> Better as
>>
>> static inline void *tcg_code_ptr_rw(TCGContext *s, void *rx)
>> {
>> #ifdef CONFIG_IOS_JIT
>>     return rx + s->code_rw_mirror_diff;
>> #else
>>     return rx;
>> #endif
>> }
>>
>>
>> r~
>
>


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 07/10] tcg: implement bulletproof JIT
  2020-10-14 20:54         ` BALATON Zoltan via
@ 2020-10-14 21:40           ` Richard Henderson
  0 siblings, 0 replies; 47+ messages in thread
From: Richard Henderson @ 2020-10-14 21:40 UTC (permalink / raw)
  To: BALATON Zoltan; +Cc: Philippe Mathieu-Daudé, Joelle van Dyne, QEMU

On 10/14/20 1:54 PM, BALATON Zoltan wrote:
>> static inline void *tcg_code_ptr_rw(TCGContext *s, void *rx)
>> {
>> #ifdef CONFIG_IOS_JIT
>>    return rx + s->code_rw_mirror_diff;
> 
> This looks better but can you add to void *? I think some compilers may
> complain about that so may need to cast here to uint8_t * then back to void *

We already rely on void* arithmetic all over the code base.


r~


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 07/10] tcg: implement bulletproof JIT
  2020-10-14 20:58         ` Joelle van Dyne
  2020-10-14 21:08           ` BALATON Zoltan via
@ 2020-10-14 21:49           ` Richard Henderson
  2020-10-14 22:54             ` Joelle van Dyne
  1 sibling, 1 reply; 47+ messages in thread
From: Richard Henderson @ 2020-10-14 21:49 UTC (permalink / raw)
  To: Joelle van Dyne; +Cc: Philippe Mathieu-Daudé, QEMU

On 10/14/20 1:58 PM, Joelle van Dyne wrote:
> Much of the code that uses the macro is like the following (from
> aarch64/tcg-include.inc.c)
> 
>         *TCG_CODE_PTR_RW(s, code_ptr) =
>             deposit32(*TCG_CODE_PTR_RW(s, code_ptr), 0, 26, offset);
> 
> Before the change, it was just *code_ptr. I'm saying the alternative
> was to have to write "tcg_insn_unit *rw_code_ptr = (tcg_insn_unit
> *)TCG_CODE_PTR_RW(s, code_ptr)" everywhere or else inline cast it.
> Whereas making it return tcg_insn_unit * means only three instances of
> casting to uint8_t *. Using void * means casting at every instance.

I should have done more than skim, I suppose.

Well, without going back to look, how many of these are there, really?
Virtually all of the writes should be via tcg_out32().

If there's < 5 of the above per tcg/foo/ -- particularly if they're all
restricted to relocations as in the above -- then I'm ok with local variable
assignment to "rw_ptr".  Especially since the replacement isn't exactly small,
and you're having to split to two separate lines anyway.

I'll have a real look when you've split this into parts, because otherwise it's
just too big.


r~


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH 07/10] tcg: implement bulletproof JIT
  2020-10-14 21:49           ` Richard Henderson
@ 2020-10-14 22:54             ` Joelle van Dyne
  0 siblings, 0 replies; 47+ messages in thread
From: Joelle van Dyne @ 2020-10-14 22:54 UTC (permalink / raw)
  To: Richard Henderson; +Cc: QEMU, Philippe Mathieu-Daudé, Joelle van Dyne

There's about 40 instances of *code_ptr or code_ptr[i] changed to
TCG_CODE_PTR_RW(s, code_ptr). It's around 2 instances per function, so
if I go with a local variable, that would be ~20 extra LOC.

Another alternative is two separate functions: tcg_code_ptr_insn_rw()
which returns tcg_insn_unit * and tcg_code_ptr_rw() which returns void
*. I'll go that route unless there's any objections?

-j

On Wed, Oct 14, 2020 at 2:49 PM Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> On 10/14/20 1:58 PM, Joelle van Dyne wrote:
> > Much of the code that uses the macro is like the following (from
> > aarch64/tcg-include.inc.c)
> >
> >         *TCG_CODE_PTR_RW(s, code_ptr) =
> >             deposit32(*TCG_CODE_PTR_RW(s, code_ptr), 0, 26, offset);
> >
> > Before the change, it was just *code_ptr. I'm saying the alternative
> > was to have to write "tcg_insn_unit *rw_code_ptr = (tcg_insn_unit
> > *)TCG_CODE_PTR_RW(s, code_ptr)" everywhere or else inline cast it.
> > Whereas making it return tcg_insn_unit * means only three instances of
> > casting to uint8_t *. Using void * means casting at every instance.
>
> I should have done more than skim, I suppose.
>
> Well, without going back to look, how many of these are there, really?
> Virtually all of the writes should be via tcg_out32().
>
> If there's < 5 of the above per tcg/foo/ -- particularly if they're all
> restricted to relocations as in the above -- then I'm ok with local variable
> assignment to "rw_ptr".  Especially since the replacement isn't exactly small,
> and you're having to split to two separate lines anyway.
>
> I'll have a real look when you've split this into parts, because otherwise it's
> just too big.
>
>
> r~


^ permalink raw reply	[flat|nested] 47+ messages in thread

end of thread, other threads:[~2020-10-14 22:58 UTC | newest]

Thread overview: 47+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-12 23:29 [PATCH 00/10] iOS and Apple Silicon host support Joelle van Dyne
2020-10-12 23:29 ` [PATCH 01/10] configure: option to disable host block devices Joelle van Dyne
2020-10-12 23:29 ` [PATCH 02/10] configure: cross-compiling without cross_prefix Joelle van Dyne
2020-10-12 23:29 ` [PATCH 03/10] qemu: add support for iOS host Joelle van Dyne
2020-10-12 23:29 ` [PATCH 04/10] meson: option to build as shared library Joelle van Dyne
2020-10-13  7:51   ` Daniel P. Berrangé
2020-10-13 14:41     ` BALATON Zoltan via
2020-10-13 14:46       ` Daniel P. Berrangé
2020-10-13 15:16         ` Joelle van Dyne
2020-10-13 15:57           ` Daniel P. Berrangé
2020-10-13 16:40             ` BALATON Zoltan via
2020-10-14 16:09               ` Joelle van Dyne
2020-10-13 15:23         ` BALATON Zoltan via
2020-10-12 23:29 ` [PATCH 05/10] slirp: update for iOS resolv fix Joelle van Dyne
2020-10-13 13:32   ` Philippe Mathieu-Daudé
2020-10-13 14:38     ` Marc-André Lureau
2020-10-13 14:59       ` Philippe Mathieu-Daudé
2020-10-14 15:54         ` Joelle van Dyne
2020-10-12 23:29 ` [PATCH 06/10] coroutine: add libucontext as external library Joelle van Dyne
2020-10-13 13:31   ` Stefan Hajnoczi
2020-10-13 14:49     ` BALATON Zoltan via
2020-10-13 15:25       ` Joelle van Dyne
2020-10-13 16:18       ` Daniel P. Berrangé
2020-10-12 23:29 ` [PATCH 07/10] tcg: implement bulletproof JIT Joelle van Dyne
2020-10-12 23:29   ` Joelle van Dyne
2020-10-13  8:22   ` Philippe Mathieu-Daudé
2020-10-13  8:22     ` Philippe Mathieu-Daudé
2020-10-13 14:58   ` BALATON Zoltan via
2020-10-13 14:58     ` BALATON Zoltan
2020-10-14 16:03     ` Joelle van Dyne
2020-10-14 20:35       ` Richard Henderson
2020-10-14 20:54         ` BALATON Zoltan via
2020-10-14 21:40           ` Richard Henderson
2020-10-14 20:58         ` Joelle van Dyne
2020-10-14 21:08           ` BALATON Zoltan via
2020-10-14 21:49           ` Richard Henderson
2020-10-14 22:54             ` Joelle van Dyne
2020-10-12 23:29 ` [PATCH 08/10] tcg: mirror mapping RWX pages for iOS optional Joelle van Dyne
2020-10-13 13:52   ` Paolo Bonzini
2020-10-13 15:10     ` Joelle van Dyne
2020-10-12 23:29 ` [PATCH 09/10] tcg: support JIT on Apple Silicon Joelle van Dyne
2020-10-13 13:55   ` Paolo Bonzini
2020-10-13 14:09     ` Peter Maydell
2020-10-13 15:13       ` Joelle van Dyne
2020-10-12 23:29 ` [PATCH 10/10] block: check availablity for preadv/pwritev on mac Joelle van Dyne
2020-10-13  1:21 ` [PATCH 00/10] iOS and Apple Silicon host support no-reply
2020-10-13  2:12   ` Joelle van Dyne

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.