gpsp/memmap.c

84 lines
2.4 KiB
C

#include <stdint.h>
#include "memmap.h"
// The JIT cache buffer is allocated via mmap (or win equivalent) so that it
// can be RWX. On top of that, we need the bufer to be "close" to the text
// segment, so that we can perform jumps between the two code blocks.
// Android and some other platforms discourage the usage of sections in the
// binary (ie. on-disk ELF) that are marked as executable and writtable for
// security reasons. Therefore we prefer to use mmap even though it can be
// tricky to map correctly.
// To map a block close to the code, we take the function address as a proxy
// of the text section address, and try to map the cache next to it. This is
// an iterative process of trial and error that is hopefully successful.
// x86-64 has a +/- 2GB offset requirement.
// ARM64 has a +/-128MB offset requirement.
// ARM32 has a +/- 32MB offset requirement (gpsp does not require this).
// MIPS requires blocks to be within the same 256MB boundary (identical 4 MSB)
#ifdef MMAP_JIT_CACHE
#ifdef WIN32
#include <windows.h>
#include <io.h>
void *map_jit_block(unsigned size) {
unsigned i;
uintptr_t base = (uintptr_t)(map_jit_block) & (~0xFFFFFULL);
for (i = 0; i < 256; i++) {
int offset = ((i & 1) ? 1 : -1) * (i >> 1) * 1024 * 1024;
uintptr_t baddr = base + (intptr_t)offset;
if (!baddr)
continue; // Do not map NULL, bad things happen :)
void *p = VirtualAlloc((void*)baddr, size, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (p == (void*)baddr)
return p;
if (p)
VirtualFree(p, 0, MEM_RELEASE);
}
return 0;
}
void unmap_jit_block(void *bufptr, unsigned size) {
VirtualFree(bufptr, 0, MEM_RELEASE);
}
#else
#include <sys/mman.h>
// Posix implementation
void *map_jit_block(unsigned size) {
unsigned i;
uintptr_t base = (uintptr_t)(map_jit_block) & (~0xFFFFFULL);
for (i = 0; i < 256; i++) {
int offset = ((i & 1) ? 1 : -1) * (i >> 1) * 1024 * 1024;
uintptr_t baddr = base + (intptr_t)offset;
if (!baddr)
continue; // Do not map NULL, bad things happen :)
void *p = mmap((void*)baddr, size, PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_ANON|MAP_PRIVATE, -1, 0);
if (p == (void*)baddr)
return p;
if (p)
munmap(p, size);
}
return 0;
}
void unmap_jit_block(void *bufptr, unsigned size) {
munmap(bufptr, size);
}
#endif /* WIN32 */
#endif /* MMAP_JIT_CACHE */