+static void mprotect_w_x(void *start, void *end, int is_x)
+{
+#ifdef NO_WRITE_EXEC
+ #if defined(VITA)
+ // *Open* enables write on all memory that was
+ // allocated by sceKernelAllocMemBlockForVM()?
+ if (is_x)
+ sceKernelCloseVMDomain();
+ else
+ sceKernelOpenVMDomain();
+ #else
+ u_long mstart = (u_long)start & ~4095ul;
+ u_long mend = (u_long)end;
+ if (mprotect((void *)mstart, mend - mstart,
+ PROT_READ | (is_x ? PROT_EXEC : PROT_WRITE)) != 0)
+ SysPrintf("mprotect(%c) failed: %s\n", is_x ? 'x' : 'w', strerror(errno));
+ #endif
+#endif
+}
+
+static void start_tcache_write(void *start, void *end)
+{
+ mprotect_w_x(start, end, 0);
+}
+
+static void end_tcache_write(void *start, void *end)
+{
+#ifdef __arm__
+ size_t len = (char *)end - (char *)start;
+ #if defined(__BLACKBERRY_QNX__)
+ msync(start, len, MS_SYNC | MS_CACHE_ONLY | MS_INVALIDATE_ICACHE);
+ #elif defined(__MACH__)
+ sys_cache_control(kCacheFunctionPrepareForExecution, start, len);
+ #elif defined(VITA)
+ sceKernelSyncVMDomain(sceBlock, start, len);
+ #elif defined(_3DS)
+ ctr_flush_invalidate_cache();
+ #else
+ __clear_cache(start, end);
+ #endif
+ (void)len;
+#endif
+
+ mprotect_w_x(start, end, 1);
+}
+
+static void *start_block(void)
+{
+ u_char *end = out + MAX_OUTPUT_BLOCK_SIZE;
+ if (end > (u_char *)BASE_ADDR + (1<<TARGET_SIZE_2))
+ end = (u_char *)BASE_ADDR + (1<<TARGET_SIZE_2);
+ start_tcache_write(out, end);
+ return out;
+}
+
+static void end_block(void *start)
+{
+ end_tcache_write(start, out);
+}
+