#include #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 #include 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 // 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 */