Skip to content

Commit

Permalink
[iOS] Honour R^X requirement in ARM JIT
Browse files Browse the repository at this point in the history
- Only required for 64bit OSs, it's expensive
- hrydgard/ppsspp#8937
  • Loading branch information
Vogtinator committed Dec 2, 2016
1 parent a585c2d commit fb534bc
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 12 deletions.
14 changes: 2 additions & 12 deletions core/os/os-linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,21 +64,11 @@ void os_sparse_decommit(void *page, size_t size)
(void) size;
}

#ifdef IS_IOS_BUILD
bool runtime_is64Bit()
{
#include <sys/utsname.h>
struct utsname ret;
uname(&ret);
return (strstr(ret.version, "ARM64") != NULL);
}
#endif

void *os_alloc_executable(size_t size)
{
#ifdef IS_IOS_BUILD
// the access() will succeed on jailbroken only
if (access("/bin/bash", F_OK) != 0 || runtime_is64Bit())
// /bin/bash only exists if jailbroken
if (access("/bin/bash", F_OK) != 0)
{
// Can't use JIT
return NULL;
Expand Down
38 changes: 38 additions & 0 deletions core/translate_arm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,25 @@ static __attribute__((unused)) void emit_bkpt()
emit_al(0x1200070); // bkpt #0
}

#ifdef IS_IOS_BUILD
#include <sys/utsname.h>
#include <sys/mman.h>

// 64bit iOS enforces W^X
static bool w_xor_x_enforced = false;
#endif

bool translate_init()
{
if(translate_buffer)
return true;

#ifdef IS_IOS_BUILD
struct utsname ret;
uname(&ret);
w_xor_x_enforced = (strstr(ret.version, "ARM64") != NULL);
#endif

translate_current = translate_buffer = reinterpret_cast<uint32_t*>(os_alloc_executable(INSN_BUFFER_SIZE));
translate_end = translate_current + INSN_BUFFER_SIZE/sizeof(*translate_buffer);
jump_table_current = jump_table;
Expand Down Expand Up @@ -203,6 +217,11 @@ void translate(uint32_t pc_start, uint32_t *insn_ptr_start)
this_translation->jump_table = reinterpret_cast<void**>(jump_table_start);
this_translation->start_ptr = insn_ptr_start;

#ifdef IS_IOS_BUILD
// Last page marked as RW
uintptr_t translate_current_rw = 0;
#endif

// This loop is executed once per instruction.
// Due to the CPU being able to jump to each instruction seperately,
// there is no state preserved between (virtual) instructions.
Expand All @@ -215,6 +234,19 @@ void translate(uint32_t pc_start, uint32_t *insn_ptr_start)
|| (pc ^ pc_start) & ~0x3ff)
goto exit_translation;

#ifdef IS_IOS_BUILD
if(w_xor_x_enforced)
{
// If we now write into a different page
if((uintptr_t(translate_current) ^ translate_current_rw) & ~4095)
{
// Mark this page and the next one as writable
mprotect((void*)(uintptr_t(translate_current) & ~4095), 8192, PROT_READ | PROT_WRITE);
translate_current_rw = uintptr_t(translate_current);
}
}
#endif

Instruction i;
uint32_t insn = i.raw = *insn_ptr;

Expand Down Expand Up @@ -786,6 +818,12 @@ void translate(uint32_t pc_start, uint32_t *insn_ptr_start)
// Flush the instruction cache
#ifdef IS_IOS_BUILD
sys_cache_control(1 /* kCacheFunctionPrepareForExecution */, jump_table_start[0], (translate_current-jump_table_start[0])*4);

if(w_xor_x_enforced)
{
auto start_page = uintptr_t(jump_table_start[0]) & ~4095;
mprotect((void*) start_page, uintptr_t(translate_current) - start_page, PROT_READ | PROT_EXEC);
}
#else
__builtin___clear_cache(jump_table_start[0], translate_current);
#endif
Expand Down

0 comments on commit fb534bc

Please sign in to comment.