From 760f4a1949d5b2fc654cd6308d56bd7b9eb25780 Mon Sep 17 00:00:00 2001 From: Ludwig Nussel Date: Sun, 28 Feb 2010 09:00:02 +0000 Subject: [PATCH] 64bit Windows support (patch by Michael Menegakis) --- Makefile | 36 +++++++--- code/jpeg-6b/jinclude.h | 3 + code/jpeg-6b/jmorecfg.h | 2 + code/qcommon/q_platform.h | 28 +++++++- code/qcommon/vm_x86_64.c | 106 ++++++++++++++++++----------- code/qcommon/vm_x86_64_assembler.c | 30 ++++---- code/sys/sys_win32.c | 9 +++ 7 files changed, 151 insertions(+), 63 deletions(-) diff --git a/Makefile b/Makefile index 8ef1fc11..a692b4a0 100644 --- a/Makefile +++ b/Makefile @@ -460,8 +460,6 @@ ifeq ($(PLATFORM),mingw32) WINDRES=windres endif - ARCH=x86 - BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \ -DUSE_ICON CLIENT_CFLAGS = @@ -486,12 +484,20 @@ ifeq ($(PLATFORM),mingw32) CLIENT_CFLAGS += -DUSE_CODEC_VORBIS endif - OPTIMIZEVM = -O3 -march=i586 -fno-omit-frame-pointer \ - -falign-loops=2 -funroll-loops -falign-jumps=2 -falign-functions=2 \ - -fstrength-reduce - OPTIMIZE = $(OPTIMIZEVM) -ffast-math - - HAVE_VM_COMPILED = true + ifeq ($(ARCH),x86_64) + OPTIMIZEVM = -O3 -fno-omit-frame-pointer \ + -falign-loops=2 -funroll-loops -falign-jumps=2 -falign-functions=2 \ + -fstrength-reduce + OPTIMIZE = $(OPTIMIZEVM) --fast-math + HAVE_VM_COMPILED = true + endif + ifeq ($(ARCH),x86) + OPTIMIZEVM = -O3 -march=i586 -fno-omit-frame-pointer \ + -falign-loops=2 -funroll-loops -falign-jumps=2 -falign-functions=2 \ + -fstrength-reduce + OPTIMIZE = $(OPTIMIZEVM) -ffast-math + HAVE_VM_COMPILED = true + endif SHLIBEXT=dll SHLIBCFLAGS= @@ -509,7 +515,11 @@ ifeq ($(PLATFORM),mingw32) ifneq ($(USE_CURL_DLOPEN),1) ifeq ($(USE_LOCAL_HEADERS),1) CLIENT_CFLAGS += -DCURL_STATICLIB - CLIENT_LIBS += $(LIBSDIR)/win32/libcurl.a + ifeq ($(ARCH),x86_64) + CLIENT_LIBS += $(LIBSDIR)/win64/libcurl.a + else + CLIENT_LIBS += $(LIBSDIR)/win32/libcurl.a + endif else CLIENT_LIBS += $(CURL_LIBS) endif @@ -523,14 +533,22 @@ ifeq ($(PLATFORM),mingw32) ifeq ($(ARCH),x86) # build 32bit BASE_CFLAGS += -m32 + else + BASE_CFLAGS += -m64 endif # libmingw32 must be linked before libSDLmain CLIENT_LIBS += -lmingw32 ifeq ($(USE_LOCAL_HEADERS),1) CLIENT_CFLAGS += -I$(SDLHDIR)/include + ifeq ($(ARCH), x86) CLIENT_LIBS += $(LIBSDIR)/win32/libSDLmain.a \ $(LIBSDIR)/win32/libSDL.dll.a + else + CLIENT_LIBS += $(LIBSDIR)/win64/libSDLmain.a \ + $(LIBSDIR)/win64/libSDL.dll.a \ + $(LIBSDIR)/win64/libSDL.a + endif else CLIENT_CFLAGS += $(SDL_CFLAGS) CLIENT_LIBS += $(SDL_LIBS) diff --git a/code/jpeg-6b/jinclude.h b/code/jpeg-6b/jinclude.h index 1c5515cd..33d2cd5b 100644 --- a/code/jpeg-6b/jinclude.h +++ b/code/jpeg-6b/jinclude.h @@ -14,6 +14,9 @@ * JPEG library. Most applications need only include jpeglib.h. */ +#ifdef __WIN64__ +#include "basetsd.h" +#endif #ifdef _MSC_VER diff --git a/code/jpeg-6b/jmorecfg.h b/code/jpeg-6b/jmorecfg.h index f8020071..ec679eb0 100644 --- a/code/jpeg-6b/jmorecfg.h +++ b/code/jpeg-6b/jmorecfg.h @@ -158,9 +158,11 @@ typedef short INT16; /* INT32 must hold at least signed 32-bit values. */ /* MinGW basetsd.h defines INT32 - don't redefine it */ +#ifndef __WIN64 #if !(defined __MINGW32__ && defined _BASETSD_H) typedef long INT32; #endif +#endif /* Datatype used for image dimensions. The JPEG standard only supports * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore diff --git a/code/qcommon/q_platform.h b/code/qcommon/q_platform.h index 5f498fc5..65f1fb2c 100644 --- a/code/qcommon/q_platform.h +++ b/code/qcommon/q_platform.h @@ -72,9 +72,33 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // for windows fastcall option #define QDECL -//================================================================= WIN32 === +//================================================================= WIN64/32 === -#ifdef _WIN32 +#ifdef __WIN64__ + +#undef QDECL +#define QDECL __cdecl + +#if defined( _MSC_VER ) +#define OS_STRING "win_msvc64" +#elif defined __MINGW64__ +#define OS_STRING "win_mingw64" +#endif + +#define ID_INLINE inline +#define PATH_SEP '\\' + +#if defined( __WIN64__ ) +#define ARCH_STRING "x86_64" +#elif defined _M_ALPHA +#define ARCH_STRING "AXP" +#endif + +#define Q3_LITTLE_ENDIAN + +#define DLL_EXT ".dll" + +#elif __WIN32__ #undef QDECL #define QDECL __cdecl diff --git a/code/qcommon/vm_x86_64.c b/code/qcommon/vm_x86_64.c index 0efc8770..bc79bfa4 100644 --- a/code/qcommon/vm_x86_64.c +++ b/code/qcommon/vm_x86_64.c @@ -23,11 +23,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 #include #include -#include #include #include #include @@ -35,6 +32,19 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include #include +#include + +#ifdef __WIN64__ + #include + #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 + #include + #define VM_X86_64_MMAP + #define CROSSCALL +#endif + //#define DEBUG_VM #ifdef DEBUG_VM @@ -44,8 +54,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); @@ -71,11 +79,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; @@ -231,13 +239,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"); @@ -249,7 +257,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 @@ -339,7 +347,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 @@ -363,7 +371,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; @@ -378,20 +386,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); @@ -430,9 +438,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); } @@ -473,7 +491,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 { @@ -517,7 +535,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; @@ -558,7 +576,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"); @@ -725,7 +743,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 @@ -742,7 +760,7 @@ emit_do_syscall: 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 %%r10"); emit("pop %%r9"); @@ -909,15 +927,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; @@ -934,17 +962,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 } @@ -1034,7 +1064,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" ); diff --git a/code/qcommon/vm_x86_64_assembler.c b/code/qcommon/vm_x86_64_assembler.c index 346680e1..1771284c 100644 --- a/code/qcommon/vm_x86_64_assembler.c +++ b/code/qcommon/vm_x86_64_assembler.c @@ -25,10 +25,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include #include -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -typedef unsigned long u64; +#include + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; static char* out; static unsigned compiledOfs; @@ -77,7 +79,7 @@ static void emit1(unsigned char v) if(fout) writecnt = fwrite(&v, 1, 1, fout); - debug("%02hhx ", v); + debug("%02hx ", v); } else { @@ -282,7 +284,7 @@ static void labelhash_free(void) min = MIN(min, n); max = MAX(max, n); } - printf("total %u, hsize %lu, zero %u, min %u, max %u\n", t, sizeof(labelhash)/sizeof(labelhash[0]), z, min, max); + printf("total %u, hsize %"PRIu64", zero %u, min %u, max %u\n", t, sizeof(labelhash)/sizeof(labelhash[0]), z, min, max); memset(labelhash, 0, sizeof(labelhash)); } @@ -308,7 +310,7 @@ static const char* argtype2str(argtype_t t) static inline int iss8(u64 v) { - return (labs(v) <= 0x80); + return (llabs(v) <= 0x80); //llabs instead of labs required for __WIN64 } static inline int isu8(u64 v) @@ -318,7 +320,7 @@ static inline int isu8(u64 v) static inline int iss16(u64 v) { - return (labs(v) <= 0x8000); + return (llabs(v) <= 0x8000); } static inline int isu16(u64 v) @@ -328,7 +330,7 @@ static inline int isu16(u64 v) static inline int iss32(u64 v) { - return (labs(v) <= 0x80000000); + return (llabs(v) <= 0x80000000); } static inline int isu32(u64 v) @@ -338,7 +340,7 @@ static inline int isu32(u64 v) static void emit_opsingle(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) { - u8 op = (u8)((unsigned long) data); + u8 op = (u8)((uint64_t) data); if(arg1.type != T_NONE || arg2.type != T_NONE) CRAP_INVALID_ARGS; @@ -501,7 +503,7 @@ static void maybe_emit_displacement(arg_t* arg) /* one byte operator with register added to operator */ static void emit_opreg(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) { - u8 op = (u8)((unsigned long) data); + u8 op = (u8)((uint64_t) data); if(arg1.type != T_REGISTER || arg2.type != T_NONE) CRAP_INVALID_ARGS; @@ -754,7 +756,7 @@ static void emit_condjump(const char* mnemonic, arg_t arg1, arg_t arg2, void* da { unsigned off; int disp; - unsigned char opcode = (unsigned char)(((unsigned long)data)&0xFF); + unsigned char opcode = (unsigned char)(((uint64_t)data)&0xFF); if(arg1.type != T_LABEL || arg2.type != T_NONE) crap("%s: argument must be label", mnemonic); @@ -1151,7 +1153,7 @@ static unsigned char nexttok(const char** str, char* label, u64* val) else if(*s >= '0' && *s <= '9') { char* endptr = NULL; - u64 v = strtol(s, &endptr, 0); + u64 v = strtoull(s, &endptr, 0); if(endptr && (endptr-s == 0)) crap("invalid integer %s", s); if(val) *val = v; @@ -1272,7 +1274,7 @@ tok_memory: } break; default: - crap("invalid token %hhu in %s", *(unsigned char*)s, *str); + crap("invalid token %hu in %s", *(unsigned char*)s, *str); break; } diff --git a/code/sys/sys_win32.c b/code/sys/sys_win32.c index 74cf1d19..ce1b4335 100644 --- a/code/sys/sys_win32.c +++ b/code/sys/sys_win32.c @@ -41,6 +41,15 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // Used to determine where to store user-specific files static char homePath[ MAX_OSPATH ] = { 0 }; +#ifdef __WIN64__ +void Sys_SnapVector( float *v ) +{ + v[0] = rint(v[0]); + v[1] = rint(v[1]); + v[2] = rint(v[2]); +} +#endif + /* ================ Sys_DefaultHomePath