This adds support for x86-64 dynarec both on Windows and Linux. Since they have different requirements there's some macro magic in the stubs file. This also fixes x86 support in some cases: stack alignment requirements where violated all over. This allows the usage of clang as a compiler (which has a tendency to use SSE instructions more often than gcc does). To support this I also reworked the mmap/VirtualAlloc magic to make sure JIT arena stays close to .text. Fixed some other minor issues and removed some unnecessary JIT code here and there. clang tends to do some (wrong?) assumptions about global symbols alignment.
83 lines
2.4 KiB
C
83 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 */
|
|
|