diff options
Diffstat (limited to 'src/qcommon/vm_x86_64.c')
-rw-r--r-- | src/qcommon/vm_x86_64.c | 113 |
1 files changed, 75 insertions, 38 deletions
diff --git a/src/qcommon/vm_x86_64.c b/src/qcommon/vm_x86_64.c index 93e25f6d..13c39172 100644 --- a/src/qcommon/vm_x86_64.c +++ b/src/qcommon/vm_x86_64.c @@ -24,11 +24,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // vm_x86_64.c -- load time compiler and execution environment for x86-64 #include "vm_local.h" - -#include <sys/mman.h> #include <sys/stat.h> #include <sys/types.h> -#include <sys/wait.h> #include <sys/time.h> #include <time.h> #include <fcntl.h> @@ -36,6 +33,19 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include <unistd.h> #include <stdarg.h> +#include <inttypes.h> + +#ifdef __WIN64__ + #include <windows.h> + #define CROSSCALL __attribute__ ((sysv_abi))//fool the vm we're SYSV ABI + //#define __USE_MINGW_ANSI_STDIO 1 //very slow - avoid if possible +#else + #include <sys/mman.h> + #include <sys/wait.h> + #define VM_X86_64_MMAP + #define CROSSCALL +#endif + //#define DEBUG_VM #ifdef DEBUG_VM @@ -45,8 +55,6 @@ static FILE* qdasmout; #define Dfprintf(args...) #endif -#define VM_X86_64_MMAP - void assembler_set_output(char* buf); size_t assembler_get_code_size(void); void assembler_init(int pass); @@ -72,11 +80,11 @@ static void VM_Destroy_Compiled(vm_t* self); */ -static long callAsmCall(long callProgramStack, long callSyscallNum) +static int64_t CROSSCALL callAsmCall(int64_t callProgramStack, int64_t callSyscallNum) { vm_t *savedVM; - long ret = 0x77; - long args[11]; + int64_t ret = 0x77; + int64_t args[11]; // int iargs[11]; int i; @@ -232,13 +240,13 @@ void emit(const char* fmt, ...) #define CHECK_INSTR_REG(reg) \ emit("cmpl $%u, %%"#reg, header->instructionCount); \ emit("jb jmp_ok_i_%08x", instruction); \ - emit("movq $%lu, %%rax", (unsigned long)jmpviolation); \ + emit("movq $%"PRIu64", %%rax", (uint64_t)jmpviolation); \ emit("callq *%%rax"); \ emit("jmp_ok_i_%08x:", instruction); #define PREPARE_JMP(reg) \ CHECK_INSTR_REG(reg) \ - emit("movq $%lu, %%rbx", (unsigned long)vm->instructionPointers); \ + emit("movq $%"PRIu64", %%rbx", (uint64_t)vm->instructionPointers); \ emit("movl (%%rbx, %%rax, 4), %%eax"); \ emit("addq %%r10, %%rax"); @@ -250,7 +258,7 @@ void emit(const char* fmt, ...) #define JMPIARG \ CHECK_INSTR(iarg); \ - emit("movq $%lu, %%rax", vm->codeBase+vm->instructionPointers[iarg]); \ + emit("movq $%"PRIu64", %%rax", vm->codeBase+vm->instructionPointers[iarg]); \ emit("jmpq *%%rax"); #define CONST_OPTIMIZE @@ -340,7 +348,7 @@ void emit(const char* fmt, ...) emit("andl $0x%x, %%ecx", vm->dataMask &~(bytes-1)); \ emit("cmpl %%" #reg ", %%ecx"); \ emit("jz rc_ok_i_%08x", instruction); \ - emit("movq $%lu, %%rax", (unsigned long)memviolation); \ + emit("movq $%"PRIu64", %%rax", (uint64_t)memviolation); \ emit("callq *%%rax"); \ emit("rc_ok_i_%08x:", instruction); #elif 1 @@ -364,7 +372,7 @@ static void* getentrypoint(vm_t* vm) return vm->codeBase; } -static void block_copy_vm(unsigned dest, unsigned src, unsigned count) +static void CROSSCALL block_copy_vm(unsigned dest, unsigned src, unsigned count) { unsigned dataMask = currentVM->dataMask; @@ -379,20 +387,20 @@ static void block_copy_vm(unsigned dest, unsigned src, unsigned count) memcpy(currentVM->dataBase+dest, currentVM->dataBase+src, count); } -static void eop(void) +static void CROSSCALL eop(void) { Com_Error(ERR_DROP, "end of program reached without return!\n"); exit(1); } -static void jmpviolation(void) +static void CROSSCALL jmpviolation(void) { Com_Error(ERR_DROP, "program tried to execute code outside VM\n"); exit(1); } #ifdef DEBUG_VM -static void memviolation(void) +static void CROSSCALL memviolation(void) { Com_Error(ERR_DROP, "program tried to access memory outside VM\n"); exit(1); @@ -431,9 +439,19 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { { compiledOfs = assembler_get_code_size(); vm->codeLength = compiledOfs; - vm->codeBase = mmap(NULL, compiledOfs, PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); - if(vm->codeBase == (void*)-1) - Com_Error(ERR_DROP, "VM_CompileX86: can't mmap memory"); + + #ifdef VM_X86_64_MMAP + vm->codeBase = mmap(NULL, compiledOfs, PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); + if(vm->codeBase == (void*)-1) + Com_Error(ERR_DROP, "VM_CompileX86: can't mmap memory"); + #elif __WIN64__ + // allocate memory with write permissions under windows. + vm->codeBase = VirtualAlloc(NULL, compiledOfs, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); + if(!vm->codeBase) + Com_Error(ERR_DROP, "VM_CompileX86: VirtualAlloc failed"); + #else + vm->codeBase = malloc(compiledOfs); + #endif assembler_set_output((char*)vm->codeBase); } @@ -474,7 +492,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { else if(op_argsize[op] == 1) { barg = code[pc++]; - Dfprintf(qdasmout, "%s %8hhu\n", opnames[op], barg); + Dfprintf(qdasmout, "%s %8hu\n", opnames[op], barg); } else { @@ -518,7 +536,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { goto emit_do_syscall; CHECK_INSTR(const_value); - emit("movq $%lu, %%rax", vm->codeBase+vm->instructionPointers[const_value]); + emit("movq $%"PRIu64", %%rax", vm->codeBase+vm->instructionPointers[const_value]); emit("callq *%%rax"); got_const = 0; break; @@ -559,7 +577,7 @@ emit_do_syscall: // first argument already in rdi emit("movq %%rax, %%rsi"); // second argument in rsi } - emit("movq $%lu, %%rax", (unsigned long)callAsmCall); + emit("movq $%"PRIu64", %%rax", (uint64_t)callAsmCall); emit("callq *%%rax"); emit("pop %%rbx"); emit("addq %%rbx, %%rsp"); @@ -726,7 +744,7 @@ emit_do_syscall: MAYBE_EMIT_CONST(); emit("subq $4, %%rsi"); emit("movl 4(%%rsi), %%eax"); // get value from stack - emit("movl $0x%hhx, %%ebx", barg); + emit("movl $0x%hx, %%ebx", barg); emit("addl %%edi, %%ebx"); RANGECHECK(ebx, 4); emit("movl %%eax, 0(%%r8,%%rbx, 1)"); // store in args space @@ -740,11 +758,18 @@ emit_do_syscall: emit("push %%r8"); emit("push %%r9"); emit("push %%r10"); + emit("movq %%rsp, %%rbx"); // we need to align the stack pointer + emit("subq $8, %%rbx"); // | + emit("andq $127, %%rbx"); // | + emit("subq %%rbx, %%rsp"); // <-+ + emit("push %%rbx"); emit("movl 4(%%rsi), %%edi"); // 1st argument dest emit("movl 8(%%rsi), %%esi"); // 2nd argument src emit("movl $%d, %%edx", iarg); // 3rd argument count - emit("movq $%lu, %%rax", (unsigned long)block_copy_vm); + emit("movq $%"PRIu64", %%rax", (uint64_t)block_copy_vm); emit("callq *%%rax"); + emit("pop %%rbx"); + emit("addq %%rbx, %%rsp"); emit("pop %%r10"); emit("pop %%r9"); emit("pop %%r8"); @@ -910,15 +935,25 @@ emit_do_syscall: Com_Error(ERR_DROP, "leftover const\n"); } - emit("movq $%lu, %%rax", (unsigned long)eop); + emit("movq $%"PRIu64", %%rax", (uint64_t)eop); emit("callq *%%rax"); } // pass loop assembler_init(0); - if(mprotect(vm->codeBase, compiledOfs, PROT_READ|PROT_EXEC)) - Com_Error(ERR_DROP, "VM_CompileX86: mprotect failed"); + #ifdef VM_X86_64_MMAP + if(mprotect(vm->codeBase, compiledOfs, PROT_READ|PROT_EXEC)) + Com_Error(ERR_DROP, "VM_CompileX86: mprotect failed"); + #elif __WIN64__ + { + DWORD oldProtect = 0; + + // remove write permissions; give exec permision + if(!VirtualProtect(vm->codeBase, compiledOfs, PAGE_EXECUTE_READ, &oldProtect)) + Com_Error(ERR_DROP, "VM_CompileX86: VirtualProtect failed"); + } + #endif vm->destroy = VM_Destroy_Compiled; @@ -935,17 +970,19 @@ emit_do_syscall: fclose(qdasmout); #endif #endif - - if(vm->compiled) - { - struct timeval tvdone = {0, 0}; - struct timeval dur = {0, 0}; - Com_Printf( "VM file %s compiled to %i bytes of code (%p - %p)\n", vm->name, vm->codeLength, vm->codeBase, vm->codeBase+vm->codeLength ); - gettimeofday(&tvdone, NULL); - timersub(&tvdone, &tvstart, &dur); - Com_Printf( "compilation took %lu.%06lu seconds\n", dur.tv_sec, dur.tv_usec ); - } + #ifndef __WIN64__ //timersub and gettimeofday + if(vm->compiled) + { + struct timeval tvdone = {0, 0}; + struct timeval dur = {0, 0}; + Com_Printf( "VM file %s compiled to %i bytes of code (%p - %p)\n", vm->name, vm->codeLength, vm->codeBase, vm->codeBase+vm->codeLength ); + + gettimeofday(&tvdone, NULL); + timersub(&tvdone, &tvstart, &dur); + Com_Printf( "compilation took %"PRIu64".%06"PRIu64" seconds\n", dur.tv_sec, dur.tv_usec ); + } + #endif } @@ -1035,7 +1072,7 @@ int VM_CallCompiled( vm_t *vm, int *args ) { ); if ( opStack != &stack[1] ) { - Com_Error( ERR_DROP, "opStack corrupted in compiled code (offset %ld)\n", (long int) ((void *) &stack[1] - opStack)); + Com_Error( ERR_DROP, "opStack corrupted in compiled code (offset %"PRId64")\n", (int64_t) ((void *) &stack[1] - opStack)); } if ( programStack != stackOnEntry - 48 ) { Com_Error( ERR_DROP, "programStack corrupted in compiled code\n" ); |