File smokin-guns-1.1-x86_64.patch of Package smokin-guns
Index: code/asm/qasm-inline.h
===================================================================
--- /dev/null
+++ code/asm/qasm-inline.h
@@ -0,0 +1,39 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+#ifndef __ASM_INLINE_I386__
+#define __ASM_INLINE_I386__
+
+#include "../qcommon/q_platform.h"
+
+#if idx64
+ #define EAX "%%rax"
+ #define EBX "%%rbx"
+ #define ESP "%%rsp"
+ #define EDI "%%rdi"
+#else
+ #define EAX "%%eax"
+ #define EBX "%%ebx"
+ #define ESP "%%esp"
+ #define EDI "%%edi"
+#endif
+
+#endif
Index: code/asm/ftola.asm
===================================================================
--- /dev/null
+++ code/asm/ftola.asm
@@ -0,0 +1,87 @@
+; ===========================================================================
+; Copyright (C) 2011 Thilo Schulz <thilo@tjps.eu>
+;
+; This file is part of Quake III Arena source code.
+;
+; Quake III Arena source code is free software; you can redistribute it
+; and/or modify it under the terms of the GNU General Public License as
+; published by the Free Software Foundation; either version 2 of the License,
+; or (at your option) any later version.
+;
+; Quake III Arena source code is distributed in the hope that it will be
+; useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Quake III Arena source code; if not, write to the Free Software
+; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+; ===========================================================================
+
+; MASM ftol conversion functions using SSE or FPU
+; assume __cdecl calling convention is being used for x86, __fastcall for x64
+
+IFNDEF idx64
+.model flat, c
+ENDIF
+
+.data
+
+ifndef idx64
+ fpucw WORD 0F7Fh
+endif
+
+.code
+
+IFDEF idx64
+; qftol using SSE
+
+ qftolsse PROC
+ cvttss2si eax, xmm0
+ ret
+ qftolsse ENDP
+
+ qvmftolsse PROC
+ movss xmm0, dword ptr [rdi + rbx * 4]
+ cvttss2si eax, xmm0
+ ret
+ qvmftolsse ENDP
+
+ELSE
+; qftol using FPU
+
+ qftolx87m macro src
+ sub esp, 2
+ fnstcw word ptr [esp]
+ fldcw fpucw
+ fld dword ptr src
+ fistp dword ptr src
+ fldcw [esp]
+ mov eax, src
+ add esp, 2
+ ret
+ endm
+
+ qftolx87 PROC
+ qftolx87m [esp + 6]
+ qftolx87 ENDP
+
+ qvmftolx87 PROC
+ qftolx87m [edi + ebx * 4]
+ qvmftolx87 ENDP
+
+; qftol using SSE
+ qftolsse PROC
+ movss xmm0, dword ptr [esp + 4]
+ cvttss2si eax, xmm0
+ ret
+ qftolsse ENDP
+
+ qvmftolsse PROC
+ movss xmm0, dword ptr [edi + ebx * 4]
+ cvttss2si eax, xmm0
+ ret
+ qvmftolsse ENDP
+ENDIF
+
+end
Index: code/asm/ftola.c
===================================================================
--- /dev/null
+++ code/asm/ftola.c
@@ -0,0 +1,99 @@
+/*
+===========================================================================
+Copyright (C) 2011 Thilo Schulz <thilo@tjps.eu>
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+along with Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#include "qasm-inline.h"
+
+static const unsigned short fpucw = 0x0C7F;
+
+/*
+ * GNU inline asm ftol conversion functions using SSE or FPU
+ */
+
+long qftolsse(float f)
+{
+ long retval;
+
+ __asm__ volatile
+ (
+ "cvttss2si %1, %0\n"
+ : "=r" (retval)
+ : "x" (f)
+ );
+
+ return retval;
+}
+
+int qvmftolsse(void)
+{
+ int retval;
+
+ __asm__ volatile
+ (
+ "movss (" EDI ", " EBX ", 4), %%xmm0\n"
+ "cvttss2si %%xmm0, %0\n"
+ : "=r" (retval)
+ :
+ : "%xmm0"
+ );
+
+ return retval;
+}
+
+long qftolx87(float f)
+{
+ long retval;
+ unsigned short oldcw;
+
+ __asm__ volatile
+ (
+ "fnstcw %2\n"
+ "fldcw %3\n"
+ "flds %1\n"
+ "fistpl %1\n"
+ "fldcw %2\n"
+ "mov %1, %0\n"
+ : "=r" (retval)
+ : "m" (f), "m" (oldcw), "m" (fpucw)
+ );
+
+ return retval;
+}
+
+int qvmftolx87(void)
+{
+ int retval;
+ unsigned short oldcw;
+
+ __asm__ volatile
+ (
+ "fnstcw %1\n"
+ "fldcw %2\n"
+ "flds (" EDI ", " EBX ", 4)\n"
+ "fistpl (" EDI ", " EBX ", 4)\n"
+ "fldcw %1\n"
+ "mov (" EDI ", " EBX ", 4), %0\n"
+ : "=r" (retval)
+ : "m" (oldcw), "m" (fpucw)
+ );
+
+ return retval;
+}
Index: code/asm/qasm.h
===================================================================
--- code/asm/qasm.h.orig
+++ code/asm/qasm.h
@@ -29,7 +29,7 @@ Foundation, Inc., 51 Franklin St, Fifth
.section .note.GNU-stack,"",@progbits
#endif
-#ifdef __ELF__
+#if defined(__ELF__) || defined(__WIN64__)
#define C(label) label
#else
#define C(label) _##label
Index: code/asm/snapvector.asm
===================================================================
--- /dev/null
+++ code/asm/snapvector.asm
@@ -0,0 +1,93 @@
+; ===========================================================================
+; Copyright (C) 2011 Thilo Schulz <thilo@tjps.eu>
+;
+; This file is part of Quake III Arena source code.
+;
+; Quake III Arena source code is free software; you can redistribute it
+; and/or modify it under the terms of the GNU General Public License as
+; published by the Free Software Foundation; either version 2 of the License,
+; or (at your option) any later version.
+;
+; Quake III Arena source code is distributed in the hope that it will be
+; useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Quake III Arena source code; if not, write to the Free Software
+; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+; ===========================================================================
+
+; MASM version of snapvector conversion function using SSE or FPU
+; assume __cdecl calling convention is being used for x86, __fastcall for x64
+;
+; function prototype:
+; void qsnapvector(vec3_t vec)
+
+IFNDEF idx64
+.model flat, c
+ENDIF
+
+.data
+
+ ALIGN 16
+ ssemask DWORD 0FFFFFFFFh, 0FFFFFFFFh, 0FFFFFFFFh, 00000000h
+ ssecw DWORD 00001F80h
+
+IFNDEF idx64
+ fpucw WORD 037Fh
+ENDIF
+
+.code
+
+IFDEF idx64
+; qsnapvector using SSE
+
+ qsnapvectorsse PROC
+ sub rsp, 8
+ movaps xmm1, ssemask ; initialize the mask register
+ movups xmm0, [rcx] ; here is stored our vector. Read 4 values in one go
+ movaps xmm2, xmm0 ; keep a copy of the original data
+ andps xmm0, xmm1 ; set the fourth value to zero in xmm0
+ andnps xmm1, xmm2 ; copy fourth value to xmm1 and set rest to zero
+ cvtps2dq xmm0, xmm0 ; convert 4 single fp to int
+ cvtdq2ps xmm0, xmm0 ; convert 4 int to single fp
+ orps xmm0, xmm1 ; combine all 4 values again
+ movups [rcx], xmm0 ; write 3 rounded and 1 unchanged values back to memory
+ ret
+ qsnapvectorsse ENDP
+
+ELSE
+
+ qsnapvectorsse PROC
+ mov eax, dword ptr 4[esp] ; store address of vector in eax
+ movaps xmm1, ssemask ; initialize the mask register for maskmovdqu
+ movups xmm0, [eax] ; here is stored our vector. Read 4 values in one go
+ movaps xmm2, xmm0 ; keep a copy of the original data
+ andps xmm0, xmm1 ; set the fourth value to zero in xmm0
+ andnps xmm1, xmm2 ; copy fourth value to xmm1 and set rest to zero
+ cvtps2dq xmm0, xmm0 ; convert 4 single fp to int
+ cvtdq2ps xmm0, xmm0 ; convert 4 int to single fp
+ orps xmm0, xmm1 ; combine all 4 values again
+ movups [eax], xmm0 ; write 3 rounded and 1 unchanged values back to memory
+ ret
+ qsnapvectorsse ENDP
+
+ qroundx87 macro src
+ fld dword ptr src
+ fistp dword ptr src
+ fild dword ptr src
+ fstp dword ptr src
+ endm
+
+ qsnapvectorx87 PROC
+ mov eax, dword ptr 4[esp]
+ qroundx87 [eax]
+ qroundx87 4[eax]
+ qroundx87 8[eax]
+ ret
+ qsnapvectorx87 ENDP
+
+ENDIF
+
+end
Index: code/asm/snapvector.c
===================================================================
--- /dev/null
+++ code/asm/snapvector.c
@@ -0,0 +1,73 @@
+/*
+===========================================================================
+Copyright (C) 2011 Thilo Schulz <thilo@tjps.eu>
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#include "qasm-inline.h"
+#include "../qcommon/q_shared.h"
+
+/*
+ * GNU inline asm version of qsnapvector
+ * See MASM snapvector.asm for commentary
+ */
+
+static unsigned char ssemask[16] __attribute__((aligned(16))) =
+{
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00"
+};
+
+void qsnapvectorsse(vec3_t vec)
+{
+ __asm__ volatile
+ (
+ "movaps (%0), %%xmm1\n"
+ "movups (%1), %%xmm0\n"
+ "movaps %%xmm0, %%xmm2\n"
+ "andps %%xmm1, %%xmm0\n"
+ "andnps %%xmm2, %%xmm1\n"
+ "cvtps2dq %%xmm0, %%xmm0\n"
+ "cvtdq2ps %%xmm0, %%xmm0\n"
+ "orps %%xmm1, %%xmm0\n"
+ "movups %%xmm0, (%1)\n"
+ :
+ : "r" (ssemask), "r" (vec)
+ : "memory", "%xmm0", "%xmm1", "%xmm2"
+ );
+
+}
+
+#define QROUNDX87(src) \
+ "flds " src "\n" \
+ "fistps " src "\n" \
+ "filds " src "\n" \
+ "fstps " src "\n"
+
+void qsnapvectorx87(vec3_t vec)
+{
+ __asm__ volatile
+ (
+ QROUNDX87("(%0)")
+ QROUNDX87("4(%0)")
+ QROUNDX87("8(%0)")
+ :
+ : "r" (vec)
+ : "memory"
+ );
+}
Index: code/qcommon/cm_polylib.c
===================================================================
--- code/qcommon/cm_polylib.c.orig
+++ code/qcommon/cm_polylib.c
@@ -273,11 +273,11 @@ CopyWinding
*/
winding_t *CopyWinding (winding_t *w)
{
- unsigned long size;
+ intptr_t size;
winding_t *c;
c = AllocWinding (w->numpoints);
- size = (long)((winding_t *)0)->p[w->numpoints];
+ size = (intptr_t) ((winding_t *)0)->p[w->numpoints];
Com_Memcpy (c, w, size);
return c;
}
Index: code/qcommon/common.c
===================================================================
--- code/qcommon/common.c.orig
+++ code/qcommon/common.c
@@ -109,6 +109,14 @@ cvar_t *com_basegame;
cvar_t *com_homepath;
cvar_t *com_busyWait;
+#if idx64
+ void (*Q_VMftol)(void);
+#elif id386
+ long (QDECL *Q_ftol)(float f);
+ void (QDECL *Q_VMftol)(void);
+ void (QDECL *Q_SnapVector)(vec3_t vec);
+#endif
+
// com_speeds times
int time_game;
int time_frontend; // renderer frontend time
@@ -2606,6 +2614,53 @@ static void Com_DetectAltivec(void)
/*
=================
+Com_DetectSSE
+Find out whether we have SSE support for Q_ftol function
+=================
+*/
+
+#if id386 || idx64
+
+static void Com_DetectSSE(void)
+{
+#if !idx64
+ cpuFeatures_t feat;
+
+ feat = Sys_GetProcessorFeatures();
+
+ if(feat & CF_SSE)
+ {
+ if(feat & CF_SSE2)
+ Q_SnapVector = qsnapvectorsse;
+ else
+ Q_SnapVector = qsnapvectorx87;
+
+ Q_ftol = qftolsse;
+#endif
+ Q_VMftol = qvmftolsse;
+
+ Com_Printf("Have SSE support\n");
+#if !idx64
+ }
+ else
+ {
+ Q_ftol = qftolx87;
+ Q_VMftol = qvmftolx87;
+ Q_SnapVector = qsnapvectorx87;
+
+ Com_Printf("No SSE support on this machine\n");
+ }
+#endif
+}
+
+#else
+
+#define Com_DetectSSE()
+
+#endif
+
+/*
+=================
Com_InitRand
Seed the random number generator, if possible with an OS supplied random seed.
=================
@@ -2654,6 +2709,8 @@ void Com_Init( char *commandLine ) {
// Swap_Init ();
Cbuf_Init ();
+ Com_DetectSSE();
+
// override anything from the config files with command line args
Com_StartupVariable( NULL );
Index: code/qcommon/q_platform.h
===================================================================
--- code/qcommon/q_platform.h.orig
+++ code/qcommon/q_platform.h
@@ -24,6 +24,8 @@ Foundation, Inc., 51 Franklin St, Fifth
#define __Q_PLATFORM_H
// this is for determining if we have an asm version of a C function
+#define idx64 0
+
#ifdef Q3_VM
#define id386 0
@@ -76,6 +78,9 @@ Foundation, Inc., 51 Franklin St, Fifth
#if defined(_WIN64) || defined(__WIN64__)
+#undef idx64
+#define idx64 1
+
#undef QDECL
#define QDECL __cdecl
@@ -85,7 +90,7 @@ Foundation, Inc., 51 Franklin St, Fifth
#define OS_STRING "win_mingw64"
#endif
-#define ID_INLINE inline
+#define ID_INLINE __inline
#define PATH_SEP '\\'
#if defined( __WIN64__ )
@@ -144,6 +149,8 @@ Foundation, Inc., 51 Franklin St, Fifth
#define ARCH_STRING "i386"
#define Q3_LITTLE_ENDIAN
#elif defined __x86_64__
+#undef idx64
+#define idx64 1
#define ARCH_STRING "x86_64"
#define Q3_LITTLE_ENDIAN
#endif
@@ -170,6 +177,8 @@ Foundation, Inc., 51 Franklin St, Fifth
#if defined __i386__
#define ARCH_STRING "i386"
#elif defined __x86_64__
+#undef idx64
+#define idx64 1
#define ARCH_STRING "x86_64"
#elif defined __powerpc64__
#define ARCH_STRING "ppc64"
@@ -232,6 +241,8 @@ Foundation, Inc., 51 Franklin St, Fifth
#ifdef __i386__
#define ARCH_STRING "i386"
#elif defined __amd64__
+#undef idx64
+#define idx64 1
#define ARCH_STRING "amd64"
#elif defined __axp__
#define ARCH_STRING "alpha"
Index: code/qcommon/q_shared.h
===================================================================
--- code/qcommon/q_shared.h.orig
+++ code/qcommon/q_shared.h
@@ -500,6 +500,58 @@ extern vec3_t axisDefault[3];
#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
+int Q_isnan(float x);
+
+#if idx64
+ extern long qftolsse(float f);
+ extern void qvmftolsse(void);
+ extern void qsnapvectorsse(vec3_t vec);
+
+ #define Q_ftol qftolsse
+ #define Q_SnapVector qsnapvectorsse
+
+ extern void (*Q_VMftol)(void);
+#elif id386
+ extern long QDECL qftolx87(float f);
+ extern long QDECL qftolsse(float f);
+ extern void QDECL qvmftolx87(void);
+ extern void QDECL qvmftolsse(void);
+ extern void QDECL qsnapvectorx87(vec3_t vec);
+ extern void QDECL qsnapvectorsse(vec3_t vec);
+
+ extern long (QDECL *Q_ftol)(float f);
+ extern void (QDECL *Q_VMftol)(void);
+ extern void (QDECL *Q_SnapVector)(vec3_t vec);
+#else
+ #define Q_ftol(f) lrintf((f))
+ #define Q_SnapVector(vec)\
+ do\
+ {\
+ vec3_t *temp = (vec);\
+ \
+ (*temp)[0] = round((*temp)[0]);\
+ (*temp)[1] = round((*temp)[1]);\
+ (*temp)[2] = round((*temp)[2]);\
+ } while(0)
+#endif
+/*
+// if your system does not have lrintf() and round() you can try this block. Please also open a bug report at bugzilla.icculus.org
+// or write a mail to the ioq3 mailing list.
+#else
+ #define Q_ftol(v) ((long) (v))
+ #define Q_round(v) do { if((v) < 0) (v) -= 0.5f; else (v) += 0.5f; (v) = Q_ftol((v)); } while(0)
+ #define Q_SnapVector(vec) \
+ do\
+ {\
+ vec3_t *temp = (vec);\
+ \
+ Q_round((*temp)[0]);\
+ Q_round((*temp)[1]);\
+ Q_round((*temp)[2]);\
+ } while(0)
+#endif
+*/
+
#if idppc
static ID_INLINE float Q_rsqrt( float number ) {
@@ -736,8 +788,6 @@ void RotateVectorAroundVector( vec3_t or
void MatrixMultiply(float in1[3][3], float in2[3][3], float out[3][3]);
void AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
void PerpendicularVector( vec3_t dst, const vec3_t src );
-int Q_isnan( float x );
-
#ifndef MAX
#define MAX(x,y) ((x)>(y)?(x):(y))
Index: code/qcommon/vm_interpreted.c
===================================================================
--- code/qcommon/vm_interpreted.c.orig
+++ code/qcommon/vm_interpreted.c
@@ -193,9 +193,8 @@ void VM_PrepareInterpreter( vm_t *vm, vm
op = (int)code[ byte_pc ];
codeBase[int_pc] = op;
- if ( byte_pc > header->codeLength ) {
- Com_Error( ERR_FATAL, "VM_PrepareInterpreter: pc > header->codeLength" );
- }
+ if(byte_pc > header->codeLength)
+ Com_Error(ERR_DROP, "VM_PrepareInterpreter: pc > header->codeLength");
byte_pc++;
int_pc++;
@@ -266,6 +265,9 @@ void VM_PrepareInterpreter( vm_t *vm, vm
case OP_LEF:
case OP_GTF:
case OP_GEF:
+ if(codeBase[int_pc] < 0 || codeBase[int_pc] > vm->instructionCount)
+ Com_Error(ERR_DROP, "VM_PrepareInterpreter: Jump to invalid instruction number");
+
// codeBase[pc] is the instruction index. Convert that into an offset into
//the int-aligned codeBase[] by the lookup table.
codeBase[int_pc] = vm->instructionPointers[codeBase[int_pc]];
@@ -313,11 +315,12 @@ locals from sp
==============
*/
-#define DEBUGSTR va("%s%i", VM_Indent(vm), opStack-stack )
+#define DEBUGSTR va("%s%i", VM_Indent(vm), opStackOfs)
int VM_CallInterpreted( vm_t *vm, int *args ) {
- int stack[OPSTACK_SIZE];
- int *opStack;
+ byte stack[OPSTACK_SIZE + 15];
+ register int *opStack;
+ register uint8_t opStackOfs;
int programCounter;
int programStack;
int stackOnEntry;
@@ -346,10 +349,6 @@ int VM_CallInterpreted( vm_t *vm, int *a
codeImage = (int *)vm->codeBase;
dataMask = vm->dataMask;
- // leave a free spot at start of stack so
- // that as long as opStack is valid, opStack-1 will
- // not corrupt anything
- opStack = stack;
programCounter = 0;
programStack -= 48;
@@ -369,6 +368,13 @@ int VM_CallInterpreted( vm_t *vm, int *a
VM_Debug(0);
+ // leave a free spot at start of stack so
+ // that as long as opStack is valid, opStack-1 will
+ // not corrupt anything
+ opStack = PADP(stack, 16);
+ *opStack = 0xDEADBEEF;
+ opStackOfs = 0;
+
// vm_debugLevel=2;
// main interpreter loop, will exit when a LEAVE instruction
// grabs the -1 program counter
@@ -380,27 +386,23 @@ int VM_CallInterpreted( vm_t *vm, int *a
// unsigned int r2;
nextInstruction:
- r0 = ((int *)opStack)[0];
- r1 = ((int *)opStack)[-1];
+ r0 = opStack[opStackOfs];
+ r1 = opStack[(uint8_t) (opStackOfs - 1)];
nextInstruction2:
#ifdef DEBUG_VM
if ( (unsigned)programCounter >= vm->codeLength ) {
Com_Error( ERR_DROP, "VM pc out of range" );
- }
-
- if ( opStack < stack ) {
- Com_Error( ERR_DROP, "VM opStack underflow" );
- }
- if ( opStack >= stack+OPSTACK_SIZE ) {
- Com_Error( ERR_DROP, "VM opStack overflow" );
+ return 0;
}
if ( programStack <= vm->stackBottom ) {
Com_Error( ERR_DROP, "VM stack overflow" );
+ return 0;
}
if ( programStack & 3 ) {
Com_Error( ERR_DROP, "VM program stack misaligned" );
+ return 0;
}
if ( vm_debugLevel > 1 ) {
@@ -414,79 +416,67 @@ nextInstruction2:
#ifdef DEBUG_VM
default:
Com_Error( ERR_DROP, "Bad VM instruction" ); // this should be scanned on load!
+ return 0;
#endif
case OP_BREAK:
vm->breakCount++;
goto nextInstruction2;
case OP_CONST:
- opStack++;
+ opStackOfs++;
r1 = r0;
- r0 = *opStack = r2;
+ r0 = opStack[opStackOfs] = r2;
programCounter += 1;
goto nextInstruction2;
case OP_LOCAL:
- opStack++;
+ opStackOfs++;
r1 = r0;
- r0 = *opStack = r2+programStack;
+ r0 = opStack[opStackOfs] = r2+programStack;
programCounter += 1;
goto nextInstruction2;
case OP_LOAD4:
#ifdef DEBUG_VM
- if ( *opStack & 3 ) {
+ if(opStack[opStackOfs] & 3)
+ {
Com_Error( ERR_DROP, "OP_LOAD4 misaligned" );
+ return 0;
}
#endif
- r0 = *opStack = *(int *)&image[ r0&dataMask&~3 ];
+ r0 = opStack[opStackOfs] = *(int *) &image[r0 & dataMask & ~3 ];
goto nextInstruction2;
case OP_LOAD2:
- r0 = *opStack = *(unsigned short *)&image[ r0&dataMask&~1 ];
+ r0 = opStack[opStackOfs] = *(unsigned short *)&image[ r0&dataMask&~1 ];
goto nextInstruction2;
case OP_LOAD1:
- r0 = *opStack = image[ r0&dataMask ];
+ r0 = opStack[opStackOfs] = image[ r0&dataMask ];
goto nextInstruction2;
case OP_STORE4:
*(int *)&image[ r1&(dataMask & ~3) ] = r0;
- opStack -= 2;
+ opStackOfs -= 2;
goto nextInstruction;
case OP_STORE2:
*(short *)&image[ r1&(dataMask & ~1) ] = r0;
- opStack -= 2;
+ opStackOfs -= 2;
goto nextInstruction;
case OP_STORE1:
image[ r1&dataMask ] = r0;
- opStack -= 2;
+ opStackOfs -= 2;
goto nextInstruction;
case OP_ARG:
// single byte offset from programStack
*(int *)&image[ (codeImage[programCounter] + programStack)&dataMask&~3 ] = r0;
- opStack--;
+ opStackOfs--;
programCounter += 1;
goto nextInstruction;
case OP_BLOCK_COPY:
- {
- int *src, *dest;
- int count, srci, desti;
-
- count = r2;
- // MrE: copy range check
- srci = r0 & dataMask;
- desti = r1 & dataMask;
- count = ((srci + count) & dataMask) - srci;
- count = ((desti + count) & dataMask) - desti;
-
- src = (int *)&image[ srci ];
- dest = (int *)&image[ desti ];
-
- memcpy(dest, src, count);
- programCounter += 1;
- opStack -= 2;
- }
+ VM_BlockCopy(r1, r0, r2);
+ programCounter += 1;
+ opStackOfs -= 2;
goto nextInstruction;
case OP_CALL:
@@ -495,7 +485,7 @@ nextInstruction2:
// jump to the location on the stack
programCounter = r0;
- opStack--;
+ opStackOfs--;
if ( programCounter < 0 ) {
// system call
int r;
@@ -540,8 +530,8 @@ nextInstruction2:
#endif
// save return value
- opStack++;
- *opStack = r;
+ opStackOfs++;
+ opStack[opStackOfs] = r;
programCounter = *(int *)&image[ programStack ];
// vm->callLevel = temp;
#ifdef DEBUG_VM
@@ -551,6 +541,7 @@ nextInstruction2:
#endif
} else if ( (unsigned)programCounter >= vm->instructionCount ) {
Com_Error( ERR_DROP, "VM program counter out of range in OP_CALL" );
+ return 0;
} else {
programCounter = vm->instructionPointers[ programCounter ];
}
@@ -558,10 +549,10 @@ nextInstruction2:
// push and pop are only needed for discarded or bad function return values
case OP_PUSH:
- opStack++;
+ opStackOfs++;
goto nextInstruction;
case OP_POP:
- opStack--;
+ opStackOfs--;
goto nextInstruction;
case OP_ENTER:
@@ -608,6 +599,7 @@ nextInstruction2:
goto done;
} else if ( (unsigned)programCounter >= vm->codeLength ) {
Com_Error( ERR_DROP, "VM program counter out of range in OP_LEAVE" );
+ return 0;
}
goto nextInstruction;
@@ -619,15 +611,18 @@ nextInstruction2:
case OP_JUMP:
if ( (unsigned)r0 >= vm->instructionCount )
+ {
Com_Error( ERR_DROP, "VM program counter out of range in OP_JUMP" );
+ return 0;
+ }
programCounter = vm->instructionPointers[ r0 ];
- opStack--;
+ opStackOfs--;
goto nextInstruction;
case OP_EQ:
- opStack -= 2;
+ opStackOfs -= 2;
if ( r1 == r0 ) {
programCounter = r2; //vm->instructionPointers[r2];
goto nextInstruction;
@@ -637,7 +632,7 @@ nextInstruction2:
}
case OP_NE:
- opStack -= 2;
+ opStackOfs -= 2;
if ( r1 != r0 ) {
programCounter = r2; //vm->instructionPointers[r2];
goto nextInstruction;
@@ -647,7 +642,7 @@ nextInstruction2:
}
case OP_LTI:
- opStack -= 2;
+ opStackOfs -= 2;
if ( r1 < r0 ) {
programCounter = r2; //vm->instructionPointers[r2];
goto nextInstruction;
@@ -657,7 +652,7 @@ nextInstruction2:
}
case OP_LEI:
- opStack -= 2;
+ opStackOfs -= 2;
if ( r1 <= r0 ) {
programCounter = r2; //vm->instructionPointers[r2];
goto nextInstruction;
@@ -667,7 +662,7 @@ nextInstruction2:
}
case OP_GTI:
- opStack -= 2;
+ opStackOfs -= 2;
if ( r1 > r0 ) {
programCounter = r2; //vm->instructionPointers[r2];
goto nextInstruction;
@@ -677,7 +672,7 @@ nextInstruction2:
}
case OP_GEI:
- opStack -= 2;
+ opStackOfs -= 2;
if ( r1 >= r0 ) {
programCounter = r2; //vm->instructionPointers[r2];
goto nextInstruction;
@@ -687,7 +682,7 @@ nextInstruction2:
}
case OP_LTU:
- opStack -= 2;
+ opStackOfs -= 2;
if ( ((unsigned)r1) < ((unsigned)r0) ) {
programCounter = r2; //vm->instructionPointers[r2];
goto nextInstruction;
@@ -697,7 +692,7 @@ nextInstruction2:
}
case OP_LEU:
- opStack -= 2;
+ opStackOfs -= 2;
if ( ((unsigned)r1) <= ((unsigned)r0) ) {
programCounter = r2; //vm->instructionPointers[r2];
goto nextInstruction;
@@ -707,7 +702,7 @@ nextInstruction2:
}
case OP_GTU:
- opStack -= 2;
+ opStackOfs -= 2;
if ( ((unsigned)r1) > ((unsigned)r0) ) {
programCounter = r2; //vm->instructionPointers[r2];
goto nextInstruction;
@@ -717,7 +712,7 @@ nextInstruction2:
}
case OP_GEU:
- opStack -= 2;
+ opStackOfs -= 2;
if ( ((unsigned)r1) >= ((unsigned)r0) ) {
programCounter = r2; //vm->instructionPointers[r2];
goto nextInstruction;
@@ -727,68 +722,74 @@ nextInstruction2:
}
case OP_EQF:
- if ( ((float *)opStack)[-1] == *(float *)opStack ) {
+ opStackOfs -= 2;
+
+ if(((float *) opStack)[(uint8_t) (opStackOfs + 1)] == ((float *) opStack)[(uint8_t) (opStackOfs + 2)])
+ {
programCounter = r2; //vm->instructionPointers[r2];
- opStack -= 2;
goto nextInstruction;
} else {
programCounter += 1;
- opStack -= 2;
goto nextInstruction;
}
case OP_NEF:
- if ( ((float *)opStack)[-1] != *(float *)opStack ) {
+ opStackOfs -= 2;
+
+ if(((float *) opStack)[(uint8_t) (opStackOfs + 1)] != ((float *) opStack)[(uint8_t) (opStackOfs + 2)])
+ {
programCounter = r2; //vm->instructionPointers[r2];
- opStack -= 2;
goto nextInstruction;
} else {
programCounter += 1;
- opStack -= 2;
goto nextInstruction;
}
case OP_LTF:
- if ( ((float *)opStack)[-1] < *(float *)opStack ) {
+ opStackOfs -= 2;
+
+ if(((float *) opStack)[(uint8_t) (opStackOfs + 1)] < ((float *) opStack)[(uint8_t) (opStackOfs + 2)])
+ {
programCounter = r2; //vm->instructionPointers[r2];
- opStack -= 2;
goto nextInstruction;
} else {
programCounter += 1;
- opStack -= 2;
goto nextInstruction;
}
case OP_LEF:
- if ( ((float *)opStack)[-1] <= *(float *)opStack ) {
+ opStackOfs -= 2;
+
+ if(((float *) opStack)[(uint8_t) ((uint8_t) (opStackOfs + 1))] <= ((float *) opStack)[(uint8_t) ((uint8_t) (opStackOfs + 2))])
+ {
programCounter = r2; //vm->instructionPointers[r2];
- opStack -= 2;
goto nextInstruction;
} else {
programCounter += 1;
- opStack -= 2;
goto nextInstruction;
}
case OP_GTF:
- if ( ((float *)opStack)[-1] > *(float *)opStack ) {
+ opStackOfs -= 2;
+
+ if(((float *) opStack)[(uint8_t) (opStackOfs + 1)] > ((float *) opStack)[(uint8_t) (opStackOfs + 2)])
+ {
programCounter = r2; //vm->instructionPointers[r2];
- opStack -= 2;
goto nextInstruction;
} else {
programCounter += 1;
- opStack -= 2;
goto nextInstruction;
}
case OP_GEF:
- if ( ((float *)opStack)[-1] >= *(float *)opStack ) {
+ opStackOfs -= 2;
+
+ if(((float *) opStack)[(uint8_t) (opStackOfs + 1)] >= ((float *) opStack)[(uint8_t) (opStackOfs + 2)])
+ {
programCounter = r2; //vm->instructionPointers[r2];
- opStack -= 2;
goto nextInstruction;
} else {
programCounter += 1;
- opStack -= 2;
goto nextInstruction;
}
@@ -796,101 +797,101 @@ nextInstruction2:
//===================================================================
case OP_NEGI:
- *opStack = -r0;
+ opStack[opStackOfs] = -r0;
goto nextInstruction;
case OP_ADD:
- opStack[-1] = r1 + r0;
- opStack--;
+ opStackOfs--;
+ opStack[opStackOfs] = r1 + r0;
goto nextInstruction;
case OP_SUB:
- opStack[-1] = r1 - r0;
- opStack--;
+ opStackOfs--;
+ opStack[opStackOfs] = r1 - r0;
goto nextInstruction;
case OP_DIVI:
- opStack[-1] = r1 / r0;
- opStack--;
+ opStackOfs--;
+ opStack[opStackOfs] = r1 / r0;
goto nextInstruction;
case OP_DIVU:
- opStack[-1] = ((unsigned)r1) / ((unsigned)r0);
- opStack--;
+ opStackOfs--;
+ opStack[opStackOfs] = ((unsigned) r1) / ((unsigned) r0);
goto nextInstruction;
case OP_MODI:
- opStack[-1] = r1 % r0;
- opStack--;
+ opStackOfs--;
+ opStack[opStackOfs] = r1 % r0;
goto nextInstruction;
case OP_MODU:
- opStack[-1] = ((unsigned)r1) % (unsigned)r0;
- opStack--;
+ opStackOfs--;
+ opStack[opStackOfs] = ((unsigned) r1) % ((unsigned) r0);
goto nextInstruction;
case OP_MULI:
- opStack[-1] = r1 * r0;
- opStack--;
+ opStackOfs--;
+ opStack[opStackOfs] = r1 * r0;
goto nextInstruction;
case OP_MULU:
- opStack[-1] = ((unsigned)r1) * ((unsigned)r0);
- opStack--;
+ opStackOfs--;
+ opStack[opStackOfs] = ((unsigned) r1) * ((unsigned) r0);
goto nextInstruction;
case OP_BAND:
- opStack[-1] = ((unsigned)r1) & ((unsigned)r0);
- opStack--;
+ opStackOfs--;
+ opStack[opStackOfs] = ((unsigned) r1) & ((unsigned) r0);
goto nextInstruction;
case OP_BOR:
- opStack[-1] = ((unsigned)r1) | ((unsigned)r0);
- opStack--;
+ opStackOfs--;
+ opStack[opStackOfs] = ((unsigned) r1) | ((unsigned) r0);
goto nextInstruction;
case OP_BXOR:
- opStack[-1] = ((unsigned)r1) ^ ((unsigned)r0);
- opStack--;
+ opStackOfs--;
+ opStack[opStackOfs] = ((unsigned) r1) ^ ((unsigned) r0);
goto nextInstruction;
case OP_BCOM:
- *opStack = ~ ((unsigned)r0);
+ opStack[opStackOfs] = ~((unsigned) r0);
goto nextInstruction;
case OP_LSH:
- opStack[-1] = r1 << r0;
- opStack--;
+ opStackOfs--;
+ opStack[opStackOfs] = r1 << r0;
goto nextInstruction;
case OP_RSHI:
- opStack[-1] = r1 >> r0;
- opStack--;
+ opStackOfs--;
+ opStack[opStackOfs] = r1 >> r0;
goto nextInstruction;
case OP_RSHU:
- opStack[-1] = ((unsigned)r1) >> r0;
- opStack--;
+ opStackOfs--;
+ opStack[opStackOfs] = ((unsigned) r1) >> r0;
goto nextInstruction;
case OP_NEGF:
- *(float *)opStack = -*(float *)opStack;
+ ((float *) opStack)[opStackOfs] = -((float *) opStack)[opStackOfs];
goto nextInstruction;
case OP_ADDF:
- *(float *)(opStack-1) = *(float *)(opStack-1) + *(float *)opStack;
- opStack--;
+ opStackOfs--;
+ ((float *) opStack)[opStackOfs] = ((float *) opStack)[opStackOfs] + ((float *) opStack)[(uint8_t) (opStackOfs + 1)];
goto nextInstruction;
case OP_SUBF:
- *(float *)(opStack-1) = *(float *)(opStack-1) - *(float *)opStack;
- opStack--;
+ opStackOfs--;
+ ((float *) opStack)[opStackOfs] = ((float *) opStack)[opStackOfs] - ((float *) opStack)[(uint8_t) (opStackOfs + 1)];
goto nextInstruction;
case OP_DIVF:
- *(float *)(opStack-1) = *(float *)(opStack-1) / *(float *)opStack;
- opStack--;
+ opStackOfs--;
+ ((float *) opStack)[opStackOfs] = ((float *) opStack)[opStackOfs] / ((float *) opStack)[(uint8_t) (opStackOfs + 1)];
goto nextInstruction;
case OP_MULF:
- *(float *)(opStack-1) = *(float *)(opStack-1) * *(float *)opStack;
- opStack--;
+ opStackOfs--;
+ ((float *) opStack)[opStackOfs] = ((float *) opStack)[opStackOfs] * ((float *) opStack)[(uint8_t) (opStackOfs + 1)];
goto nextInstruction;
case OP_CVIF:
- *(float *)opStack = (float)*opStack;
+ ((float *) opStack)[opStackOfs] = (float) opStack[opStackOfs];
goto nextInstruction;
case OP_CVFI:
- *opStack = (int) *(float *)opStack;
+ opStack[opStackOfs] = Q_ftol(((float *) opStack)[opStackOfs]);
goto nextInstruction;
case OP_SEX8:
- *opStack = (signed char)*opStack;
+ opStack[opStackOfs] = (signed char) opStack[opStackOfs];
goto nextInstruction;
case OP_SEX16:
- *opStack = (short)*opStack;
+ opStack[opStackOfs] = (short) opStack[opStackOfs];
goto nextInstruction;
}
}
@@ -898,12 +899,11 @@ nextInstruction2:
done:
vm->currentlyInterpreting = qfalse;
- if ( opStack != &stack[1] ) {
- Com_Error( ERR_DROP, "Interpreter error: opStack = %ld", (long int) (opStack - stack) );
- }
+ if (opStackOfs != 1 || *opStack != 0xDEADBEEF)
+ Com_Error(ERR_DROP, "Interpreter error: opStack[0] = %X, opStackOfs = %d", opStack[0], opStackOfs);
vm->programStack = stackOnEntry;
// return the result
- return *opStack;
+ return opStack[opStackOfs];
}
Index: code/qcommon/vm.c
===================================================================
--- code/qcommon/vm.c.orig
+++ code/qcommon/vm.c
@@ -378,15 +378,20 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboole
// load the image
Com_sprintf( filename, sizeof(filename), "vm/%s.qvm", vm->name );
Com_Printf( "Loading vm file %s...\n", filename );
- length = FS_ReadFile( filename, &header.v );
+
+ length = FS_ReadFileDir(filename, vm->searchPath, &header.v);
+
if ( !header.h ) {
Com_Printf( "Failed.\n" );
VM_Free( vm );
+
+ Com_Printf(S_COLOR_YELLOW "Warning: Couldn't open VM file %s\n", filename);
+
return NULL;
}
// show where the qvm was loaded from
- Cmd_ExecuteString( va( "which %s\n", filename ) );
+ FS_Which(filename, vm->searchPath);
if( LittleLong( header.h->vmMagic ) == VM_MAGIC_VER2 ) {
Com_Printf( "...which has vmMagic VM_MAGIC_VER2\n" );
@@ -401,9 +406,13 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboole
|| header.h->bssLength < 0
|| header.h->dataLength < 0
|| header.h->litLength < 0
- || header.h->codeLength <= 0 ) {
- VM_Free( vm );
- Com_Error( ERR_FATAL, "%s has bad header", filename );
+ || header.h->codeLength <= 0 )
+ {
+ VM_Free(vm);
+ FS_FreeFile(header.v);
+
+ Com_Printf(S_COLOR_YELLOW "Warning: %s has bad header\n", filename);
+ return NULL;
}
} else if( LittleLong( header.h->vmMagic ) == VM_MAGIC ) {
// byte swap the header
@@ -416,14 +425,21 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboole
if ( header.h->bssLength < 0
|| header.h->dataLength < 0
|| header.h->litLength < 0
- || header.h->codeLength <= 0 ) {
- VM_Free( vm );
- Com_Error( ERR_FATAL, "%s has bad header", filename );
+ || header.h->codeLength <= 0 )
+ {
+ VM_Free(vm);
+ FS_FreeFile(header.v);
+
+ Com_Printf(S_COLOR_YELLOW "Warning: %s has bad header\n", filename);
+ return NULL;
}
} else {
VM_Free( vm );
- Com_Error( ERR_FATAL, "%s does not have a recognisable "
- "magic number in its header", filename );
+ FS_FreeFile(header.v);
+
+ Com_Printf(S_COLOR_YELLOW "Warning: %s does not have a recognisable "
+ "magic number in its header\n", filename);
+ return NULL;
}
// round up to next power of 2 so all data operations can
@@ -525,7 +541,9 @@ vm_t *VM_Create( const char *module, int
vmInterpret_t interpret ) {
vm_t *vm;
vmHeader_t *header;
- int i, remaining;
+ int i, remaining, retval;
+ char filename[MAX_OSPATH];
+ void *startSearch = NULL;
if ( !module || !module[0] || !systemCalls ) {
Com_Error( ERR_FATAL, "VM_Create: bad parms" );
@@ -554,29 +572,45 @@ vm_t *VM_Create( const char *module, int
vm = &vmTable[i];
- Q_strncpyz( vm->name, module, sizeof( vm->name ) );
- vm->systemCall = systemCalls;
-
- if ( interpret == VMI_NATIVE ) {
- // try to load as a system dll
- Com_Printf( "Loading dll file %s.\n", vm->name );
- vm->dllHandle = Sys_LoadDll( module, &vm->entryPoint, VM_DllSyscall );
- if ( vm->dllHandle ) {
- return vm;
- }
-
- Com_Printf( "Failed to load dll, looking for qvm.\n" );
- interpret = VMI_COMPILED;
- }
+ Q_strncpyz(vm->name, module, sizeof(vm->name));
- // load the image
- if( !( header = VM_LoadQVM( vm, qtrue ) ) ) {
+ do
+ {
+ retval = FS_FindVM(&startSearch, filename, sizeof(filename), module, (interpret == VMI_NATIVE));
+
+ if(retval == VMI_NATIVE)
+ {
+ Com_Printf("Try loading dll file %s\n", filename);
+
+ vm->dllHandle = Sys_LoadDll(filename, &vm->entryPoint, VM_DllSyscall);
+
+ if(vm->dllHandle)
+ {
+ vm->systemCall = systemCalls;
+ return vm;
+ }
+
+ Com_Printf("Failed loading dll, trying next\n");
+ }
+ else if(retval == VMI_COMPILED)
+ {
+ vm->searchPath = startSearch;
+ if((header = VM_LoadQVM(vm, qtrue)))
+ break;
+
+ // VM_Free overwrites the name on failed load
+ Q_strncpyz(vm->name, module, sizeof(vm->name));
+ }
+ } while(retval >= 0);
+
+ if(retval < 0)
return NULL;
- }
+
+ vm->systemCall = systemCalls;
// allocate space for the jump targets, which will be filled in by the compile/prep functions
vm->instructionCount = header->instructionCount;
- vm->instructionPointers = Hunk_Alloc( vm->instructionCount*4, h_high );
+ vm->instructionPointers = Hunk_Alloc(vm->instructionCount * sizeof(*vm->instructionPointers), h_high);
// copy or compile the instructions
vm->codeLength = header->codeLength;
@@ -589,7 +623,8 @@ vm_t *VM_Create( const char *module, int
interpret = VMI_BYTECODE;
}
#else
- if ( interpret >= VMI_COMPILED ) {
+ if(interpret != VMI_BYTECODE)
+ {
vm->compiled = qtrue;
VM_Compile( vm, header );
}
@@ -915,3 +950,25 @@ void VM_LogSyscalls( int *args ) {
fprintf(f, "%i: %p (%i) = %i %i %i %i\n", callnum, (void*)(args - (int *)currentVM->dataBase),
args[0], args[1], args[2], args[3], args[4] );
}
+
+/*
+=================
+VM_BlockCopy
+Executes a block copy operation within currentVM data space
+=================
+*/
+
+void VM_BlockCopy(unsigned int dest, unsigned int src, size_t n)
+{
+ unsigned int dataMask = currentVM->dataMask;
+
+ if ((dest & dataMask) != dest
+ || (src & dataMask) != src
+ || ((dest + n) & dataMask) != dest + n
+ || ((src + n) & dataMask) != src + n)
+ {
+ Com_Error(ERR_DROP, "OP_BLOCK_COPY out of range!");
+ }
+
+ Com_Memcpy(currentVM->dataBase + dest, currentVM->dataBase + src, n);
+}
Index: code/qcommon/files.c
===================================================================
--- code/qcommon/files.c.orig
+++ code/qcommon/files.c
@@ -218,6 +218,7 @@ typedef struct fileInPack_s {
} fileInPack_t;
typedef struct {
+ char pakPathname[MAX_OSPATH]; // c:\quake3\baseq3
char pakFilename[MAX_OSPATH]; // c:\quake3\baseq3\pak0.pk3
char pakBasename[MAX_OSPATH]; // pak0
char pakGamename[MAX_OSPATH]; // baseq3
@@ -233,6 +234,7 @@ typedef struct {
typedef struct {
char path[MAX_OSPATH]; // c:\quake3
+ char fullpath[MAX_OSPATH]; // c:\quake3\baseq3
char gamedir[MAX_OSPATH]; // baseq3
} directory_t;
@@ -432,7 +434,7 @@ static fileHandle_t FS_HandleForFile(voi
}
static FILE *FS_FileForHandle( fileHandle_t f ) {
- if ( f < 0 || f > MAX_FILE_HANDLES ) {
+ if ( f < 1 || f > MAX_FILE_HANDLES ) {
Com_Error( ERR_DROP, "FS_FileForHandle: out of range" );
}
if (fsh[f].zipFile == qtrue) {
@@ -454,6 +456,25 @@ void FS_ForceFlush( fileHandle_t f ) {
/*
================
+FS_fplength
+================
+*/
+
+long FS_fplength(FILE *h)
+{
+ long pos;
+ long end;
+
+ pos = ftell(h);
+ fseek(h, 0, SEEK_END);
+ end = ftell(h);
+ fseek(h, pos, SEEK_SET);
+
+ return end;
+}
+
+/*
+================
FS_filelength
If this is called on a non-unique FILE (from a pak file),
@@ -461,18 +482,16 @@ it will return the size of the pak file,
size of the file.
================
*/
-int FS_filelength( fileHandle_t f ) {
- int pos;
- int end;
- FILE* h;
+long FS_filelength(fileHandle_t f)
+{
+ FILE *h;
h = FS_FileForHandle(f);
- pos = ftell (h);
- fseek (h, 0, SEEK_END);
- end = ftell (h);
- fseek (h, pos, SEEK_SET);
-
- return end;
+
+ if(h == NULL)
+ return -1;
+ else
+ return FS_fplength(h);
}
/*
@@ -580,7 +599,7 @@ static void FS_CheckFilenameIsNotExecuta
if( !Q_stricmp( COM_GetExtension( filename ), DLL_EXT ) )
{
Com_Error( ERR_FATAL, "%s: Not allowed to manipulate '%s' due "
- "to %s extension\n", function, filename, DLL_EXT );
+ "to %s extension", function, filename, DLL_EXT );
}
}
@@ -611,6 +630,28 @@ void FS_HomeRemove( const char *homePath
/*
================
+FS_FileInPathExists
+
+Tests if path and file exists
+================
+*/
+qboolean FS_FileInPathExists(const char *testpath)
+{
+ FILE *filep;
+
+ filep = fopen(testpath, "rb");
+
+ if(filep)
+ {
+ fclose(filep);
+ return qtrue;
+ }
+
+ return qfalse;
+}
+
+/*
+================
FS_FileExists
Tests if the file exists in the current gamedir, this DOES NOT
@@ -619,19 +660,9 @@ search the paths. This is to determine
NOTE TTimo: this goes with FS_FOpenFileWrite for opening the file afterwards
================
*/
-qboolean FS_FileExists( const char *file )
+qboolean FS_FileExists(const char *file)
{
- FILE *f;
- char *testpath;
-
- testpath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, file );
-
- f = fopeni( testpath, "rb" );
- if (f) {
- fclose( f );
- return qtrue;
- }
- return qfalse;
+ return FS_FileInPathExists(FS_BuildOSPath(fs_homepath->string, fs_gamedir, file));
}
/*
@@ -643,18 +674,12 @@ Tests if the file exists
*/
qboolean FS_SV_FileExists( const char *file )
{
- FILE *f;
char *testpath;
testpath = FS_BuildOSPath( fs_homepath->string, file, "");
testpath[strlen(testpath)-1] = '\0';
- f = fopeni( testpath, "rb" );
- if (f) {
- fclose( f );
- return qtrue;
- }
- return qfalse;
+ return FS_FileInPathExists(testpath);
}
@@ -708,7 +733,8 @@ Search for a file somewhere below the ho
in that order
===========
*/
-int FS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp ) {
+long FS_SV_FOpenFileRead(const char *filename, fileHandle_t *fp)
+{
char *ospath;
fileHandle_t f = 0;
@@ -1081,250 +1107,392 @@ qboolean FS_IsDemoExt(const char *filena
/*
===========
-FS_FOpenFileRead
+FS_FOpenFileReadDir
-Finds the file in the search path.
+Tries opening file "filename" in searchpath "search"
Returns filesize and an open FILE pointer.
-Used for streaming data out of either a
-separate file or a ZIP file.
===========
*/
extern qboolean com_fullyInitialized;
-int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueFILE ) {
- searchpath_t *search;
- char *netpath;
- pack_t *pak;
- fileInPack_t *pakFile;
- directory_t *dir;
+long FS_FOpenFileReadDir(const char *filename, searchpath_t *search, fileHandle_t *file, qboolean uniqueFILE)
+{
long hash;
- FILE *temp;
- int l;
-
- hash = 0;
-
- if ( !fs_searchpaths ) {
- Com_Error( ERR_FATAL, "Filesystem call made without initialization" );
- }
-
- if ( file == NULL ) {
- // just wants to see if file is there
- for ( search = fs_searchpaths ; search ; search = search->next ) {
- //
- if ( search->pack ) {
- hash = FS_HashFileName(filename, search->pack->hashSize);
- }
- // is the element a pak file?
- if ( search->pack && search->pack->hashTable[hash] ) {
- // look through all the pak file elements
- pak = search->pack;
- pakFile = pak->hashTable[hash];
- do {
- // case and separator insensitive comparisons
- if ( !FS_FilenameCompare( pakFile->name, filename ) ) {
- // found it!
- return qtrue;
- }
- pakFile = pakFile->next;
- } while(pakFile != NULL);
- } else if ( search->dir ) {
- dir = search->dir;
-
- netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename );
- temp = fopeni (netpath, "rb");
- if ( !temp ) {
- continue;
- }
- fclose(temp);
- return qtrue;
- }
- }
- return qfalse;
- }
+ pack_t *pak;
+ fileInPack_t *pakFile;
+ directory_t *dir;
+ char *netpath;
+ FILE *filep;
+ int len;
- if ( !filename ) {
- Com_Error( ERR_FATAL, "FS_FOpenFileRead: NULL 'filename' parameter passed" );
- }
+ if(filename == NULL)
+ Com_Error(ERR_FATAL, "FS_FOpenFileRead: NULL 'filename' parameter passed");
// qpaths are not supposed to have a leading slash
- if ( filename[0] == '/' || filename[0] == '\\' ) {
+ if(filename[0] == '/' || filename[0] == '\\')
filename++;
- }
// make absolutely sure that it can't back up the path.
// The searchpaths do guarantee that something will always
// be prepended, so we don't need to worry about "c:" or "//limbo"
- if ( strstr( filename, ".." ) || strstr( filename, "::" ) ) {
+ if(strstr(filename, ".." ) || strstr(filename, "::"))
+ {
+ if(file == NULL)
+ return qfalse;
+
*file = 0;
return -1;
}
-
+
// make sure the q3key file is only readable by the quake3.exe at initialization
// any other time the key should only be accessed in memory using the provided functions
- if( com_fullyInitialized && strstr( filename, "q3key" ) ) {
+ if(com_fullyInitialized && strstr(filename, "q3key"))
+ {
+ if(file == NULL)
+ return qfalse;
+
*file = 0;
return -1;
}
- //
- // search through the path, one element at a time
- //
+ if(file == NULL)
+ {
+ // just wants to see if file is there
+
+ // is the element a pak file?
+ if(search->pack)
+ {
+ hash = FS_HashFileName(filename, search->pack->hashSize);
+
+ if(search->pack->hashTable[hash])
+ {
+ // look through all the pak file elements
+ pak = search->pack;
+ pakFile = pak->hashTable[hash];
+
+ do
+ {
+ // case and separator insensitive comparisons
+ if(!FS_FilenameCompare(pakFile->name, filename))
+ {
+ // found it!
+ if(pakFile->len)
+ return pakFile->len;
+ else
+ {
+ // It's not nice, but legacy code depends
+ // on positive value if file exists no matter
+ // what size
+ return 1;
+ }
+ }
+
+ pakFile = pakFile->next;
+ } while(pakFile != NULL);
+ }
+ }
+ else if(search->dir)
+ {
+ dir = search->dir;
+
+ netpath = FS_BuildOSPath(dir->path, dir->gamedir, filename);
+ filep = fopeni (netpath, "rb");
+
+ if(filep)
+ {
+ len = FS_fplength(filep);
+ fclose(filep);
+
+ if(len)
+ return len;
+ else
+ return 1;
+ }
+ }
+
+ return 0;
+ }
*file = FS_HandleForFile();
fsh[*file].handleFiles.unique = uniqueFILE;
+
+ // is the element a pak file?
+ if(search->pack)
+ {
+ hash = FS_HashFileName(filename, search->pack->hashSize);
- for ( search = fs_searchpaths ; search ; search = search->next ) {
- //
- if ( search->pack ) {
- hash = FS_HashFileName(filename, search->pack->hashSize);
- }
- // is the element a pak file?
- if ( search->pack && search->pack->hashTable[hash] ) {
+ if(search->pack->hashTable[hash])
+ {
// disregard if it doesn't match one of the allowed pure pak files
- if ( !FS_PakIsPure(search->pack) ) {
- continue;
+ if(!FS_PakIsPure(search->pack))
+ {
+ *file = 0;
+ return -1;
}
// look through all the pak file elements
pak = search->pack;
pakFile = pak->hashTable[hash];
- do {
+
+ do
+ {
// case and separator insensitive comparisons
- if ( !FS_FilenameCompare( pakFile->name, filename ) ) {
+ if(!FS_FilenameCompare(pakFile->name, filename))
+ {
// found it!
// mark the pak as having been referenced and mark specifics on cgame and ui
// shaders, txt, arena files by themselves do not count as a reference as
// these are loaded from all pk3s
// from every pk3 file..
- l = strlen(filename);
-
+ len = strlen(filename);
+
if (!(pak->referenced & FS_GENERAL_REF))
{
- if(!FS_IsExt(filename, ".shader", l) &&
- !FS_IsExt(filename, ".txt", l) &&
- !FS_IsExt(filename, ".cfg", l) &&
- !FS_IsExt(filename, ".config", l) &&
- !FS_IsExt(filename, ".bot", l) &&
- !FS_IsExt(filename, ".arena", l) &&
- !FS_IsExt(filename, ".menu", l) &&
+ if(!FS_IsExt(filename, ".shader", len) &&
+ !FS_IsExt(filename, ".txt", len) &&
+ !FS_IsExt(filename, ".cfg", len) &&
+ !FS_IsExt(filename, ".config", len) &&
+ !FS_IsExt(filename, ".bot", len) &&
+ !FS_IsExt(filename, ".arena", len) &&
+ !FS_IsExt(filename, ".menu", len) &&
!strstr(filename, "levelshots"))
{
pak->referenced |= FS_GENERAL_REF;
}
}
- if (!(pak->referenced & FS_QAGAME_REF) && strstr(filename, "qagame.qvm")) {
+ if(strstr(filename, "qagame.qvm"))
pak->referenced |= FS_QAGAME_REF;
- }
- if (!(pak->referenced & FS_CGAME_REF) && strstr(filename, "cgame.qvm")) {
+ if(strstr(filename, "cgame.qvm"))
pak->referenced |= FS_CGAME_REF;
- }
- if (!(pak->referenced & FS_UI_REF) && strstr(filename, "ui.qvm")) {
+ if(strstr(filename, "ui.qvm"))
pak->referenced |= FS_UI_REF;
- }
- if ( uniqueFILE ) {
+ if(uniqueFILE)
+ {
// open a new file on the pakfile
- fsh[*file].handleFiles.file.z = unzOpen (pak->pakFilename);
- if (fsh[*file].handleFiles.file.z == NULL) {
- Com_Error (ERR_FATAL, "Couldn't open %s", pak->pakFilename);
- }
- } else {
- fsh[*file].handleFiles.file.z = pak->handle;
+ fsh[*file].handleFiles.file.z = unzOpen(pak->pakFilename);
+
+ if(fsh[*file].handleFiles.file.z == NULL)
+ Com_Error(ERR_FATAL, "Couldn't open %s", pak->pakFilename);
}
- Q_strncpyz( fsh[*file].name, filename, sizeof( fsh[*file].name ) );
+ else
+ fsh[*file].handleFiles.file.z = pak->handle;
+
+ Q_strncpyz(fsh[*file].name, filename, sizeof(fsh[*file].name));
fsh[*file].zipFile = qtrue;
+
// set the file position in the zip file (also sets the current file info)
unzSetOffset(fsh[*file].handleFiles.file.z, pakFile->pos);
+
// open the file in the zip
- unzOpenCurrentFile( fsh[*file].handleFiles.file.z );
+ unzOpenCurrentFile(fsh[*file].handleFiles.file.z);
fsh[*file].zipFilePos = pakFile->pos;
- if ( fs_debug->integer ) {
- Com_Printf( "FS_FOpenFileRead: %s (found in '%s')\n",
- filename, pak->pakFilename );
+ if(fs_debug->integer)
+ {
+ Com_Printf("FS_FOpenFileRead: %s (found in '%s')\n",
+ filename, pak->pakFilename);
}
+
return pakFile->len;
}
+
pakFile = pakFile->next;
} while(pakFile != NULL);
- } else if ( search->dir ) {
- // check a file in the directory tree
+ }
+ }
+ else if(search->dir)
+ {
+ // check a file in the directory tree
- // if we are running restricted, the only files we
- // will allow to come from the directory are .cfg files
- l = strlen( filename );
- // FIXME TTimo I'm not sure about the fs_numServerPaks test
- // if you are using FS_ReadFile to find out if a file exists,
- // this test can make the search fail although the file is in the directory
- // I had the problem on https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=8
- // turned out I used FS_FileExists instead
- if(fs_numServerPaks)
+ // if we are running restricted, the only files we
+ // will allow to come from the directory are .cfg files
+ len = strlen(filename);
+ // FIXME TTimo I'm not sure about the fs_numServerPaks test
+ // if you are using FS_ReadFile to find out if a file exists,
+ // this test can make the search fail although the file is in the directory
+ // I had the problem on https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=8
+ // turned out I used FS_FileExists instead
+ if(fs_numServerPaks)
+ {
+ if(!FS_IsExt(filename, ".cfg", len) && // for config files
+ !FS_IsExt(filename, ".menu", len) && // menu files
+ !FS_IsExt(filename, ".game", len) && // menu files
+ !FS_IsExt(filename, ".cfg", len) && // for journal files
+ !FS_IsDemoExt(filename, len)) // demos
{
- if(!FS_IsExt(filename, ".cfg", l) && // for config files
- !FS_IsExt(filename, ".menu", l) && // menu files
- !FS_IsExt(filename, ".game", l) && // menu files
- !FS_IsExt(filename, ".cfg", l) && // for journal files
- !FS_IsDemoExt(filename, l)) // demos
- {
- continue;
- }
+ *file = 0;
+ return -1;
}
+ }
- dir = search->dir;
+ dir = search->dir;
- netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename );
- fsh[*file].handleFiles.file.o = fopeni (netpath, "rb");
- if ( !fsh[*file].handleFiles.file.o ) {
- continue;
- }
+ netpath = FS_BuildOSPath(dir->path, dir->gamedir, filename);
+ filep = fopen(netpath, "rb");
- Q_strncpyz( fsh[*file].name, filename, sizeof( fsh[*file].name ) );
- fsh[*file].zipFile = qfalse;
- if ( fs_debug->integer ) {
- Com_Printf( "FS_FOpenFileRead: %s (found in '%s/%s')\n", filename,
- dir->path, dir->gamedir );
- }
+ if (filep == NULL)
+ {
+ *file = 0;
+ return -1;
+ }
+
+ Q_strncpyz(fsh[*file].name, filename, sizeof(fsh[*file].name));
+ fsh[*file].zipFile = qfalse;
+
+ if(fs_debug->integer)
+ {
+ Com_Printf("FS_FOpenFileRead: %s (found in '%s/%s')\n", filename,
+ dir->path, dir->gamedir);
+ }
+
+ fsh[*file].handleFiles.file.o = filep;
+ return FS_fplength(filep);
+ }
+
+ return -1;
+}
+
+/*
+===========
+FS_FOpenFileRead
+
+Finds the file in the search path.
+Returns filesize and an open FILE pointer.
+Used for streaming data out of either a
+separate file or a ZIP file.
+===========
+*/
+long FS_FOpenFileRead(const char *filename, fileHandle_t *file, qboolean uniqueFILE)
+{
+ searchpath_t *search;
+ long len;
+
+ if(!fs_searchpaths)
+ Com_Error(ERR_FATAL, "Filesystem call made without initialization");
- return FS_filelength (*file);
- }
+ for(search = fs_searchpaths; search; search = search->next)
+ {
+ len = FS_FOpenFileReadDir(filename, search, file, uniqueFILE);
+
+ if(file == NULL)
+ {
+ if(len > 0)
+ return len;
+ }
+ else
+ {
+ if(len >= 0 && *file)
+ return len;
+ }
+
}
#ifdef FS_MISSING
- if (missingFiles) {
+ if(missingFiles)
fprintf(missingFiles, "%s\n", filename);
- }
#endif
- *file = 0;
+
+ if(file)
+ *file = 0;
+
return -1;
}
+/*
+=================
+FS_FindVM
-char *FS_FindDll( const char *filename ) {
- searchpath_t *search;
- directory_t *dir;
+Find a suitable VM file in search path order.
- if ( !fs_searchpaths ) {
- Com_Error( ERR_FATAL, "Filesystem call made without initialization" );
- }
+In each searchpath try:
+ - open DLL file if DLL loading enabled
+ - open QVM file
- for ( search = fs_searchpaths ; search ; search = search->next ) {
- if ( search->dir ) {
- FILE *f;
- char *netpath;
+Enable search for DLL by setting enableDll to FSVM_ENABLEDLL
+
+write found DLL or QVM to "found" and return VMI_NATIVE if DLL, VMI_COMPILED if QVM
+Return the searchpath in "startSearch".
+=================
+*/
+
+vmInterpret_t FS_FindVM(void **startSearch, char *found, int foundlen, const char *name, int enableDll)
+{
+ searchpath_t *search, *lastSearch;
+ directory_t *dir;
+ pack_t *pack;
+ char dllName[MAX_OSPATH], qvmName[MAX_OSPATH];
+ char *netpath;
+
+ if(!fs_searchpaths)
+ Com_Error(ERR_FATAL, "Filesystem call made without initialization");
+
+ if(enableDll)
+ Com_sprintf(dllName, sizeof(dllName), "%s" ARCH_STRING DLL_EXT, name);
+
+ Com_sprintf(qvmName, sizeof(dllName), "vm/%s.qvm", name);
+ lastSearch = *startSearch;
+ if(*startSearch == NULL)
+ search = fs_searchpaths;
+ else
+ search = lastSearch->next;
+
+ while(search)
+ {
+ if(search->dir && !fs_numServerPaks)
+ {
dir = search->dir;
- netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename );
- f = fopen( netpath, "rb" );
- if (f) {
- fclose( f );
- return netpath;
+
+ if(enableDll)
+ {
+ netpath = FS_BuildOSPath(dir->path, dir->gamedir, dllName);
+
+ if(FS_FileInPathExists(netpath))
+ {
+ Q_strncpyz(found, netpath, foundlen);
+ *startSearch = search;
+
+ return VMI_NATIVE;
+ }
+ }
+
+ if(FS_FOpenFileReadDir(qvmName, search, NULL, qfalse) > 0)
+ {
+ *startSearch = search;
+ return VMI_COMPILED;
+ }
+ }
+ else if(search->pack)
+ {
+ pack = search->pack;
+
+ if(lastSearch && lastSearch->pack)
+ {
+ // make sure we only try loading one VM file per game dir
+ // i.e. if VM from pak7.pk3 fails we won't try one from pak6.pk3
+
+ if(!FS_FilenameCompare(lastSearch->pack->pakPathname, pack->pakPathname))
+ {
+ search = search->next;
+ continue;
+ }
+ }
+
+ if(FS_FOpenFileReadDir(qvmName, search, NULL, qfalse) > 0)
+ {
+ *startSearch = search;
+
+ return VMI_COMPILED;
}
}
+
+ search = search->next;
}
- return NULL;
+ return -1;
}
/*
@@ -1493,7 +1661,7 @@ int FS_Seek( fileHandle_t f, long offset
if( offset < 0 || origin == FS_SEEK_END ) {
Com_Error( ERR_FATAL, "Negative offsets and FS_SEEK_END not implemented "
- "for FS_Seek on pk3 file contents\n" );
+ "for FS_Seek on pk3 file contents" );
return -1;
}
@@ -1611,17 +1779,20 @@ int FS_FileIsInPAK(const char *filename,
/*
============
-FS_ReadFile
+FS_ReadFileDir
Filename are relative to the quake search path
a null buffer will just return the file length without loading
+If searchPath is non-NULL search only in that specific search path
============
*/
-int FS_ReadFile( const char *qpath, void **buffer ) {
+long FS_ReadFileDir(const char *qpath, void *searchPath, void **buffer)
+{
fileHandle_t h;
+ searchpath_t *search;
byte* buf;
qboolean isConfig;
- int len;
+ long len;
if ( !fs_searchpaths ) {
Com_Error( ERR_FATAL, "Filesystem call made without initialization" );
@@ -1678,8 +1849,19 @@ int FS_ReadFile( const char *qpath, void
isConfig = qfalse;
}
- // look for it in the filesystem or pack files
- len = FS_FOpenFileRead( qpath, &h, qfalse );
+ search = searchPath;
+
+ if(search == NULL)
+ {
+ // look for it in the filesystem or pack files
+ len = FS_FOpenFileRead(qpath, &h, qfalse);
+ }
+ else
+ {
+ // look for it in a specific search path only
+ len = FS_FOpenFileReadDir(qpath, search, &h, qfalse);
+ }
+
if ( h == 0 ) {
if ( buffer ) {
*buffer = NULL;
@@ -1727,6 +1909,19 @@ int FS_ReadFile( const char *qpath, void
}
/*
+============
+FS_ReadFile
+
+Filename are relative to the quake search path
+a null buffer will just return the file length without loading
+============
+*/
+long FS_ReadFile(const char *qpath, void **buffer)
+{
+ return FS_ReadFileDir(qpath, NULL, buffer);
+}
+
+/*
=============
FS_FreeFile
=============
@@ -2582,21 +2777,40 @@ void FS_TouchFile_f( void ) {
/*
============
+FS_Which
+============
+*/
+
+qboolean FS_Which(const char *filename, void *searchPath)
+{
+ searchpath_t *search = searchPath;
+
+ if(FS_FOpenFileReadDir(filename, search, NULL, qfalse) > 0)
+ {
+ if(search->pack)
+ {
+ Com_Printf("File \"%s\" found in \"%s\"\n", filename, search->pack->pakFilename);
+ return qtrue;
+ }
+ else if(search->dir)
+ {
+ Com_Printf( "File \"%s\" found at \"%s\"\n", filename, search->dir->fullpath);
+ return qtrue;
+ }
+ }
+
+ return qfalse;
+}
+
+/*
+============
FS_Which_f
============
*/
void FS_Which_f( void ) {
searchpath_t *search;
- char *netpath;
- pack_t *pak;
- fileInPack_t *pakFile;
- directory_t *dir;
- long hash;
- FILE *temp;
- char *filename;
- char buf[ MAX_OSPATH ];
+ char *filename;
- hash = 0;
filename = Cmd_Argv(1);
if ( !filename[0] ) {
@@ -2610,40 +2824,13 @@ void FS_Which_f( void ) {
}
// just wants to see if file is there
- for ( search = fs_searchpaths ; search ; search = search->next ) {
- if ( search->pack ) {
- hash = FS_HashFileName(filename, search->pack->hashSize);
- }
- // is the element a pak file?
- if ( search->pack && search->pack->hashTable[hash] ) {
- // look through all the pak file elements
- pak = search->pack;
- pakFile = pak->hashTable[hash];
- do {
- // case and separator insensitive comparisons
- if ( !FS_FilenameCompare( pakFile->name, filename ) ) {
- // found it!
- Com_Printf( "File \"%s\" found in \"%s\"\n", filename, pak->pakFilename );
- return;
- }
- pakFile = pakFile->next;
- } while(pakFile != NULL);
- } else if ( search->dir ) {
- dir = search->dir;
-
- netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename );
- temp = fopen (netpath, "rb");
- if ( !temp ) {
- continue;
- }
- fclose(temp);
- Com_sprintf( buf, sizeof( buf ), "%s/%s", dir->path, dir->gamedir );
- FS_ReplaceSeparators( buf );
- Com_Printf( "File \"%s\" found at \"%s\"\n", filename, buf );
+ for(search = fs_searchpaths; search; search = search->next)
+ {
+ if(FS_Which(filename, search))
return;
- }
}
- Com_Printf( "File not found: \"%s\"\n", filename );
+
+ Com_Printf("File not found: \"%s\"\n", filename);
return;
}
@@ -2673,7 +2860,7 @@ void FS_AddGameDirectory( const char *pa
int i;
searchpath_t *search;
pack_t *pak;
- char *pakfile;
+ char curpath[MAX_OSPATH + 1], *pakfile;
int numfiles;
char **pakfiles;
@@ -2686,22 +2873,11 @@ void FS_AddGameDirectory( const char *pa
Q_strncpyz( fs_gamedir, dir, sizeof( fs_gamedir ) );
- //
- // add the directory to the search path
- //
- search = Z_Malloc (sizeof(searchpath_t));
- search->dir = Z_Malloc( sizeof( *search->dir ) );
-
- Q_strncpyz( search->dir->path, path, sizeof( search->dir->path ) );
- Q_strncpyz( search->dir->gamedir, dir, sizeof( search->dir->gamedir ) );
- search->next = fs_searchpaths;
- fs_searchpaths = search;
-
// find all pak files in this directory
- pakfile = FS_BuildOSPath( path, dir, "" );
- pakfile[ strlen(pakfile) - 1 ] = 0; // strip the trailing slash
+ Q_strncpyz(curpath, FS_BuildOSPath(path, dir, ""), sizeof(curpath));
+ curpath[strlen(curpath) - 1] = '\0'; // strip the trailing slash
- pakfiles = Sys_ListFiles( pakfile, ".pk3", NULL, &numfiles, qfalse );
+ pakfiles = Sys_ListFiles(curpath, ".pk3", NULL, &numfiles, qfalse);
qsort( pakfiles, numfiles, sizeof(char*), paksort );
@@ -2709,8 +2885,10 @@ void FS_AddGameDirectory( const char *pa
pakfile = FS_BuildOSPath( path, dir, pakfiles[i] );
if ( ( pak = FS_LoadZipFile( pakfile, pakfiles[i] ) ) == 0 )
continue;
+
+ Q_strncpyz(pak->pakPathname, curpath, sizeof(pak->pakPathname));
// store the game name for downloading
- strcpy(pak->pakGamename, dir);
+ Q_strncpyz(pak->pakGamename, dir, sizeof(pak->pakGamename));
fs_packFiles += pak->numfiles;
@@ -2722,6 +2900,19 @@ void FS_AddGameDirectory( const char *pa
// done
Sys_FreeFileList( pakfiles );
+
+ //
+ // add the directory to the search path
+ //
+ search = Z_Malloc (sizeof(searchpath_t));
+ search->dir = Z_Malloc( sizeof( *search->dir ) );
+
+ Q_strncpyz(search->dir->path, path, sizeof(search->dir->path));
+ Q_strncpyz(search->dir->fullpath, curpath, sizeof(search->dir->fullpath));
+ Q_strncpyz(search->dir->gamedir, dir, sizeof(search->dir->gamedir));
+
+ search->next = fs_searchpaths;
+ fs_searchpaths = search;
}
/*
@@ -2807,7 +2998,7 @@ qboolean FS_ComparePaks( char *neededpak
// never autodownload any of the id paks
if(FS_idPak(fs_serverReferencedPakNames[i], BASEGAME, NUM_ID_PAKS)
#ifndef STANDALONE
- || FS_idPak(fs_serverReferencedPakNames[i], BASETA, NUM_TA_PAKS)
+ || FS_idPak(fs_serverReferencedPakNames[i], BASETA, NUM_TA_PAKS)
#endif
)
{
@@ -3871,7 +4062,7 @@ void FS_FilenameCompletion( const char *
const char *FS_GetCurrentGameDir(void)
{
if(fs_gamedirvar->string[0])
- return fs_gamedirvar->string;
+ return fs_gamedirvar->string;
- return com_basegame->string;
+ return com_basegame->string;
}
Index: code/qcommon/vm_local.h
===================================================================
--- code/qcommon/vm_local.h.orig
+++ code/qcommon/vm_local.h
@@ -25,7 +25,7 @@ Foundation, Inc., 51 Franklin St, Fifth
// don't change, this is hardcoded into x86 VMs, opStack protection relies
// on this
-#define OPSTACK_SIZE 256
+#define OPSTACK_SIZE 1024
#define OPSTACK_MASK (OPSTACK_SIZE-1)
// don't change
@@ -142,7 +142,8 @@ struct vm_s {
//------------------------------------
- char name[MAX_QPATH];
+ char name[MAX_QPATH];
+ void *searchPath; // hint for FS_ReadFileDir()
// for dynamic linked modules
void *dllHandle;
@@ -157,7 +158,7 @@ struct vm_s {
int entryOfs;
int codeLength;
- int *instructionPointers;
+ intptr_t *instructionPointers;
int instructionCount;
byte *dataBase;
@@ -190,3 +191,5 @@ vmSymbol_t *VM_ValueToFunctionSymbol( vm
int VM_SymbolToValue( vm_t *vm, const char *symbol );
const char *VM_ValueToSymbol( vm_t *vm, int value );
void VM_LogSyscalls( int *args );
+
+void VM_BlockCopy(unsigned int dest, unsigned int src, size_t n);
Index: code/qcommon/vm_x86.c
===================================================================
--- code/qcommon/vm_x86.c.orig
+++ code/qcommon/vm_x86.c
@@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth
// vm_x86.c -- load time compiler and execution environment for x86
#include "vm_local.h"
+
#ifdef _WIN32
#include <windows.h>
#endif
@@ -45,12 +46,15 @@ static void VM_Destroy_Compiled(vm_t* se
/*
- eax scratch
- ebx scratch
- ecx scratch (required for shifts)
- edx scratch (required for divisions)
- esi program stack
- edi opstack
+ eax scratch
+ ebx/bl opStack offset
+ ecx scratch (required for shifts)
+ edx scratch (required for divisions)
+ esi program stack
+ edi opStack base
+x86_64:
+ r8 vm->instructionPointers
+ r9 vm->dataBase
*/
@@ -64,29 +68,6 @@ static int pc = 0;
#define FTOL_PTR
-#ifdef _MSC_VER
-
-#if defined( FTOL_PTR )
-int _ftol( float );
-static int ftolPtr = (int)_ftol;
-#endif
-
-#else // _MSC_VER
-
-#if defined( FTOL_PTR )
-
-int qftol( void );
-int qftol027F( void );
-int qftol037F( void );
-int qftol0E7F( void );
-int qftol0F7F( void );
-
-
-static int ftolPtr = (int)qftol0F7F;
-#endif // FTOL_PTR
-
-#endif
-
static int instruction, pass;
static int lastConst = 0;
static int oc0, oc1, pop0, pop1;
@@ -95,20 +76,30 @@ static int jlabel;
typedef enum
{
LAST_COMMAND_NONE = 0,
- LAST_COMMAND_MOV_EDI_EAX,
- LAST_COMMAND_SUB_DI_4,
- LAST_COMMAND_SUB_DI_8,
+ LAST_COMMAND_MOV_STACK_EAX,
+ LAST_COMMAND_SUB_BL_1,
+ LAST_COMMAND_SUB_BL_2,
} ELastCommand;
+typedef enum
+{
+ VM_JMP_VIOLATION = 0,
+ VM_BLOCK_COPY = 1
+} ESysCallType;
+
static ELastCommand LastCommand;
-static void ErrJump( void )
-{
- Com_Error( ERR_DROP, "program tried to execute code outside VM\n" );
- exit(1);
+static int iss8(int32_t v)
+{
+ return (SCHAR_MIN <= v && v <= SCHAR_MAX);
}
-static void (*const errJumpPtr)(void) = ErrJump;
+#if 0
+static int isu8(uint32_t v)
+{
+ return (v <= UCHAR_MAX);
+}
+#endif
static int NextConstant4(void)
{
@@ -139,18 +130,32 @@ static void Emit1( int v )
LastCommand = LAST_COMMAND_NONE;
}
-#if 0
-static void Emit2( int v ) {
- Emit1( v & 255 );
- Emit1( ( v >> 8 ) & 255 );
+static void Emit2(int v)
+{
+ Emit1(v & 255);
+ Emit1((v >> 8) & 255);
}
-#endif
-static void Emit4( int v ) {
- Emit1( v & 255 );
- Emit1( ( v >> 8 ) & 255 );
- Emit1( ( v >> 16 ) & 255 );
- Emit1( ( v >> 24 ) & 255 );
+
+static void Emit4(int v)
+{
+ Emit1(v & 0xFF);
+ Emit1((v >> 8) & 0xFF);
+ Emit1((v >> 16) & 0xFF);
+ Emit1((v >> 24) & 0xFF);
+}
+
+static void EmitPtr(void *ptr)
+{
+ intptr_t v = (intptr_t) ptr;
+
+ Emit4(v);
+#if idx64
+ Emit1((v >> 32) & 0xFF);
+ Emit1((v >> 40) & 0xFF);
+ Emit1((v >> 48) & 0xFF);
+ Emit1((v >> 56) & 0xFF);
+#endif
}
static int Hex( int c ) {
@@ -186,23 +191,46 @@ static void EmitString( const char *stri
string += 3;
}
}
+static void EmitRexString(byte rex, const char *string)
+{
+#if idx64
+ if(rex)
+ Emit1(rex);
+#endif
+
+ EmitString(string);
+}
+#define MASK_REG(modrm, mask) \
+ EmitString("81"); \
+ EmitString((modrm)); \
+ Emit4((mask))
+
+// add bl, bytes
+#define STACK_PUSH(bytes) \
+ EmitString("80 C3"); \
+ Emit1(bytes)
+
+// sub bl, bytes
+#define STACK_POP(bytes) \
+ EmitString("80 EB"); \
+ Emit1(bytes)
static void EmitCommand(ELastCommand command)
{
switch(command)
{
- case LAST_COMMAND_MOV_EDI_EAX:
- EmitString( "89 07" ); // mov dword ptr [edi], eax
+ case LAST_COMMAND_MOV_STACK_EAX:
+ EmitString("89 04 9F"); // mov dword ptr [edi + ebx * 4], eax
break;
- case LAST_COMMAND_SUB_DI_4:
- EmitString( "83 EF 04" ); // sub edi, 4
+ case LAST_COMMAND_SUB_BL_1:
+ STACK_POP(1); // sub bl, 1
break;
- case LAST_COMMAND_SUB_DI_8:
- EmitString( "83 EF 08" ); // sub edi, 8
+ case LAST_COMMAND_SUB_BL_2:
+ STACK_POP(2); // sub bl, 2
break;
default:
break;
@@ -210,115 +238,133 @@ static void EmitCommand(ELastCommand com
LastCommand = command;
}
-static void EmitAddEDI4( vm_t *vm ) {
- if ( jlabel ) {
- EmitString( "83 C7 04" ); // add edi,4
- return;
- }
- if ( LastCommand == LAST_COMMAND_SUB_DI_4 )
- { // sub edi, 4
- compiledOfs -= 3;
- vm->instructionPointers[ instruction-1 ] = compiledOfs;
- return;
- }
- if ( LastCommand == LAST_COMMAND_SUB_DI_8 )
- { // sub edi, 8
- compiledOfs -= 3;
- vm->instructionPointers[ instruction-1 ] = compiledOfs;
- EmitString( "83 EF 04" ); // sub edi,4
- return;
- }
- EmitString( "83 C7 04" ); // add edi,4
-}
-
-static void EmitMovEAXEDI(vm_t *vm) {
- if ( jlabel ) {
- EmitString( "8B 07" ); // mov eax, dword ptr [edi]
- return;
- }
- if (LastCommand == LAST_COMMAND_MOV_EDI_EAX)
- { // mov [edi], eax
- compiledOfs -= 2;
- vm->instructionPointers[ instruction-1 ] = compiledOfs;
- return;
- }
- if (pop1 == OP_DIVI || pop1 == OP_DIVU || pop1 == OP_MULI || pop1 == OP_MULU ||
- pop1 == OP_STORE4 || pop1 == OP_STORE2 || pop1 == OP_STORE1 )
- {
- return;
- }
- if (pop1 == OP_CONST && buf[compiledOfs-6] == 0xC7 && buf[compiledOfs-5] == 0x07 )
- { // mov edi, 0x123456
- compiledOfs -= 6;
- vm->instructionPointers[ instruction-1 ] = compiledOfs;
- EmitString( "B8" ); // mov eax, 0x12345678
- Emit4( lastConst );
- return;
- }
- EmitString( "8B 07" ); // mov eax, dword ptr [edi]
-}
-
-void EmitMovECXEDI( vm_t *vm ) {
- if ( jlabel ) {
- EmitString( "8B 0F" ); // mov ecx, dword ptr [edi]
- return;
- }
- if ( LastCommand == LAST_COMMAND_MOV_EDI_EAX ) // mov [edi], eax
+static void EmitPushStack(vm_t *vm)
+{
+ if (!jlabel)
{
- compiledOfs -= 2;
- vm->instructionPointers[ instruction-1 ] = compiledOfs;
- EmitString( "89 C1" ); // mov ecx, eax
- return;
- }
- if (pop1 == OP_DIVI || pop1 == OP_DIVU || pop1 == OP_MULI || pop1 == OP_MULU ||
- pop1 == OP_STORE4 || pop1 == OP_STORE2 || pop1 == OP_STORE1 )
- {
- EmitString( "89 C1" ); // mov ecx, eax
- return;
+ if(LastCommand == LAST_COMMAND_SUB_BL_1)
+ { // sub bl, 1
+ compiledOfs -= 3;
+ vm->instructionPointers[instruction - 1] = compiledOfs;
+ return;
+ }
+ if(LastCommand == LAST_COMMAND_SUB_BL_2)
+ { // sub bl, 2
+ compiledOfs -= 3;
+ vm->instructionPointers[instruction - 1] = compiledOfs;
+ STACK_POP(1); // sub bl, 1
+ return;
+ }
}
- EmitString( "8B 0F" ); // mov ecx, dword ptr [edi]
-}
+ STACK_PUSH(1); // add bl, 1
+}
-qboolean EmitMovEBXEDI(vm_t *vm, int andit) {
- if ( jlabel ) {
- EmitString( "8B 1F" ); // mov ebx, dword ptr [edi]
- return qfalse;
- }
- if ( LastCommand == LAST_COMMAND_MOV_EDI_EAX )
- { // mov dword ptr [edi], eax
- compiledOfs -= 2;
- vm->instructionPointers[ instruction-1 ] = compiledOfs;
- EmitString( "8B D8"); // mov bx, eax
- return qfalse;
+static void EmitMovEAXStack(vm_t *vm, int andit)
+{
+ if(!jlabel)
+ {
+ if(LastCommand == LAST_COMMAND_MOV_STACK_EAX)
+ { // mov [edi + ebx * 4], eax
+ compiledOfs -= 3;
+ vm->instructionPointers[instruction - 1] = compiledOfs;
+ }
+ else if(pop1 == OP_CONST && buf[compiledOfs-7] == 0xC7 && buf[compiledOfs-6] == 0x04 && buf[compiledOfs - 5] == 0x9F)
+ { // mov [edi + ebx * 4], 0x12345678
+ compiledOfs -= 7;
+ vm->instructionPointers[instruction - 1] = compiledOfs;
+ EmitString("B8"); // mov eax, 0x12345678
+
+ if(andit)
+ Emit4(lastConst & andit);
+ else
+ Emit4(lastConst);
+
+ return;
+ }
+ else if(pop1 != OP_DIVI && pop1 != OP_DIVU && pop1 != OP_MULI && pop1 != OP_MULU &&
+ pop1 != OP_STORE4 && pop1 != OP_STORE2 && pop1 != OP_STORE1)
+ {
+ EmitString("8B 04 9F"); // mov eax, dword ptr [edi + ebx * 4]
+ }
}
- if ( pop1 == OP_DIVI || pop1 == OP_DIVU || pop1 == OP_MULI || pop1 == OP_MULU ||
- pop1 == OP_STORE4 || pop1 == OP_STORE2 || pop1 == OP_STORE1 )
- {
- EmitString( "8B D8"); // mov bx, eax
- return qfalse;
+ else
+ EmitString("8B 04 9F"); // mov eax, dword ptr [edi + ebx * 4]
+
+ if(andit)
+ {
+ EmitString("25"); // and eax, 0x12345678
+ Emit4(andit);
}
- if ( pop1 == OP_CONST && buf[compiledOfs-6] == 0xC7 && buf[compiledOfs-5] == 0x07 )
- { // mov dword ptr [edi], 0x12345678
- compiledOfs -= 6;
- vm->instructionPointers[ instruction-1 ] = compiledOfs;
- EmitString( "BB" ); // mov ebx, 0x12345678
- if (andit) {
- Emit4( lastConst & andit );
- } else {
- Emit4( lastConst );
+}
+
+void EmitMovECXStack(vm_t *vm)
+{
+ if(!jlabel)
+ {
+ if(LastCommand == LAST_COMMAND_MOV_STACK_EAX) // mov [edi + ebx * 4], eax
+ {
+ compiledOfs -= 3;
+ vm->instructionPointers[instruction - 1] = compiledOfs;
+ EmitString("89 C1"); // mov ecx, eax
+ return;
+ }
+ if(pop1 == OP_DIVI || pop1 == OP_DIVU || pop1 == OP_MULI || pop1 == OP_MULU ||
+ pop1 == OP_STORE4 || pop1 == OP_STORE2 || pop1 == OP_STORE1)
+ {
+ EmitString("89 C1"); // mov ecx, eax
+ return;
}
- return qtrue;
}
- EmitString( "8B 1F" ); // mov ebx, dword ptr [edi]
- return qfalse;
+ EmitString("8B 0C 9F"); // mov ecx, dword ptr [edi + ebx * 4]
+}
+
+
+void EmitMovEDXStack(vm_t *vm, int andit)
+{
+ if(!jlabel)
+ {
+ if(LastCommand == LAST_COMMAND_MOV_STACK_EAX)
+ { // mov dword ptr [edi + ebx * 4], eax
+ compiledOfs -= 3;
+ vm->instructionPointers[instruction - 1] = compiledOfs;
+
+ EmitString("8B D0"); // mov edx, eax
+ }
+ else if(pop1 == OP_DIVI || pop1 == OP_DIVU || pop1 == OP_MULI || pop1 == OP_MULU ||
+ pop1 == OP_STORE4 || pop1 == OP_STORE2 || pop1 == OP_STORE1)
+ {
+ EmitString("8B D0"); // mov edx, eax
+ }
+ else if(pop1 == OP_CONST && buf[compiledOfs-7] == 0xC7 && buf[compiledOfs-6] == 0x07 && buf[compiledOfs - 5] == 0x9F)
+ { // mov dword ptr [edi + ebx * 4], 0x12345678
+ compiledOfs -= 7;
+ vm->instructionPointers[instruction - 1] = compiledOfs;
+ EmitString("BA"); // mov edx, 0x12345678
+
+ if(andit)
+ Emit4(lastConst & andit);
+ else
+ Emit4(lastConst);
+
+ return;
+ }
+ else
+ EmitString("8B 14 9F"); // mov edx, dword ptr [edi + ebx * 4]
+
+ }
+ else
+ EmitString("8B 14 9F"); // mov edx, dword ptr [edi + ebx * 4]
+
+ if(andit)
+ MASK_REG("E2", andit); // and edx, 0x12345678
}
#define JUSED(x) \
do { \
- if (x < 0 || x >= jusedSize) { \
- VMFREE_BUFFERS(); \
+ if (x < 0 || x >= vm->instructionCount) { \
+ VMFREE_BUFFERS(); \
Com_Error( ERR_DROP, \
"VM_CompileX86: jump target out of range at offset %d", pc ); \
} \
@@ -327,67 +373,213 @@ qboolean EmitMovEBXEDI(vm_t *vm, int and
#define SET_JMPOFS(x) do { buf[(x)] = compiledOfs - ((x) + 1); } while(0)
+
+/*
+=================
+ErrJump
+Error handler for jump/call to invalid instruction number
+=================
+*/
+
+static void ErrJump(void)
+{
+ Com_Error(ERR_DROP, "program tried to execute code outside VM");
+ exit(1);
+}
+
/*
=================
DoSyscall
-Uses asm to get arguments from stack to work around different calling conventions
+Uses asm to retrieve arguments from registers to work around different calling conventions
=================
*/
+#if defined(_MSC_VER) && idx64
+
+extern void qsyscall64(void);
+extern uint8_t qvmcall64(int *programStack, int *opStack, intptr_t *instructionPointers, byte *dataBase);
+
+// Microsoft does not support inline assembler on x64 platforms. Meh.
+void DoSyscall(int syscallNum, int programStack, int *opStackBase, uint8_t opStackOfs, intptr_t arg)
+{
+#else
static void DoSyscall(void)
{
- vm_t *savedVM;
- int *data;
-
int syscallNum;
int programStack;
- int *opStack;
-
- // Get arguments directly from registers to work around different calling conventions
+ int *opStackBase;
+ uint8_t opStackOfs;
+ intptr_t arg;
+#endif
+
+ vm_t *savedVM;
+
#ifdef _MSC_VER
+ #ifndef idx64
__asm
{
- mov dword ptr syscallNum, eax
- mov dword ptr programStack, esi
- mov dword ptr opStack, edi
+ mov dword ptr syscallNum, eax
+ mov dword ptr programStack, esi
+ mov byte ptr opStackOfs, bl
+ mov dword ptr opStackBase, edi
+ mov dword ptr arg, ecx
}
+ #endif
#else
__asm__ volatile(
""
- : "=a" (syscallNum), "=S" (programStack), "=D" (opStack)
- :
- : "memory"
+ : "=a" (syscallNum), "=S" (programStack), "=D" (opStackBase), "=b" (opStackOfs),
+ "=c" (arg)
);
#endif
- // save currentVM so as to allow for recursive VM entry
- savedVM = currentVM;
- data = (int *) (savedVM->dataBase + programStack + 4);
-
- // modify VM stack pointer for recursive VM entry
- savedVM->programStack = programStack - 4;
- *data = syscallNum;
- opStack[1] = savedVM->systemCall(data);
+ if(syscallNum < 0)
+ {
+ int *data;
+#if idx64
+ int index;
+ intptr_t args[11];
+#endif
+
+ // save currentVM so as to allow for recursive VM entry
+ savedVM = currentVM;
+ data = (int *) (savedVM->dataBase + programStack + 4);
+
+ // modify VM stack pointer for recursive VM entry
+ savedVM->programStack = programStack - 4;
+
+#if idx64
+ args[0] = ~syscallNum;
+ for(index = 1; index < ARRAY_LEN(args); index++)
+ args[index] = data[index];
+
+ opStackBase[opStackOfs + 1] = savedVM->systemCall(args);
+#else
+ data[0] = ~syscallNum;
+ opStackBase[opStackOfs + 1] = savedVM->systemCall(data);
+#endif
+
+ currentVM = savedVM;
+ }
+ else
+ {
+ switch(syscallNum)
+ {
+ case VM_JMP_VIOLATION:
+ ErrJump();
+ break;
+ case VM_BLOCK_COPY:
+ if(opStackOfs < 1)
+ Com_Error(ERR_DROP, "VM_BLOCK_COPY failed due to corrupted opStack");
+
+ VM_BlockCopy(opStackBase[(opStackOfs - 1)], opStackBase[opStackOfs], arg);
+ break;
+ default:
+ Com_Error(ERR_DROP, "Unknown VM operation %d", syscallNum);
+ break;
+ }
+ }
+}
- currentVM = savedVM;
+/*
+=================
+EmitCallRel
+Relative call to vm->codeBase + callOfs
+=================
+*/
+
+void EmitCallRel(vm_t *vm, int callOfs)
+{
+ EmitString("E8"); // call 0x12345678
+ Emit4(callOfs - compiledOfs - 4);
+}
+
+/*
+=================
+EmitCallDoSyscall
+Call to DoSyscall()
+=================
+*/
+
+int EmitCallDoSyscall(vm_t *vm)
+{
+ // use edx register to store DoSyscall address
+#if defined(_MSC_VER) && idx64
+ EmitRexString(0x48, "BA"); // mov edx, qsyscall64
+ EmitPtr(qsyscall64);
+#else
+ EmitRexString(0x48, "BA"); // mov edx, DoSyscall
+ EmitPtr(DoSyscall);
+#endif
+
+ // Push important registers to stack as we can't really make
+ // any assumptions about calling conventions.
+ EmitString("51"); // push ebx
+ EmitString("56"); // push esi
+ EmitString("57"); // push edi
+#if idx64
+ EmitRexString(0x41, "50"); // push r8
+ EmitRexString(0x41, "51"); // push r9
+#endif
+
+ // align the stack pointer to a 16-byte-boundary
+ EmitString("55"); // push ebp
+ EmitRexString(0x48, "89 E5"); // mov ebp, esp
+ EmitRexString(0x48, "83 E4 F0"); // and esp, 0xFFFFFFF0
+
+ // call the syscall wrapper function DoSyscall()
+
+ EmitString("FF D2"); // call edx
+
+ // reset the stack pointer to its previous value
+ EmitRexString(0x48, "89 EC"); // mov esp, ebp
+ EmitString("5D"); // pop ebp
+
+#if idx64
+ EmitRexString(0x41, "59"); // pop r9
+ EmitRexString(0x41, "58"); // pop r8
+#endif
+ EmitString("5F"); // pop edi
+ EmitString("5E"); // pop esi
+ EmitString("59"); // pop ebx
+
+ EmitString("C3"); // ret
+
+ return compiledOfs;
+}
+
+/*
+=================
+EmitCallErrJump
+Emit the code that triggers execution of the jump violation handler
+=================
+*/
+
+static void EmitCallErrJump(vm_t *vm, int sysCallOfs)
+{
+ EmitString("B8"); // mov eax, 0x12345678
+ Emit4(VM_JMP_VIOLATION);
+
+ EmitCallRel(vm, sysCallOfs);
}
/*
=================
EmitCallProcedure
+VM OP_CALL procedure for call destinations obtained at runtime
=================
*/
-int EmitCallProcedure(vm_t *vm)
+int EmitCallProcedure(vm_t *vm, int sysCallOfs)
{
int jmpSystemCall, jmpBadAddr;
int retval;
- EmitString("8B 07"); // mov eax, dword ptr [edi]
- EmitString("83 EF 04"); // sub edi, 4
+ EmitString("8B 04 9F"); // mov eax, dword ptr [edi + ebx * 4]
+ STACK_POP(1); // sub bl, 1
EmitString("85 C0"); // test eax, eax
- // Jump to syscall code
+ // Jump to syscall code, 1 byte offset should suffice
EmitString("7C"); // jl systemCall
jmpSystemCall = compiledOfs++;
@@ -399,17 +591,19 @@ int EmitCallProcedure(vm_t *vm)
// Error jump if invalid jump target
EmitString("73"); // jae badAddr
jmpBadAddr = compiledOfs++;
-
- EmitString("FF 14 85"); // call dword ptr [vm->instructionPointers + eax * 4]
+
+#if idx64
+ EmitRexString(0x49, "FF 14 C0"); // call qword ptr [r8 + eax * 8]
+#else
+ EmitString("FF 14 85"); // call dword ptr [vm->instructionPointers + eax * 4]
Emit4((intptr_t) vm->instructionPointers);
- EmitString("8B 07"); // mov eax, dword ptr [edi]
- EmitString("C3"); // ret
+#endif
+ EmitString("8B 04 9F"); // mov eax, dword ptr [edi + ebx * 4]
+ EmitString("C3"); // ret
// badAddr:
SET_JMPOFS(jmpBadAddr);
- EmitString("B8"); // mov eax, ErrJump
- Emit4((intptr_t) ErrJump);
- EmitString("FF D0"); // call eax
+ EmitCallErrJump(vm, sysCallOfs);
/************ System Call ************/
@@ -417,74 +611,115 @@ int EmitCallProcedure(vm_t *vm)
SET_JMPOFS(jmpSystemCall);
retval = compiledOfs;
- EmitString("F7 D0"); // not eax
- // use ecx register to store DoSyscall address
- EmitString("B9"); // mov ecx, DoSyscall
- Emit4((intptr_t) DoSyscall);
-
- // align the stack pointer to a 16-byte-boundary
- EmitString("55"); // push ebp
- EmitString("89 E5"); // mov ebp, esp
- EmitString("83 E4 F0"); // and esp, 0xFFFFFFF0
-
- // call the syscall wrapper function
- EmitString("FF D1"); // call ecx
-
- // reset the stack pointer to its previous value
- EmitString("89 EC"); // mov esp, ebp
- EmitString("5D"); // pop ebp
+ EmitCallRel(vm, sysCallOfs);
// have opStack reg point at return value
- EmitString("83 C7 04"); // add edi, 4
+ STACK_PUSH(1); // add bl, 1
EmitString("C3"); // ret
return retval;
}
-void EmitCall(vm_t *vm, int sysCallOfs)
+/*
+=================
+EmitJumpIns
+Jump to constant instruction number
+=================
+*/
+
+void EmitJumpIns(vm_t *vm, const char *jmpop, int cdest)
{
- EmitString("51"); // push ecx
- EmitString("8B 0D"); // mov ecx, dword ptr [&vm->codeBase]
- Emit4((intptr_t) &vm->codeBase);
-
- if(sysCallOfs)
- {
- if(sysCallOfs < 0x80 || sysCallOfs > 0x7f)
- {
- EmitString("83 C1"); // add ecx, sysCallOfs
- Emit1(sysCallOfs);
- }
- else
- {
- EmitString("81 C1"); // add ecx, sysCallOfs
- Emit4(sysCallOfs);
- }
- }
+ JUSED(cdest);
+
+ EmitString(jmpop); // j??? 0x12345678
+
+ // we only know all the jump addresses in the third pass
+ if(pass == 2)
+ Emit4(vm->instructionPointers[cdest] - compiledOfs - 4);
+ else
+ compiledOfs += 4;
+}
+
+/*
+=================
+EmitCallIns
+Call to constant instruction number
+=================
+*/
- EmitString("FF D1"); // call ecx
- EmitString("59"); // pop ecx
+void EmitCallIns(vm_t *vm, int cdest)
+{
+ JUSED(cdest);
+
+ EmitString("E8"); // call 0x12345678
+
+ // we only know all the jump addresses in the third pass
+ if(pass == 2)
+ Emit4(vm->instructionPointers[cdest] - compiledOfs - 4);
+ else
+ compiledOfs += 4;
}
/*
=================
EmitCallConst
+Call to constant instruction number or syscall
=================
*/
-void EmitCallConst(vm_t *vm, int cdest, int sysCallOfs)
+void EmitCallConst(vm_t *vm, int cdest, int callProcOfsSyscall)
{
if(cdest < 0)
{
EmitString("B8"); // mov eax, cdest
Emit4(cdest);
- EmitCall(vm, sysCallOfs);
+ EmitCallRel(vm, callProcOfsSyscall);
}
else
+ EmitCallIns(vm, cdest);
+}
+
+/*
+=================
+EmitBranchConditions
+Emits x86 branch condition as given in op
+=================
+*/
+void EmitBranchConditions(vm_t *vm, int op)
+{
+ switch(op)
{
- JUSED(cdest);
- EmitString("FF 15"); // call dword ptr [vm->instructionPointers + cdest]
- Emit4((intptr_t) &vm->instructionPointers[cdest]);
+ case OP_EQ:
+ EmitJumpIns(vm, "0F 84", Constant4()); // je 0x12345678
+ break;
+ case OP_NE:
+ EmitJumpIns(vm, "0F 85", Constant4()); // jne 0x12345678
+ break;
+ case OP_LTI:
+ EmitJumpIns(vm, "0F 8C", Constant4()); // jl 0x12345678
+ break;
+ case OP_LEI:
+ EmitJumpIns(vm, "0F 8E", Constant4()); // jle 0x12345678
+ break;
+ case OP_GTI:
+ EmitJumpIns(vm, "0F 8F", Constant4()); // jg 0x12345678
+ break;
+ case OP_GEI:
+ EmitJumpIns(vm, "0F 8D", Constant4()); // jge 0x12345678
+ break;
+ case OP_LTU:
+ EmitJumpIns(vm, "0F 82", Constant4()); // jb 0x12345678
+ break;
+ case OP_LEU:
+ EmitJumpIns(vm, "0F 86", Constant4()); // jbe 0x12345678
+ break;
+ case OP_GTU:
+ EmitJumpIns(vm, "0F 87", Constant4()); // ja 0x12345678
+ break;
+ case OP_GEU:
+ EmitJumpIns(vm, "0F 83", Constant4()); // jae 0x12345678
+ break;
}
}
@@ -492,11 +727,14 @@ void EmitCallConst(vm_t *vm, int cdest,
/*
=================
ConstOptimize
+Constant values for immediately following instructions may be translated to immediate values
+instead of opStack operations, which will save expensive operations on memory
=================
*/
-qboolean ConstOptimize(vm_t *vm, int sysCallOfs)
+
+qboolean ConstOptimize(vm_t *vm, int callProcOfsSyscall)
{
- int v, opt;
+ int v;
int op1;
// we can safely perform optimizations only in case if
@@ -509,302 +747,314 @@ qboolean ConstOptimize(vm_t *vm, int sys
switch ( op1 ) {
case OP_LOAD4:
- EmitAddEDI4(vm);
- EmitString( "BB" ); // mov ebx, 0x12345678
- Emit4( (Constant4()&vm->dataMask) + (int)vm->dataBase);
- EmitString( "8B 03" ); // mov eax, dword ptr [ebx]
- EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
+ EmitPushStack(vm);
+#if idx64
+ EmitRexString(0x41, "8B 81"); // mov eax, dword ptr [r9 + 0x12345678]
+ Emit4(Constant4() & vm->dataMask);
+#else
+ EmitString("B8"); // mov eax, 0x12345678
+ EmitPtr(vm->dataBase + (Constant4() & vm->dataMask));
+ EmitString("8B 00"); // mov eax, dword ptr [eax]
+#endif
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax
+
pc++; // OP_LOAD4
instruction += 1;
return qtrue;
case OP_LOAD2:
- EmitAddEDI4(vm);
- EmitString( "BB" ); // mov ebx, 0x12345678
- Emit4( (Constant4()&vm->dataMask) + (int)vm->dataBase);
- EmitString( "0F B7 03" ); // movzx eax, word ptr [ebx]
- EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
+ EmitPushStack(vm);
+#if idx64
+ EmitRexString(0x41, "0F B7 81"); // movzx eax, word ptr [r9 + 0x12345678]
+ Emit4(Constant4() & vm->dataMask);
+#else
+ EmitString("B8"); // mov eax, 0x12345678
+ EmitPtr(vm->dataBase + (Constant4() & vm->dataMask));
+ EmitString("0F B7 00"); // movzx eax, word ptr [eax]
+#endif
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax
+
pc++; // OP_LOAD2
instruction += 1;
return qtrue;
case OP_LOAD1:
- EmitAddEDI4(vm);
- EmitString( "BB" ); // mov ebx, 0x12345678
- Emit4( (Constant4()&vm->dataMask) + (int)vm->dataBase);
- EmitString( "0F B6 03" ); // movzx eax, byte ptr [ebx]
- EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
+ EmitPushStack(vm);
+#if idx64
+ EmitRexString(0x41, "0F B6 81"); // movzx eax, byte ptr [r9 + 0x12345678]
+ Emit4(Constant4() & vm->dataMask);
+#else
+ EmitString("B8"); // mov eax, 0x12345678
+ EmitPtr(vm->dataBase + (Constant4() & vm->dataMask));
+ EmitString("0F B6 00"); // movzx eax, byte ptr [eax]
+#endif
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax
+
pc++; // OP_LOAD1
instruction += 1;
return qtrue;
case OP_STORE4:
- opt = EmitMovEBXEDI(vm, (vm->dataMask & ~3));
- EmitString( "B8" ); // mov eax, 0x12345678
- Emit4( Constant4() );
-// if (!opt) {
-// EmitString( "81 E3" ); // and ebx, 0x12345678
-// Emit4( vm->dataMask & ~3 );
-// }
- EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax
- Emit4( (int)vm->dataBase );
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ EmitMovEAXStack(vm, (vm->dataMask & ~3));
+#if idx64
+ EmitRexString(0x41, "C7 04 01"); // mov dword ptr [r9 + eax], 0x12345678
+ Emit4(Constant4());
+#else
+ EmitString("C7 80"); // mov dword ptr [eax + 0x12345678], 0x12345678
+ Emit4((intptr_t) vm->dataBase);
+ Emit4(Constant4());
+#endif
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
pc++; // OP_STORE4
instruction += 1;
return qtrue;
case OP_STORE2:
- opt = EmitMovEBXEDI(vm, (vm->dataMask & ~1));
- EmitString( "B8" ); // mov eax, 0x12345678
- Emit4( Constant4() );
-// if (!opt) {
-// EmitString( "81 E3" ); // and ebx, 0x12345678
-// Emit4( vm->dataMask & ~1 );
-// }
- EmitString( "66 89 83" ); // mov word ptr [ebx+0x12345678], eax
- Emit4( (int)vm->dataBase );
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- pc++; // OP_STORE2
+ EmitMovEAXStack(vm, (vm->dataMask & ~1));
+#if idx64
+ Emit1(0x66); // mov word ptr [r9 + eax], 0x1234
+ EmitRexString(0x41, "C7 04 01");
+ Emit2(Constant4());
+#else
+ EmitString("66 C7 80"); // mov word ptr [eax + 0x12345678], 0x1234
+ Emit4((intptr_t) vm->dataBase);
+ Emit2(Constant4());
+#endif
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+
+ pc++; // OP_STORE2
instruction += 1;
return qtrue;
case OP_STORE1:
- opt = EmitMovEBXEDI(vm, vm->dataMask);
- EmitString( "B8" ); // mov eax, 0x12345678
- Emit4( Constant4() );
-// if (!opt) {
-// EmitString( "81 E3" ); // and ebx, 0x12345678
-// Emit4( vm->dataMask );
-// }
- EmitString( "88 83" ); // mov byte ptr [ebx+0x12345678], eax
- Emit4( (int)vm->dataBase );
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- pc++; // OP_STORE4
+ EmitMovEAXStack(vm, vm->dataMask);
+#if idx64
+ EmitRexString(0x41, "C6 04 01"); // mov byte [r9 + eax], 0x12
+ Emit1(Constant4());
+#else
+ EmitString("C6 80"); // mov byte ptr [eax + 0x12345678], 0x12
+ Emit4((intptr_t) vm->dataBase);
+ Emit1(Constant4());
+#endif
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+
+ pc++; // OP_STORE1
instruction += 1;
return qtrue;
case OP_ADD:
v = Constant4();
- EmitMovEAXEDI( vm );
- if ( v >= 0 && v <= 127 ) {
- EmitString( "83 C0" ); // add eax, 0x7F
- Emit1( v );
- } else {
- EmitString( "05" ); // add eax, 0x12345678
- Emit4( v );
+
+ EmitMovEAXStack(vm, 0);
+ if(iss8(v))
+ {
+ EmitString("83 C0"); // add eax, 0x7F
+ Emit1(v);
}
- EmitCommand( LAST_COMMAND_MOV_EDI_EAX );
+ else
+ {
+ EmitString("05"); // add eax, 0x12345678
+ Emit4(v);
+ }
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX);
+
pc++; // OP_ADD
instruction += 1;
return qtrue;
case OP_SUB:
v = Constant4();
- EmitMovEAXEDI( vm );
- if ( v >= 0 && v <= 127 ) {
- EmitString( "83 E8" ); // sub eax, 0x7F
- Emit1( v );
- } else {
- EmitString( "2D" ); // sub eax, 0x12345678
- Emit4( v );
+
+ EmitMovEAXStack(vm, 0);
+ if(iss8(v))
+ {
+ EmitString("83 E8"); // sub eax, 0x7F
+ Emit1(v);
}
- EmitCommand( LAST_COMMAND_MOV_EDI_EAX );
+ else
+ {
+ EmitString("2D"); // sub eax, 0x12345678
+ Emit4(v);
+ }
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX);
+
pc++; // OP_SUB
instruction += 1;
return qtrue;
case OP_MULI:
v = Constant4();
- EmitMovEAXEDI( vm );
- if ( v >= 0 && v <= 127 ) {
- EmitString( "6B C0" ); // imul eax, 0x7F
- Emit1( v );
- } else {
- EmitString( "69 C0" ); // imul eax, 0x12345678
- Emit4( v );
+
+ EmitMovEAXStack(vm, 0);
+ if(iss8(v))
+ {
+ EmitString("6B C0"); // imul eax, 0x7F
+ Emit1(v);
}
- EmitCommand( LAST_COMMAND_MOV_EDI_EAX );
+ else
+ {
+ EmitString("69 C0"); // imul eax, 0x12345678
+ Emit4(v);
+ }
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX);
pc++; // OP_MULI
instruction += 1;
+
return qtrue;
case OP_LSH:
v = NextConstant4();
- if ( v < 0 || v > 31 )
+ if(v < 0 || v > 31)
break;
- EmitMovEAXEDI( vm );
- EmitString( "C1 E0" ); // shl dword ptr [edi], 0x12
- Emit1( v );
- EmitCommand( LAST_COMMAND_MOV_EDI_EAX );
- pc += 5; // CONST + OP_LSH
+
+ EmitMovEAXStack(vm, 0);
+ EmitString("C1 E0"); // shl eax, 0x12
+ Emit1(v);
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX);
+
+ pc += 5; // CONST + OP_LSH
instruction += 1;
return qtrue;
case OP_RSHI:
v = NextConstant4();
- if ( v < 0 || v > 31 )
+ if(v < 0 || v > 31)
break;
- EmitMovEAXEDI( vm );
- EmitString( "C1 F8" ); // sar eax, 0x12
- Emit1( v );
- EmitCommand( LAST_COMMAND_MOV_EDI_EAX );
- pc += 5; // CONST + OP_RSHI
+
+ EmitMovEAXStack(vm, 0);
+ EmitString("C1 F8"); // sar eax, 0x12
+ Emit1(v);
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX);
+
+ pc += 5; // CONST + OP_RSHI
instruction += 1;
return qtrue;
case OP_RSHU:
v = NextConstant4();
- if ( v < 0 || v > 31 )
+ if(v < 0 || v > 31)
break;
- EmitMovEAXEDI( vm );
- EmitString( "C1 E8" ); // shr eax, 0x12
- Emit1( v );
- EmitCommand( LAST_COMMAND_MOV_EDI_EAX );
- pc += 5; // CONST + OP_RSHU
+
+ EmitMovEAXStack(vm, 0);
+ EmitString("C1 E8"); // shr eax, 0x12
+ Emit1(v);
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX);
+
+ pc += 5; // CONST + OP_RSHU
instruction += 1;
return qtrue;
case OP_BAND:
v = Constant4();
- EmitMovEAXEDI( vm );
- if ( v >= 0 && v <= 127 ) {
- EmitString( "83 E0" ); // and eax, 0x7F
- Emit1( v );
- } else {
- EmitString( "25" ); // and eax, 0x12345678
- Emit4( v );
+
+ EmitMovEAXStack(vm, 0);
+ if(iss8(v))
+ {
+ EmitString("83 E0"); // and eax, 0x7F
+ Emit1(v);
+ }
+ else
+ {
+ EmitString("25"); // and eax, 0x12345678
+ Emit4(v);
}
- EmitCommand( LAST_COMMAND_MOV_EDI_EAX );
- pc += 1; // OP_BAND
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX);
+
+ pc += 1; // OP_BAND
instruction += 1;
return qtrue;
case OP_BOR:
v = Constant4();
- EmitMovEAXEDI( vm );
- if ( v >= 0 && v <= 127 ) {
- EmitString( "83 C8" ); // or eax, 0x7F
- Emit1( v );
- } else {
- EmitString( "0D" ); // or eax, 0x12345678
- Emit4( v );
+
+ EmitMovEAXStack(vm, 0);
+ if(iss8(v))
+ {
+ EmitString("83 C8"); // or eax, 0x7F
+ Emit1(v);
}
- EmitCommand( LAST_COMMAND_MOV_EDI_EAX );
- pc += 1; // OP_BOR
+ else
+ {
+ EmitString("0D"); // or eax, 0x12345678
+ Emit4(v);
+ }
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX);
+
+ pc += 1; // OP_BOR
instruction += 1;
return qtrue;
case OP_BXOR:
v = Constant4();
- EmitMovEAXEDI( vm );
- if ( v >= 0 && v <= 127 ) {
- EmitString( "83 F0" ); // xor eax, 0x7F
- Emit1( v );
- } else {
- EmitString( "35" ); // xor eax, 0x12345678
- Emit4( v );
+
+ EmitMovEAXStack(vm, 0);
+ if(iss8(v))
+ {
+ EmitString("83 F0"); // xor eax, 0x7F
+ Emit1(v);
}
- EmitCommand( LAST_COMMAND_MOV_EDI_EAX );
- pc += 1; // OP_BXOR
- instruction += 1;
- return qtrue;
-
- case OP_EQF:
- case OP_NEF:
- if ( NextConstant4() != 0 )
- break;
- pc += 5; // CONST + OP_EQF|OP_NEF
- EmitMovEAXEDI( vm );
- EmitCommand(LAST_COMMAND_SUB_DI_4);
- // floating point hack :)
- EmitString( "25" ); // and eax, 0x7FFFFFFF
- Emit4( 0x7FFFFFFF );
- if ( op1 == OP_EQF )
- EmitString( "75 06" ); // jnz +6
else
- EmitString( "74 06" ); // jz +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
+ {
+ EmitString("35"); // xor eax, 0x12345678
+ Emit4(v);
+ }
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX);
+
+ pc += 1; // OP_BXOR
instruction += 1;
return qtrue;
case OP_EQ:
case OP_NE:
- v = Constant4();
- EmitMovEAXEDI( vm );
- EmitCommand(LAST_COMMAND_SUB_DI_4);
- if ( v == 0 ) {
- EmitString( "85 C0" ); // test eax, eax
- } else {
- EmitString( "3D" ); // cmp eax, 0x12345678
- Emit4( v );
- }
- pc += 1; // OP_EQ/OP_NE
- if ( op1 == OP_EQ )
- EmitString( "75 06" ); // jne +6
- else
- EmitString( "74 06" ); // je +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- instruction += 1;
- return qtrue;
-
- case OP_GEI:
+ case OP_LTI:
+ case OP_LEI:
case OP_GTI:
- v = Constant4();
- EmitMovEAXEDI( vm );
- EmitCommand( LAST_COMMAND_SUB_DI_4 );
- EmitString( "3D" ); // cmp eax, 0x12345678
- Emit4( v );
- pc += 1; // OP_GEI|OP_GTI
- if ( op1 == OP_GEI )
- EmitString( "7C 06" ); // jl +6
- else
- EmitString( "7E 06" ); // jle +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- instruction += 1;
+ case OP_GEI:
+ case OP_LTU:
+ case OP_LEU:
+ case OP_GTU:
+ case OP_GEU:
+ EmitMovEAXStack(vm, 0);
+ EmitCommand(LAST_COMMAND_SUB_BL_1);
+ EmitString("3D"); // cmp eax, 0x12345678
+ Emit4(Constant4());
+
+ pc++; // OP_*
+ EmitBranchConditions(vm, op1);
+ instruction++;
+
return qtrue;
- case OP_LEI:
- case OP_LTI:
- v = Constant4();
- EmitMovEAXEDI( vm );
- EmitCommand( LAST_COMMAND_SUB_DI_4 );
- EmitString( "3D" ); // cmp eax, 0x12345678
- Emit4( v );
- pc += 1; // OP_GEI|OP_GTI
- if ( op1 == OP_LEI )
- EmitString( "7F 06" ); // jg +6
+ case OP_EQF:
+ case OP_NEF:
+ if(NextConstant4())
+ break;
+ pc += 5; // CONST + OP_EQF|OP_NEF
+
+ EmitMovEAXStack(vm, 0);
+ EmitCommand(LAST_COMMAND_SUB_BL_1);
+ // floating point hack :)
+ EmitString("25"); // and eax, 0x7FFFFFFF
+ Emit4(0x7FFFFFFF);
+ if(op1 == OP_EQF)
+ EmitJumpIns(vm, "0F 84", Constant4()); // jz 0x12345678
else
- EmitString( "7D 06" ); // jge +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
+ EmitJumpIns(vm, "0F 85", Constant4()); // jnz 0x12345678
+
instruction += 1;
return qtrue;
+
case OP_JUMP:
- v = Constant4();
- JUSED(v);
- EmitString( "FF 25" ); // jmp dword ptr [instructionPointers + 0x12345678]
- Emit4( (int)vm->instructionPointers + v*4 );
+ EmitJumpIns(vm, "E9", Constant4()); // jmp 0x12345678
+
pc += 1; // OP_JUMP
instruction += 1;
return qtrue;
case OP_CALL:
- if ( NextConstant4() < 0 )
- break;
v = Constant4();
- EmitCallConst(vm, v, sysCallOfs);
+ EmitCallConst(vm, v, callProcOfsSyscall);
pc += 1; // OP_CALL
instruction += 1;
@@ -817,23 +1067,23 @@ qboolean ConstOptimize(vm_t *vm, int sys
return qfalse;
}
-
/*
=================
VM_Compile
=================
*/
-void VM_Compile( vm_t *vm, vmHeader_t *header ) {
+void VM_Compile(vm_t *vm, vmHeader_t *header)
+{
int op;
int maxLength;
int v;
int i;
- int sysCallOfs;
+ int callProcOfsSyscall, callProcOfs, callDoSyscallOfs;
jusedSize = header->instructionCount + 2;
// allocate a very large temp buffer, we will shrink it later
- maxLength = header->codeLength * 8;
+ maxLength = header->codeLength * 8 + 64;
buf = Z_Malloc(maxLength);
jused = Z_Malloc(jusedSize);
code = Z_Malloc(header->codeLength+32);
@@ -855,10 +1105,13 @@ void VM_Compile( vm_t *vm, vmHeader_t *h
// Start buffer with x86-VM specific procedures
compiledOfs = 0;
- sysCallOfs = EmitCallProcedure(vm);
+
+ callDoSyscallOfs = compiledOfs;
+ callProcOfs = EmitCallDoSyscall(vm);
+ callProcOfsSyscall = EmitCallProcedure(vm, callDoSyscallOfs);
vm->entryOfs = compiledOfs;
- for(pass=0;pass<2;pass++) {
+ for(pass=0; pass < 3; pass++) {
oc0 = -23423;
oc1 = -234354;
pop0 = -43435;
@@ -901,525 +1154,491 @@ void VM_Compile( vm_t *vm, vmHeader_t *h
case 0:
break;
case OP_BREAK:
- EmitString( "CC" ); // int 3
+ EmitString("CC"); // int 3
break;
case OP_ENTER:
- EmitString( "81 EE" ); // sub esi, 0x12345678
- Emit4( Constant4() );
+ EmitString("81 EE"); // sub esi, 0x12345678
+ Emit4(Constant4());
break;
case OP_CONST:
- if(ConstOptimize(vm, sysCallOfs))
+ if(ConstOptimize(vm, callProcOfsSyscall))
break;
- EmitAddEDI4(vm);
- EmitString( "C7 07" ); // mov dword ptr [edi], 0x12345678
+ EmitPushStack(vm);
+ EmitString("C7 04 9F"); // mov dword ptr [edi + ebx * 4], 0x12345678
lastConst = Constant4();
- Emit4( lastConst );
- if (code[pc] == OP_JUMP) {
+
+ Emit4(lastConst);
+ if(code[pc] == OP_JUMP)
JUSED(lastConst);
- }
+
break;
case OP_LOCAL:
- EmitAddEDI4(vm);
- EmitString( "8D 86" ); // lea eax, [0x12345678 + esi]
+ EmitPushStack(vm);
+ EmitString("8D 86"); // lea eax, [0x12345678 + esi]
oc0 = oc1;
oc1 = Constant4();
- Emit4( oc1 );
- EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
+ Emit4(oc1);
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax
break;
case OP_ARG:
- EmitMovEAXEDI(vm); // mov eax,dword ptr [edi]
- EmitString( "89 86" ); // mov dword ptr [esi+database],eax
- Emit4((Constant1() & vm->dataMask & 0xFF) + (int) vm->dataBase);
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ EmitMovEAXStack(vm, 0); // mov eax, dword ptr [edi + ebx * 4]
+ EmitString("8B D6"); // mov edx, esi
+ EmitString("81 C2"); // add edx, 0x12345678
+ Emit4((Constant1() & 0xFF));
+ MASK_REG("E2", vm->dataMask); // and edx, 0x12345678
+#if idx64
+ EmitRexString(0x41, "89 04 11"); // mov dword ptr [r9 + edx], eax
+#else
+ EmitString("89 82"); // mov dword ptr [edx + 0x12345678], eax
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
break;
case OP_CALL:
- EmitCall(vm, 0);
+ EmitCallRel(vm, callProcOfs);
break;
case OP_PUSH:
- EmitAddEDI4(vm);
+ EmitPushStack(vm);
break;
case OP_POP:
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
break;
case OP_LEAVE:
v = Constant4();
- EmitString( "81 C6" ); // add esi, 0x12345678
- Emit4( v );
- EmitString( "C3" ); // ret
+ EmitString("81 C6"); // add esi, 0x12345678
+ Emit4(v);
+ EmitString("C3"); // ret
break;
case OP_LOAD4:
- if (code[pc] == OP_CONST && code[pc+5] == OP_ADD && code[pc+6] == OP_STORE4) {
- if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) {
- compiledOfs -= 11;
- vm->instructionPointers[ instruction-1 ] = compiledOfs;
+ if (code[pc] == OP_CONST && code[pc+5] == OP_ADD && code[pc+6] == OP_STORE4)
+ {
+ if(oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL)
+ {
+ compiledOfs -= 12;
+ vm->instructionPointers[instruction - 1] = compiledOfs;
}
- pc++; // OP_CONST
+
+ pc++; // OP_CONST
v = Constant4();
- EmitMovEBXEDI(vm, vm->dataMask);
- if (v == 1 && oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) {
- EmitString( "FF 83"); // inc dword ptr [ebx + 0x12345678]
- Emit4( (int)vm->dataBase );
- } else {
- EmitString( "8B 83" ); // mov eax, dword ptr [ebx + 0x12345678]
- Emit4( (int)vm->dataBase );
- EmitString( "05" ); // add eax, const
- Emit4( v );
- if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) {
- EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax
- Emit4( (int)vm->dataBase );
- } else {
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- EmitString( "8B 1F" ); // mov ebx, dword ptr [edi]
- EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax
- Emit4( (int)vm->dataBase );
+
+ EmitMovEDXStack(vm, vm->dataMask);
+ if(v == 1 && oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL)
+ {
+#if idx64
+ EmitRexString(0x41, "FF 04 11"); // inc dword ptr [r9 + edx]
+#else
+ EmitString("FF 82"); // inc dword ptr [edx + 0x12345678]
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ }
+ else
+ {
+#if idx64
+ EmitRexString(0x41, "8B 04 11"); // mov eax, dword ptr [r9 + edx]
+#else
+ EmitString("8B 82"); // mov eax, dword ptr [edx + 0x12345678]
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ EmitString("05"); // add eax, v
+ Emit4(v);
+
+ if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL)
+ {
+#if idx64
+ EmitRexString(0x41, "89 04 11"); // mov dword ptr [r9 + edx], eax
+#else
+ EmitString("89 82"); // mov dword ptr [edx + 0x12345678], eax
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ }
+ else
+ {
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ EmitString("8B 14 9F"); // mov edx, dword ptr [edi + ebx * 4]
+ MASK_REG("E2", vm->dataMask); // and edx, 0x12345678
+#if idx64
+ EmitRexString(0x41, "89 04 11"); // mov dword ptr [r9 + edx], eax
+#else
+ EmitString("89 82"); // mov dword ptr [edx + 0x12345678], eax
+ Emit4((intptr_t) vm->dataBase);
+#endif
}
}
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
pc++; // OP_ADD
pc++; // OP_STORE
instruction += 3;
break;
}
- if (code[pc] == OP_CONST && code[pc+5] == OP_SUB && code[pc+6] == OP_STORE4) {
- if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) {
- compiledOfs -= 11;
- vm->instructionPointers[ instruction-1 ] = compiledOfs;
+ if(code[pc] == OP_CONST && code[pc+5] == OP_SUB && code[pc+6] == OP_STORE4)
+ {
+ if(oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL)
+ {
+ compiledOfs -= 12;
+ vm->instructionPointers[instruction - 1] = compiledOfs;
}
- EmitMovEBXEDI(vm, vm->dataMask);
- EmitString( "8B 83" ); // mov eax, dword ptr [ebx + 0x12345678]
- Emit4( (int)vm->dataBase );
- pc++; // OP_CONST
+
+ pc++; // OP_CONST
v = Constant4();
- if (v == 1 && oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) {
- EmitString( "FF 8B"); // dec dword ptr [ebx + 0x12345678]
- Emit4( (int)vm->dataBase );
- } else {
- EmitString( "2D" ); // sub eax, const
- Emit4( v );
- if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) {
- EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax
- Emit4( (int)vm->dataBase );
- } else {
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- EmitString( "8B 1F" ); // mov ebx, dword ptr [edi]
- EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax
- Emit4( (int)vm->dataBase );
+
+ EmitMovEDXStack(vm, vm->dataMask);
+ if(v == 1 && oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL)
+ {
+#if idx64
+ EmitRexString(0x41, "FF 0C 11"); // dec dword ptr [r9 + edx]
+#else
+ EmitString("FF 8A"); // dec dword ptr [edx + 0x12345678]
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ }
+ else
+ {
+#if idx64
+ EmitRexString(0x41, "8B 04 11"); // mov eax, dword ptr [r9 + edx]
+#else
+ EmitString("8B 82"); // mov eax, dword ptr [edx + 0x12345678]
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ EmitString("2D"); // sub eax, v
+ Emit4(v);
+
+ if(oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL)
+ {
+#if idx64
+ EmitRexString(0x41, "89 04 11"); // mov dword ptr [r9 + edx], eax
+#else
+ EmitString("89 82"); // mov dword ptr [edx + 0x12345678], eax
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ }
+ else
+ {
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ EmitString("8B 14 9F"); // mov edx, dword ptr [edi + ebx * 4]
+ MASK_REG("E2", vm->dataMask); // and edx, 0x12345678
+#if idx64
+ EmitRexString(0x41, "89 04 11"); // mov dword ptr [r9 + edx], eax
+#else
+ EmitString("89 82"); // mov dword ptr [edx + 0x12345678], eax
+ Emit4((intptr_t) vm->dataBase);
+#endif
}
}
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
pc++; // OP_SUB
pc++; // OP_STORE
instruction += 3;
break;
}
- if (buf[compiledOfs-2] == 0x89 && buf[compiledOfs-1] == 0x07) {
- compiledOfs -= 2;
- vm->instructionPointers[ instruction-1 ] = compiledOfs;
- EmitString( "8B 80"); // mov eax, dword ptr [eax + 0x1234567]
- Emit4( (int)vm->dataBase );
- EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
+ if(buf[compiledOfs - 3] == 0x89 && buf[compiledOfs - 2] == 0x04 && buf[compiledOfs - 1] == 0x9F)
+ {
+ compiledOfs -= 3;
+ vm->instructionPointers[instruction - 1] = compiledOfs;
+ MASK_REG("E0", vm->dataMask); // and eax, 0x12345678
+#if idx64
+ EmitRexString(0x41, "8B 04 01"); // mov eax, dword ptr [r9 + eax]
+#else
+ EmitString("8B 80"); // mov eax, dword ptr [eax + 0x1234567]
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax
break;
}
- EmitMovEBXEDI(vm, vm->dataMask);
- EmitString( "8B 83" ); // mov eax, dword ptr [ebx + 0x12345678]
- Emit4( (int)vm->dataBase );
- EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
+
+ EmitMovEAXStack(vm, vm->dataMask);
+#if idx64
+ EmitRexString(0x41, "8B 04 01"); // mov eax, dword ptr [r9 + eax]
+#else
+ EmitString("8B 80"); // mov eax, dword ptr [eax + 0x12345678]
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax
break;
case OP_LOAD2:
- EmitMovEBXEDI(vm, vm->dataMask);
- EmitString( "0F B7 83" ); // movzx eax, word ptr [ebx + 0x12345678]
- Emit4( (int)vm->dataBase );
- EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
+ EmitMovEAXStack(vm, vm->dataMask);
+#if idx64
+ EmitRexString(0x41, "0F B7 04 01"); // movzx eax, word ptr [r9 + eax]
+#else
+ EmitString("0F B7 80"); // movzx eax, word ptr [eax + 0x12345678]
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax
break;
case OP_LOAD1:
- EmitMovEBXEDI(vm, vm->dataMask);
- EmitString( "0F B6 83" ); // movzx eax, byte ptr [ebx + 0x12345678]
- Emit4( (int)vm->dataBase );
- EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
+ EmitMovEAXStack(vm, vm->dataMask);
+#if idx64
+ EmitRexString(0x41, "0F B6 04 01"); // movzx eax, byte ptr [r9 + eax]
+#else
+ EmitString("0F B6 80"); // movzx eax, byte ptr [eax + 0x12345678]
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax
break;
case OP_STORE4:
- EmitMovEAXEDI(vm);
- EmitString( "8B 5F FC" ); // mov ebx, dword ptr [edi-4]
-// if (pop1 != OP_CALL) {
-// EmitString( "81 E3" ); // and ebx, 0x12345678
-// Emit4( vm->dataMask & ~3 );
-// }
- EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax
- Emit4( (int)vm->dataBase );
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ EmitMovEAXStack(vm, 0);
+ EmitString("8B 54 9F FC"); // mov edx, dword ptr -4[edi + ebx * 4]
+ MASK_REG("E2", vm->dataMask & ~3); // and edx, 0x12345678
+#if idx64
+ EmitRexString(0x41, "89 04 11"); // mov dword ptr [r9 + edx], eax
+#else
+ EmitString("89 82"); // mov dword ptr [edx + 0x12345678], eax
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ EmitCommand(LAST_COMMAND_SUB_BL_2); // sub bl, 2
break;
case OP_STORE2:
- EmitMovEAXEDI(vm);
- EmitString( "8B 5F FC" ); // mov ebx, dword ptr [edi-4]
-// EmitString( "81 E3" ); // and ebx, 0x12345678
-// Emit4( vm->dataMask & ~1 );
- EmitString( "66 89 83" ); // mov word ptr [ebx+0x12345678], eax
- Emit4( (int)vm->dataBase );
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ EmitMovEAXStack(vm, 0);
+ EmitString("8B 54 9F FC"); // mov edx, dword ptr -4[edi + ebx * 4]
+ MASK_REG("E2", vm->dataMask & ~1); // and edx, 0x12345678
+#if idx64
+ Emit1(0x66); // mov word ptr [r9 + edx], eax
+ EmitRexString(0x41, "89 04 11");
+#else
+ EmitString("66 89 82"); // mov word ptr [edx + 0x12345678], eax
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ EmitCommand(LAST_COMMAND_SUB_BL_2); // sub bl, 2
break;
case OP_STORE1:
- EmitMovEAXEDI(vm);
- EmitString( "8B 5F FC" ); // mov ebx, dword ptr [edi-4]
-// EmitString( "81 E3" ); // and ebx, 0x12345678
-// Emit4( vm->dataMask );
- EmitString( "88 83" ); // mov byte ptr [ebx+0x12345678], eax
- Emit4( (int)vm->dataBase );
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ EmitMovEAXStack(vm, 0);
+ EmitString("8B 54 9F FC"); // mov edx, dword ptr -4[edi + ebx * 4]
+ MASK_REG("E2", vm->dataMask); // and edx, 0x12345678
+#if idx64
+ EmitRexString(0x41, "88 04 11"); // mov byte ptr [r9 + edx], eax
+#else
+ EmitString("88 82"); // mov byte ptr [edx + 0x12345678], eax
+ Emit4((intptr_t) vm->dataBase);
+#endif
+ EmitCommand(LAST_COMMAND_SUB_BL_2); // sub bl, 2
break;
case OP_EQ:
- EmitMovEAXEDI( vm );
- EmitCommand( LAST_COMMAND_SUB_DI_8 ); // sub edi, 8
- EmitString( "3B 47 04" ); // cmp eax, dword ptr [edi+4]
- EmitString( "75 06" ); // jne +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
case OP_NE:
- EmitMovEAXEDI( vm );
- EmitCommand( LAST_COMMAND_SUB_DI_8 ); // sub edi, 8
- EmitString( "3B 47 04" ); // cmp eax, dword ptr [edi+4]
- EmitString( "74 06" ); // je +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
case OP_LTI:
- EmitMovEAXEDI( vm );
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "39 47 04" ); // cmp dword ptr [edi+4], eax
- EmitString( "7D 06" ); // jnl +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
case OP_LEI:
- EmitMovEAXEDI( vm );
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "39 47 04" ); // cmp dword ptr [edi+4], eax
- EmitString( "7F 06" ); // jnle +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
case OP_GTI:
- EmitMovEAXEDI( vm );
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "39 47 04" ); // cmp eax, dword ptr [edi+4]
- EmitString( "7E 06" ); // jng +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
case OP_GEI:
- EmitMovEAXEDI( vm );
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "39 47 04" ); // cmp eax, dword ptr [edi+4]
- EmitString( "7C 06" ); // jnge +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
case OP_LTU:
- EmitMovEAXEDI( vm );
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "39 47 04" ); // cmp eax, dword ptr [edi+4]
- EmitString( "73 06" ); // jnb +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
case OP_LEU:
- EmitMovEAXEDI( vm );
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "39 47 04" ); // cmp eax, dword ptr [edi+4]
- EmitString( "77 06" ); // jnbe +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
case OP_GTU:
- EmitMovEAXEDI( vm );
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "39 47 04" ); // cmp eax, dword ptr [edi+4]
- EmitString( "76 06" ); // jna +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
case OP_GEU:
- EmitMovEAXEDI( vm );
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "39 47 04" ); // cmp eax, dword ptr [edi+4]
- EmitString( "72 06" ); // jnae +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
+ EmitMovEAXStack(vm, 0);
+ EmitCommand(LAST_COMMAND_SUB_BL_2); // sub bl, 2
+ EmitString("39 44 9F 04"); // cmp eax, dword ptr 4[edi + ebx * 4]
+
+ EmitBranchConditions(vm, op);
+ break;
case OP_EQF:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "D9 47 04" ); // fld dword ptr [edi+4]
- EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8]
- EmitString( "DF E0" ); // fnstsw ax
- EmitString( "F6 C4 40" ); // test ah,0x40
- EmitString( "74 06" ); // je +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
case OP_NEF:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "D9 47 04" ); // fld dword ptr [edi+4]
- EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8]
- EmitString( "DF E0" ); // fnstsw ax
- EmitString( "F6 C4 40" ); // test ah,0x40
- EmitString( "75 06" ); // jne +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
case OP_LTF:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "D9 47 04" ); // fld dword ptr [edi+4]
- EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8]
- EmitString( "DF E0" ); // fnstsw ax
- EmitString( "F6 C4 01" ); // test ah,0x01
- EmitString( "74 06" ); // je +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
case OP_LEF:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "D9 47 04" ); // fld dword ptr [edi+4]
- EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8]
- EmitString( "DF E0" ); // fnstsw ax
- EmitString( "F6 C4 41" ); // test ah,0x41
- EmitString( "74 06" ); // je +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
case OP_GTF:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "D9 47 04" ); // fld dword ptr [edi+4]
- EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8]
- EmitString( "DF E0" ); // fnstsw ax
- EmitString( "F6 C4 41" ); // test ah,0x41
- EmitString( "75 06" ); // jne +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
- break;
case OP_GEF:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "D9 47 04" ); // fld dword ptr [edi+4]
- EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8]
- EmitString( "DF E0" ); // fnstsw ax
- EmitString( "F6 C4 01" ); // test ah,0x01
- EmitString( "75 06" ); // jne +6
- EmitString( "FF 25" ); // jmp [0x12345678]
- v = Constant4();
- JUSED(v);
- Emit4( (int)vm->instructionPointers + v*4 );
+ EmitCommand(LAST_COMMAND_SUB_BL_2); // sub bl, 2
+ EmitString("D9 44 9F 04"); // fld dword ptr 4[edi + ebx * 4]
+ EmitString("D8 5C 9F 08"); // fcomp dword ptr 8[edi + ebx * 4]
+ EmitString("DF E0"); // fnstsw ax
+
+ switch(op)
+ {
+ case OP_EQF:
+ EmitString("F6 C4 40"); // test ah,0x40
+ EmitJumpIns(vm, "0F 85", Constant4()); // jne 0x12345678
+ break;
+ case OP_NEF:
+ EmitString("F6 C4 40"); // test ah,0x40
+ EmitJumpIns(vm, "0F 84", Constant4()); // je 0x12345678
+ break;
+ case OP_LTF:
+ EmitString("F6 C4 01"); // test ah,0x01
+ EmitJumpIns(vm, "0F 85", Constant4()); // jne 0x12345678
+ break;
+ case OP_LEF:
+ EmitString("F6 C4 41"); // test ah,0x41
+ EmitJumpIns(vm, "0F 85", Constant4()); // jne 0x12345678
+ break;
+ case OP_GTF:
+ EmitString("F6 C4 41"); // test ah,0x41
+ EmitJumpIns(vm, "0F 84", Constant4()); // je 0x12345678
+ break;
+ case OP_GEF:
+ EmitString("F6 C4 01"); // test ah,0x01
+ EmitJumpIns(vm, "0F 84", Constant4()); // je 0x12345678
break;
+ }
+ break;
case OP_NEGI:
- EmitMovEAXEDI( vm );
- EmitString( "F7 D8" ); // neg eax
- EmitCommand( LAST_COMMAND_MOV_EDI_EAX );
+ EmitMovEAXStack(vm, 0);
+ EmitString("F7 D8"); // neg eax
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX);
break;
case OP_ADD:
- EmitMovEAXEDI(vm); // mov eax, dword ptr [edi]
- EmitString( "01 47 FC" ); // add dword ptr [edi-4],eax
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ EmitMovEAXStack(vm, 0); // mov eax, dword ptr [edi + ebx * 4]
+ EmitString("01 44 9F FC"); // add dword ptr -4[edi + ebx * 4], eax
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
break;
case OP_SUB:
- EmitMovEAXEDI(vm); // mov eax, dword ptr [edi]
- EmitString( "29 47 FC" ); // sub dword ptr [edi-4],eax
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ EmitMovEAXStack(vm, 0); // mov eax, dword ptr [edi + ebx * 4]
+ EmitString("29 44 9F FC"); // sub dword ptr -4[edi + ebx * 4], eax
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
break;
case OP_DIVI:
- EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
- EmitString( "99" ); // cdq
- EmitString( "F7 3F" ); // idiv dword ptr [edi]
- EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ EmitString("8B 44 9F FC"); // mov eax,dword ptr -4[edi + ebx * 4]
+ EmitString("99"); // cdq
+ EmitString("F7 3C 9F"); // idiv dword ptr [edi + ebx * 4]
+ EmitString("89 44 9F FC"); // mov dword ptr -4[edi + ebx * 4],eax
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
break;
case OP_DIVU:
- EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
- EmitString( "33 D2" ); // xor edx, edx
- EmitString( "F7 37" ); // div dword ptr [edi]
- EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ EmitString("8B 44 9F FC"); // mov eax,dword ptr -4[edi + ebx * 4]
+ EmitString("33 D2"); // xor edx, edx
+ EmitString("F7 34 9F"); // div dword ptr [edi + ebx * 4]
+ EmitString("89 44 9F FC"); // mov dword ptr -4[edi + ebx * 4],eax
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
break;
case OP_MODI:
- EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
- EmitString( "99" ); // cdq
- EmitString( "F7 3F" ); // idiv dword ptr [edi]
- EmitString( "89 57 FC" ); // mov dword ptr [edi-4],edx
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ EmitString("8B 44 9F FC"); // mov eax,dword ptr -4[edi + ebx * 4]
+ EmitString("99" ); // cdq
+ EmitString("F7 3C 9F"); // idiv dword ptr [edi + ebx * 4]
+ EmitString("89 54 9F FC"); // mov dword ptr -4[edi + ebx * 4],edx
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
break;
case OP_MODU:
- EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
- EmitString( "33 D2" ); // xor edx, edx
- EmitString( "F7 37" ); // div dword ptr [edi]
- EmitString( "89 57 FC" ); // mov dword ptr [edi-4],edx
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ EmitString("8B 44 9F FC"); // mov eax,dword ptr -4[edi + ebx * 4]
+ EmitString("33 D2"); // xor edx, edx
+ EmitString("F7 34 9F"); // div dword ptr [edi + ebx * 4]
+ EmitString("89 54 9F FC"); // mov dword ptr -4[edi + ebx * 4],edx
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
break;
case OP_MULI:
- EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
- EmitString( "F7 2F" ); // imul dword ptr [edi]
- EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ EmitString("8B 44 9F FC"); // mov eax,dword ptr -4[edi + ebx * 4]
+ EmitString("F7 2C 9F"); // imul dword ptr [edi + ebx * 4]
+ EmitString("89 44 9F FC"); // mov dword ptr -4[edi + ebx * 4],eax
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
break;
case OP_MULU:
- EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
- EmitString( "F7 27" ); // mul dword ptr [edi]
- EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ EmitString("8B 44 9F FC"); // mov eax,dword ptr -4[edi + ebx * 4]
+ EmitString("F7 24 9F"); // mul dword ptr [edi + ebx * 4]
+ EmitString("89 44 9F FC"); // mov dword ptr -4[edi + ebx * 4],eax
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
break;
case OP_BAND:
- EmitMovEAXEDI(vm); // mov eax, dword ptr [edi]
- EmitString( "21 47 FC" ); // and dword ptr [edi-4],eax
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ EmitMovEAXStack(vm, 0); // mov eax, dword ptr [edi + ebx * 4]
+ EmitString("21 44 9F FC"); // and dword ptr -4[edi + ebx * 4],eax
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
break;
case OP_BOR:
- EmitMovEAXEDI(vm); // mov eax, dword ptr [edi]
- EmitString( "09 47 FC" ); // or dword ptr [edi-4],eax
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ EmitMovEAXStack(vm, 0); // mov eax, dword ptr [edi + ebx * 4]
+ EmitString("09 44 9F FC"); // or dword ptr -4[edi + ebx * 4],eax
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
break;
case OP_BXOR:
- EmitMovEAXEDI(vm); // mov eax, dword ptr [edi]
- EmitString( "31 47 FC" ); // xor dword ptr [edi-4],eax
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ EmitMovEAXStack(vm, 0); // mov eax, dword ptr [edi + ebx * 4]
+ EmitString("31 44 9F FC"); // xor dword ptr -4[edi + ebx * 4],eax
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
break;
case OP_BCOM:
- EmitString( "F7 17" ); // not dword ptr [edi]
+ EmitString("F7 14 9F"); // not dword ptr [edi + ebx * 4]
break;
case OP_LSH:
- //EmitString( "8B 0F" ); // mov ecx, dword ptr [edi]
- EmitMovECXEDI( vm );
- EmitString( "D3 67 FC" ); // shl dword ptr [edi-4], cl
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ EmitMovECXStack(vm);
+ EmitString("D3 64 9F FC"); // shl dword ptr -4[edi + ebx * 4], cl
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
break;
case OP_RSHI:
- //EmitString( "8B 0F" ); // mov ecx, dword ptr [edi]
- EmitMovECXEDI( vm );
- EmitString( "D3 7F FC" ); // sar dword ptr [edi-4], cl
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ EmitMovECXStack(vm);
+ EmitString("D3 7C 9F FC"); // sar dword ptr -4[edi + ebx * 4], cl
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
break;
case OP_RSHU:
- //EmitString( "8B 0F" ); // mov ecx, dword ptr [edi]
- EmitMovECXEDI( vm );
- EmitString( "D3 6F FC" ); // shr dword ptr [edi-4], cl
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ EmitMovECXStack(vm);
+ EmitString("D3 6C 9F FC"); // shr dword ptr -4[edi + ebx * 4], cl
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
break;
case OP_NEGF:
- EmitString( "D9 07" ); // fld dword ptr [edi]
- EmitString( "D9 E0" ); // fchs
- EmitString( "D9 1F" ); // fstp dword ptr [edi]
+ EmitString("D9 04 9F"); // fld dword ptr [edi + ebx * 4]
+ EmitString("D9 E0"); // fchs
+ EmitString("D9 1C 9F"); // fstp dword ptr [edi + ebx * 4]
break;
case OP_ADDF:
- EmitString( "D9 47 FC" ); // fld dword ptr [edi-4]
- EmitString( "D8 07" ); // fadd dword ptr [edi]
- EmitString( "D9 5F FC" ); // fstp dword ptr [edi-4]
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ EmitString("D9 44 9F FC"); // fld dword ptr -4[edi + ebx * 4]
+ EmitString("D8 04 9F"); // fadd dword ptr [edi + ebx * 4]
+ EmitString("D9 5C 9F FC"); // fstp dword ptr -4[edi + ebx * 4]
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
break;
case OP_SUBF:
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- EmitString( "D9 07" ); // fld dword ptr [edi]
- EmitString( "D8 67 04" ); // fsub dword ptr [edi+4]
- EmitString( "D9 1F" ); // fstp dword ptr [edi]
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ EmitString("D9 04 9F"); // fld dword ptr [edi + ebx * 4]
+ EmitString("D8 64 9F 04"); // fsub dword ptr 4[edi + ebx * 4]
+ EmitString("D9 1C 9F"); // fstp dword ptr [edi + ebx * 4]
break;
case OP_DIVF:
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- EmitString( "D9 07" ); // fld dword ptr [edi]
- EmitString( "D8 77 04" ); // fdiv dword ptr [edi+4]
- EmitString( "D9 1F" ); // fstp dword ptr [edi]
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ EmitString("D9 04 9F"); // fld dword ptr [edi + ebx * 4]
+ EmitString("D8 74 9F 04"); // fdiv dword ptr 4[edi + ebx * 4]
+ EmitString("D9 1C 9F"); // fstp dword ptr [edi + ebx * 4]
break;
case OP_MULF:
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- EmitString( "D9 07" ); // fld dword ptr [edi]
- EmitString( "D8 4f 04" ); // fmul dword ptr [edi+4]
- EmitString( "D9 1F" ); // fstp dword ptr [edi]
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ EmitString("D9 04 9F"); // fld dword ptr [edi + ebx * 4]
+ EmitString("D8 4C 9F 04"); // fmul dword ptr 4[edi + ebx * 4]
+ EmitString("D9 1C 9F"); // fstp dword ptr [edi + ebx * 4]
break;
case OP_CVIF:
- EmitString( "DB 07" ); // fild dword ptr [edi]
- EmitString( "D9 1F" ); // fstp dword ptr [edi]
+ EmitString("DB 04 9F"); // fild dword ptr [edi + ebx * 4]
+ EmitString("D9 1C 9F"); // fstp dword ptr [edi + ebx * 4]
break;
case OP_CVFI:
#ifndef FTOL_PTR // WHENHELLISFROZENOVER
// not IEEE complient, but simple and fast
- EmitString( "D9 07" ); // fld dword ptr [edi]
- EmitString( "DB 1F" ); // fistp dword ptr [edi]
+ EmitString("D9 04 9F"); // fld dword ptr [edi + ebx * 4]
+ EmitString("DB 1C 9F"); // fistp dword ptr [edi + ebx * 4]
#else // FTOL_PTR
// call the library conversion function
- EmitString( "D9 07" ); // fld dword ptr [edi]
- EmitString( "FF 15" ); // call ftolPtr
- Emit4( (int)&ftolPtr );
- EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
+ EmitRexString(0x48, "BA"); // mov edx, Q_VMftol
+ EmitPtr(Q_VMftol);
+ EmitRexString(0x48, "FF D2"); // call edx
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax
#endif
break;
case OP_SEX8:
- EmitString( "0F BE 07" ); // movsx eax, byte ptr [edi]
- EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
+ EmitString("0F BE 04 9F"); // movsx eax, byte ptr [edi + ebx * 4]
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax
break;
case OP_SEX16:
- EmitString( "0F BF 07" ); // movsx eax, word ptr [edi]
- EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
+ EmitString("0F BF 04 9F"); // movsx eax, word ptr [edi + ebx * 4]
+ EmitCommand(LAST_COMMAND_MOV_STACK_EAX); // mov dword ptr [edi + ebx * 4], eax
break;
case OP_BLOCK_COPY:
- // FIXME: range check
- EmitString( "56" ); // push esi
- EmitString( "57" ); // push edi
- EmitString( "8B 37" ); // mov esi,[edi]
- EmitString( "8B 7F FC" ); // mov edi,[edi-4]
- EmitString( "B9" ); // mov ecx,0x12345678
- Emit4( Constant4() >> 2 );
- EmitString( "B8" ); // mov eax, datamask
- Emit4( vm->dataMask );
- EmitString( "BB" ); // mov ebx, database
- Emit4( (int)vm->dataBase );
- EmitString( "23 F0" ); // and esi, eax
- EmitString( "03 F3" ); // add esi, ebx
- EmitString( "23 F8" ); // and edi, eax
- EmitString( "03 FB" ); // add edi, ebx
- EmitString( "F3 A5" ); // rep movsd
- EmitString( "5F" ); // pop edi
- EmitString( "5E" ); // pop esi
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ EmitString("B8"); // mov eax, 0x12345678
+ Emit4(VM_BLOCK_COPY);
+ EmitString("B9"); // mov ecx, 0x12345678
+ Emit4(Constant4());
+
+ EmitCallRel(vm, callDoSyscallOfs);
+
+ EmitCommand(LAST_COMMAND_SUB_BL_2); // sub bl, 2
break;
case OP_JUMP:
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- EmitString( "8B 47 04" ); // mov eax,dword ptr [edi+4]
+ EmitCommand(LAST_COMMAND_SUB_BL_1); // sub bl, 1
+ EmitString("8B 44 9F 04"); // mov eax, dword ptr 4[edi + ebx * 4]
EmitString("81 F8"); // cmp eax, vm->instructionCount
Emit4(vm->instructionCount);
- EmitString( "73 07" ); // jae +7
- EmitString( "FF 24 85" ); // jmp dword ptr [instructionPointers + eax * 4]
+#if idx64
+ EmitString("73 04"); // jae +4
+ EmitRexString(0x49, "FF 24 C0"); // jmp qword ptr [r8 + eax * 8]
+#else
+ EmitString("73 07"); // jae +7
+ EmitString("FF 24 85"); // jmp dword ptr [instructionPointers + eax * 4]
Emit4((intptr_t) vm->instructionPointers);
- EmitString( "FF 15" ); // call errJumpPtr
- Emit4((intptr_t) &errJumpPtr);
+#endif
+ EmitCallErrJump(vm, callDoSyscallOfs);
break;
default:
VMFREE_BUFFERS();
@@ -1471,7 +1690,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *h
// offset all the instruction pointers for the new location
for ( i = 0 ; i < header->instructionCount ; i++ ) {
- vm->instructionPointers[i] += (int)vm->codeBase;
+ vm->instructionPointers[i] += (intptr_t) vm->codeBase;
}
}
@@ -1493,13 +1712,16 @@ VM_CallCompiled
This function is called directly by the generated code
==============
*/
-int VM_CallCompiled( vm_t *vm, int *args ) {
- int stack[1024];
+
+int VM_CallCompiled(vm_t *vm, int *args)
+{
+ byte stack[OPSTACK_SIZE * 4 + 15];
+ void *entryPoint;
int programCounter;
- int programStack;
- int stackOnEntry;
+ int programStack, stackOnEntry;
byte *image;
- void *opStack;
+ int *opStack;
+ int opStackOfs;
currentVM = vm;
@@ -1507,8 +1729,7 @@ int VM_CallCompiled( vm_t *vm, int *args
vm->currentlyInterpreting = qtrue;
// we might be called recursively, so this might not be the very top
- programStack = vm->programStack;
- stackOnEntry = programStack;
+ programStack = stackOnEntry = vm->programStack;
// set up the stack frame
image = vm->dataBase;
@@ -1531,47 +1752,67 @@ int VM_CallCompiled( vm_t *vm, int *args
*(int *)&image[ programStack ] = -1; // will terminate the loop on return
// off we go into generated code...
- opStack = &stack;
+ entryPoint = vm->codeBase + vm->entryOfs;
+ opStack = PADP(stack, 16);
+ *opStack = 0xDEADBEEF;
+ opStackOfs = 0;
- {
#ifdef _MSC_VER
- void *entryPoint = vm->codeBase + vm->entryOfs;
+ #if idx64
+ opStackOfs = qvmcall64(&programStack, opStack, vm->instructionPointers, vm->dataBase);
+ #else
+ __asm
+ {
+ pushad
- __asm {
- pushad
- mov esi, programStack
- mov edi, opStack
- call entryPoint
- mov programStack, esi
- mov opStack, edi
- popad
- }
-#else
- /* These registers are used as scratch registers and are destroyed after the
- * call. Do not use clobber, so they can be used as input for the asm. */
- unsigned eax;
- unsigned ebx;
- unsigned ecx;
- unsigned edx;
-
- __asm__ volatile(
- "call *%6"
- : "+S" (programStack), "+D" (opStack),
- "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
- : "mr" (vm->codeBase + vm->entryOfs)
- : "cc", "memory"
- );
-#endif
- }
+ mov esi, dword ptr programStack
+ mov edi, dword ptr opStack
+ mov ebx, dword ptr opStackOfs
+
+ call entryPoint
- if ( opStack != &stack[1] ) {
- Com_Error( ERR_DROP, "opStack corrupted in compiled code" );
+ mov dword ptr opStackOfs, ebx
+ mov dword ptr opStack, edi
+ mov dword ptr programStack, esi
+
+ popad
}
- if ( programStack != stackOnEntry - 48 ) {
- Com_Error( ERR_DROP, "programStack corrupted in compiled code" );
+ #endif
+#elif idx64
+ __asm__ volatile(
+ "movq %5, %%rax\r\n"
+ "movq %3, %%r8\r\n"
+ "movq %4, %%r9\r\n"
+ "push %%r15\r\n"
+ "push %%r14\r\n"
+ "push %%r13\r\n"
+ "push %%r12\r\n"
+ "callq *%%rax\r\n"
+ "pop %%r12\r\n"
+ "pop %%r13\r\n"
+ "pop %%r14\r\n"
+ "pop %%r15\r\n"
+ : "+S" (programStack), "+D" (opStack), "+b" (opStackOfs)
+ : "g" (vm->instructionPointers), "g" (vm->dataBase), "g" (entryPoint)
+ : "cc", "memory", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11"
+ );
+#else
+ __asm__ volatile(
+ "calll *%3\r\n"
+ : "+S" (programStack), "+D" (opStack), "+b" (opStackOfs)
+ : "g" (entryPoint)
+ : "cc", "memory", "%eax", "%ecx", "%edx"
+ );
+#endif
+
+ if(opStackOfs != 1 || *opStack != 0xDEADBEEF)
+ {
+ Com_Error(ERR_DROP, "opStack corrupted in compiled code");
}
+ if(programStack != stackOnEntry - 48)
+ Com_Error(ERR_DROP, "programStack corrupted in compiled code");
vm->programStack = stackOnEntry;
- return *(int *)opStack;
+ return opStack[opStackOfs];
}
Index: code/qcommon/vm_x86_64.c
===================================================================
--- code/qcommon/vm_x86_64.c.orig
+++ code/qcommon/vm_x86_64.c
@@ -77,7 +77,7 @@ static void VM_Destroy_Compiled(vm_t* se
rsi scratch
rdi program frame pointer (programStack)
r8 pointer data (vm->dataBase)
- r9 opStack data base (opStack)
+ r9 opStack base (opStack)
r10 start of generated code
*/
@@ -257,10 +257,10 @@ void emit(const char* fmt, ...)
#endif
#define STACK_PUSH(bytes) \
- emit("addb $0x%x, %%bl", bytes); \
+ emit("addb $0x%x, %%bl", bytes >> 2); \
#define STACK_POP(bytes) \
- emit("subb $0x%x, %%bl", bytes); \
+ emit("subb $0x%x, %%bl", bytes >> 2); \
#define CHECK_INSTR_REG(reg) \
emit("cmpl $%u, %%"#reg, header->instructionCount); \
@@ -272,7 +272,7 @@ void emit(const char* fmt, ...)
#define PREPARE_JMP(reg) \
CHECK_INSTR_REG(reg); \
emit("movq $%"PRIu64", %%rsi", (intptr_t)vm->instructionPointers); \
- emit("movl (%%rsi, %%rax, 4), %%eax"); \
+ emit("movl (%%rsi, %%rax, 8), %%eax"); \
emit("addq %%r10, %%rax")
#define CHECK_INSTR(nr) \
@@ -295,7 +295,7 @@ void emit(const char* fmt, ...)
got_const = 0; \
vm->instructionPointers[instruction-1] = assembler_get_code_size(); \
STACK_PUSH(4); \
- emit("movl $%d, (%%r9, %%rbx, 1)", const_value); \
+ emit("movl $%d, (%%r9, %%rbx, 4)", const_value); \
}
#else
#define MAYBE_EMIT_CONST()
@@ -305,8 +305,8 @@ void emit(const char* fmt, ...)
#define IJ(op) \
MAYBE_EMIT_CONST(); \
STACK_POP(8); \
- emit("movl 4(%%r9, %%rbx, 1), %%eax"); \
- emit("cmpl 8(%%r9, %%rbx, 1), %%eax"); \
+ emit("movl 4(%%r9, %%rbx, 4), %%eax"); \
+ emit("cmpl 8(%%r9, %%rbx, 4), %%eax"); \
emit(op " i_%08x", instruction+1); \
JMPIARG(); \
neednilabel = 1
@@ -315,8 +315,8 @@ void emit(const char* fmt, ...)
#define FJ(bits, op) \
MAYBE_EMIT_CONST(); \
STACK_POP(8); \
- emit("flds 4(%%r9, %%rbx, 1)");\
- emit("fcomps 8(%%r9, %%rbx, 1)");\
+ emit("flds 4(%%r9, %%rbx, 4)");\
+ emit("fcomps 8(%%r9, %%rbx, 4)");\
emit("fnstsw %%ax");\
emit("testb $" #bits ", %%ah");\
emit(op " i_%08x", instruction+1);\
@@ -328,8 +328,8 @@ void emit(const char* fmt, ...)
#define XJ(op) \
MAYBE_EMIT_CONST(); \
STACK_POP(8); \
- emit("movss 4(%%r9, %%rbx, 1), %%xmm0");\
- emit("ucomiss 8(%%r9, %%rbx, 1), %%xmm0");\
+ emit("movss 4(%%r9, %%rbx, 4), %%xmm0");\
+ emit("ucomiss 8(%%r9, %%rbx, 4), %%xmm0");\
emit("jp i_%08x", instruction+1);\
emit(op " i_%08x", instruction+1);\
JMPIARG(); \
@@ -338,35 +338,35 @@ void emit(const char* fmt, ...)
#define SIMPLE(op) \
MAYBE_EMIT_CONST(); \
- emit("movl (%%r9, %%rbx, 1), %%eax"); \
+ emit("movl (%%r9, %%rbx, 4), %%eax"); \
STACK_POP(4); \
- emit(op " %%eax, (%%r9, %%rbx, 1)")
+ emit(op " %%eax, (%%r9, %%rbx, 4)")
#ifdef USE_X87
#define FSIMPLE(op) \
MAYBE_EMIT_CONST(); \
STACK_POP(4); \
- emit("flds (%%r9, %%rbx, 1)"); \
- emit(op " 4(%%r9, %%rbx, 1)"); \
- emit("fstps (%%r9, %%rbx, 1)")
+ emit("flds (%%r9, %%rbx, 4)"); \
+ emit(op " 4(%%r9, %%rbx, 4)"); \
+ emit("fstps (%%r9, %%rbx, 4)")
#define XSIMPLE(op)
#else
#define FSIMPLE(op)
#define XSIMPLE(op) \
MAYBE_EMIT_CONST(); \
STACK_POP(4); \
- emit("movss (%%r9, %%rbx, 1), %%xmm0"); \
- emit(op " 4(%%r9, %%rbx, 1), %%xmm0"); \
- emit("movss %%xmm0, (%%r9, %%rbx, 1)")
+ emit("movss (%%r9, %%rbx, 4), %%xmm0"); \
+ emit(op " 4(%%r9, %%rbx, 4), %%xmm0"); \
+ emit("movss %%xmm0, (%%r9, %%rbx, 4)")
#endif
#define SHIFT(op) \
MAYBE_EMIT_CONST(); \
STACK_POP(4); \
- emit("movl 4(%%r9, %%rbx, 1), %%ecx"); \
- emit("movl (%%r9, %%rbx, 1), %%eax"); \
+ emit("movl 4(%%r9, %%rbx, 4), %%ecx"); \
+ emit("movl (%%r9, %%rbx, 4), %%eax"); \
emit(op " %%cl, %%eax"); \
- emit("movl %%eax, (%%r9, %%rbx, 1)")
+ emit("movl %%eax, (%%r9, %%rbx, 4)")
#ifdef DEBUG_VM
#define NOTIMPL(x) \
@@ -381,21 +381,6 @@ static void* getentrypoint(vm_t* vm)
return vm->codeBase;
}
-static void CROSSCALL block_copy_vm(unsigned dest, unsigned src, unsigned count)
-{
- unsigned dataMask = currentVM->dataMask;
-
- if ((dest & dataMask) != dest
- || (src & dataMask) != src
- || ((dest+count) & dataMask) != dest + count
- || ((src+count) & dataMask) != src + count)
- {
- Com_Error(ERR_DROP, "OP_BLOCK_COPY out of range!");
- }
-
- memcpy(currentVM->dataBase+dest, currentVM->dataBase+src, count);
-}
-
static void CROSSCALL eop(void)
{
Com_Error(ERR_DROP, "End of program reached without return!");
@@ -564,7 +549,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *h
else
{
MAYBE_EMIT_CONST();
- emit("movl (%%r9, %%rbx, 1), %%eax"); // get instr from stack
+ emit("movl (%%r9, %%rbx, 4), %%eax"); // get instr from stack
STACK_POP(4);
emit("orl %%eax, %%eax");
@@ -605,7 +590,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *h
emit("pop %%rdi");
// emit("frstor 4(%%r9, %%rsi, 1)");
STACK_PUSH(4);
- emit("movl %%eax, (%%r9, %%rbx, 1)"); // store return value
+ emit("movl %%eax, (%%r9, %%rbx, 4)"); // store return value
neednilabel = 1;
break;
case OP_PUSH:
@@ -623,7 +608,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *h
const_value = iarg;
#else
STACK_PUSH(4);
- emit("movl $%d, (%%r9, %%rbx, 1)", iarg);
+ emit("movl $%d, (%%r9, %%rbx, 4)", iarg);
#endif
break;
case OP_LOCAL:
@@ -631,7 +616,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *h
emit("movl %%edi, %%esi");
emit("addl $%d,%%esi", iarg);
STACK_PUSH(4);
- emit("movl %%esi, (%%r9, %%rbx, 1)");
+ emit("movl %%esi, (%%r9, %%rbx, 4)");
break;
case OP_JUMP:
if(got_const) {
@@ -639,7 +624,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *h
got_const = 0;
JMPIARG();
} else {
- emit("movl (%%r9, %%rbx, 1), %%eax"); // get instr from stack
+ emit("movl (%%r9, %%rbx, 4), %%eax"); // get instr from stack
STACK_POP(4);
PREPARE_JMP(eax);
@@ -685,8 +670,8 @@ void VM_Compile( vm_t *vm, vmHeader_t *h
#ifndef USE_X87
MAYBE_EMIT_CONST();
STACK_POP(8);
- emit("movss 4(%%r9, %%rbx, 1), %%xmm0");
- emit("ucomiss 8(%%r9, %%rbx, 1), %%xmm0");
+ emit("movss 4(%%r9, %%rbx, 4), %%xmm0");
+ emit("ucomiss 8(%%r9, %%rbx, 4), %%xmm0");
emit("jp dojump_i_%08x", instruction);
emit("jz i_%08x", instruction+1);
emit("dojump_i_%08x:", instruction);
@@ -712,54 +697,54 @@ void VM_Compile( vm_t *vm, vmHeader_t *h
break;
case OP_LOAD1:
MAYBE_EMIT_CONST();
- emit("movl (%%r9, %%rbx, 1), %%eax"); // get value from stack
+ emit("movl (%%r9, %%rbx, 4), %%eax"); // get value from stack
RANGECHECK(eax, 1);
emit("movb (%%r8, %%rax, 1), %%al"); // deref into eax
emit("andq $255, %%rax");
- emit("movl %%eax, (%%r9, %%rbx, 1)"); // store on stack
+ emit("movl %%eax, (%%r9, %%rbx, 4)"); // store on stack
break;
case OP_LOAD2:
MAYBE_EMIT_CONST();
- emit("movl (%%r9, %%rbx, 1), %%eax"); // get value from stack
+ emit("movl (%%r9, %%rbx, 4), %%eax"); // get value from stack
RANGECHECK(eax, 2);
emit("movw (%%r8, %%rax, 1), %%ax"); // deref into eax
- emit("movl %%eax, (%%r9, %%rbx, 1)"); // store on stack
+ emit("movl %%eax, (%%r9, %%rbx, 4)"); // store on stack
break;
case OP_LOAD4:
MAYBE_EMIT_CONST();
- emit("movl (%%r9, %%rbx, 1), %%eax"); // get value from stack
+ emit("movl (%%r9, %%rbx, 4), %%eax"); // get value from stack
RANGECHECK(eax, 4); // not a pointer!?
emit("movl (%%r8, %%rax, 1), %%eax"); // deref into eax
- emit("movl %%eax, (%%r9, %%rbx, 1)"); // store on stack
+ emit("movl %%eax, (%%r9, %%rbx, 4)"); // store on stack
break;
case OP_STORE1:
MAYBE_EMIT_CONST();
- emit("movl (%%r9, %%rbx, 1), %%eax"); // get value from stack
+ emit("movl (%%r9, %%rbx, 4), %%eax"); // get value from stack
STACK_POP(8);
emit("andq $255, %%rax");
- emit("movl 4(%%r9, %%rbx, 1), %%esi"); // get pointer from stack
+ emit("movl 4(%%r9, %%rbx, 4), %%esi"); // get pointer from stack
RANGECHECK(esi, 1);
emit("movb %%al, (%%r8, %%rsi, 1)"); // store in memory
break;
case OP_STORE2:
MAYBE_EMIT_CONST();
- emit("movl (%%r9, %%rbx, 1), %%eax"); // get value from stack
+ emit("movl (%%r9, %%rbx, 4), %%eax"); // get value from stack
STACK_POP(8);
- emit("movl 4(%%r9, %%rbx, 1), %%esi"); // get pointer from stack
+ emit("movl 4(%%r9, %%rbx, 4), %%esi"); // get pointer from stack
RANGECHECK(esi, 2);
emit("movw %%ax, (%%r8, %%rsi, 1)"); // store in memory
break;
case OP_STORE4:
MAYBE_EMIT_CONST();
- emit("movl (%%r9, %%rbx, 1), %%eax"); // get value from stack
+ emit("movl (%%r9, %%rbx, 4), %%eax"); // get value from stack
STACK_POP(8);
- emit("movl 4(%%r9, %%rbx, 1), %%esi"); // get pointer from stack
+ emit("movl 4(%%r9, %%rbx, 4), %%esi"); // get pointer from stack
RANGECHECK(esi, 4);
emit("movl %%eax, (%%r8, %%rsi, 1)"); // store in memory
break;
case OP_ARG:
MAYBE_EMIT_CONST();
- emit("movl (%%r9, %%rbx, 1), %%eax"); // get value from stack
+ emit("movl (%%r9, %%rbx, 4), %%eax"); // get value from stack
STACK_POP(4);
emit("movl $0x%hx, %%esi", barg);
emit("addl %%edi, %%esi");
@@ -779,10 +764,10 @@ void VM_Compile( vm_t *vm, vmHeader_t *h
emit("andq $127, %%rsi"); // |
emit("subq %%rsi, %%rsp"); // <-+
emit("push %%rsi");
- emit("movl 4(%%r9, %%rbx, 1), %%edi"); // 1st argument dest
- emit("movl 8(%%r9, %%rbx, 1), %%rsi"); // 2nd argument src
+ emit("movl 4(%%r9, %%rbx, 4), %%edi"); // 1st argument dest
+ emit("movl 8(%%r9, %%rbx, 4), %%rsi"); // 2nd argument src
emit("movl $%d, %%edx", iarg); // 3rd argument count
- emit("movq $%"PRIu64", %%rax", (intptr_t) block_copy_vm);
+ emit("movq $%"PRIu64", %%rax", (intptr_t) VM_BlockCopy);
emit("callq *%%rax");
emit("pop %%rsi");
emit("addq %%rsi, %%rsp");
@@ -794,21 +779,21 @@ void VM_Compile( vm_t *vm, vmHeader_t *h
break;
case OP_SEX8:
MAYBE_EMIT_CONST();
- emit("movw (%%r9, %%rbx, 1), %%ax");
+ emit("movw (%%r9, %%rbx, 4), %%ax");
emit("andq $255, %%rax");
emit("cbw");
emit("cwde");
- emit("movl %%eax, (%%r9, %%rbx, 1)");
+ emit("movl %%eax, (%%r9, %%rbx, 4)");
break;
case OP_SEX16:
MAYBE_EMIT_CONST();
- emit("movw (%%r9, %%rbx, 1), %%ax");
+ emit("movw (%%r9, %%rbx, 4), %%ax");
emit("cwde");
- emit("movl %%eax, (%%r9, %%rbx, 1)");
+ emit("movl %%eax, (%%r9, %%rbx, 4)");
break;
case OP_NEGI:
MAYBE_EMIT_CONST();
- emit("negl (%%r9, %%rbx, 1)");
+ emit("negl (%%r9, %%rbx, 4)");
break;
case OP_ADD:
SIMPLE("addl");
@@ -819,49 +804,49 @@ void VM_Compile( vm_t *vm, vmHeader_t *h
case OP_DIVI:
MAYBE_EMIT_CONST();
STACK_POP(4);
- emit("movl (%%r9, %%rbx, 1), %%eax");
+ emit("movl (%%r9, %%rbx, 4), %%eax");
emit("cdq");
- emit("idivl 4(%%r9, %%rbx, 1)");
- emit("movl %%eax, (%%r9, %%rbx, 1)");
+ emit("idivl 4(%%r9, %%rbx, 4)");
+ emit("movl %%eax, (%%r9, %%rbx, 4)");
break;
case OP_DIVU:
MAYBE_EMIT_CONST();
STACK_POP(4);
- emit("movl (%%r9, %%rbx, 1), %%eax");
+ emit("movl (%%r9, %%rbx, 4), %%eax");
emit("xorq %%rdx, %%rdx");
- emit("divl 4(%%r9, %%rbx, 1)");
- emit("movl %%eax, (%%r9, %%rbx, 1)");
+ emit("divl 4(%%r9, %%rbx, 4)");
+ emit("movl %%eax, (%%r9, %%rbx, 4)");
break;
case OP_MODI:
MAYBE_EMIT_CONST();
STACK_POP(4);
- emit("movl (%%r9, %%rbx, 1), %%eax");
+ emit("movl (%%r9, %%rbx, 4), %%eax");
emit("xorl %%edx, %%edx");
emit("cdq");
- emit("idivl 4(%%r9, %%rbx, 1)");
- emit("movl %%edx, (%%r9, %%rbx, 1)");
+ emit("idivl 4(%%r9, %%rbx, 4)");
+ emit("movl %%edx, (%%r9, %%rbx, 4)");
break;
case OP_MODU:
MAYBE_EMIT_CONST();
STACK_POP(4);
- emit("movl (%%r9, %%rbx, 1), %%eax");
+ emit("movl (%%r9, %%rbx, 4), %%eax");
emit("xorl %%edx, %%edx");
- emit("divl 4(%%r9, %%rbx, 1)");
- emit("movl %%edx, (%%r9, %%rbx, 1)");
+ emit("divl 4(%%r9, %%rbx, 4)");
+ emit("movl %%edx, (%%r9, %%rbx, 4)");
break;
case OP_MULI:
MAYBE_EMIT_CONST();
STACK_POP(4);
- emit("movl (%%r9, %%rbx, 1), %%eax");
- emit("imull 4(%%r9, %%rbx, 1)");
- emit("movl %%eax, (%%r9, %%rbx, 1)");
+ emit("movl (%%r9, %%rbx, 4), %%eax");
+ emit("imull 4(%%r9, %%rbx, 4)");
+ emit("movl %%eax, (%%r9, %%rbx, 4)");
break;
case OP_MULU:
MAYBE_EMIT_CONST();
STACK_POP(4);
- emit("movl (%%r9, %%rbx, 1), %%eax");
- emit("mull 4(%%r9, %%rbx, 1)");
- emit("movl %%eax, (%%r9, %%rbx, 1)");
+ emit("movl (%%r9, %%rbx, 4), %%eax");
+ emit("mull 4(%%r9, %%rbx, 4)");
+ emit("movl %%eax, (%%r9, %%rbx, 4)");
break;
case OP_BAND:
SIMPLE("andl");
@@ -874,7 +859,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *h
break;
case OP_BCOM:
MAYBE_EMIT_CONST();
- emit("notl (%%r9, %%rbx, 1)");
+ emit("notl (%%r9, %%rbx, 4)");
break;
case OP_LSH:
SHIFT("shl");
@@ -888,12 +873,12 @@ void VM_Compile( vm_t *vm, vmHeader_t *h
case OP_NEGF:
MAYBE_EMIT_CONST();
#ifdef USE_X87
- emit("flds (%%r9, %%rbx, 1)");
+ emit("flds (%%r9, %%rbx, 4)");
emit("fchs");
- emit("fstps (%%r9, %%rbx, 1)");
+ emit("fstps (%%r9, %%rbx, 4)");
#else
emit("movl $0x80000000, %%eax");
- emit("xorl %%eax, (%%r9, %%rbx, 1)");
+ emit("xorl %%eax, (%%r9, %%rbx, 4)");
#endif
break;
case OP_ADDF:
@@ -915,27 +900,27 @@ void VM_Compile( vm_t *vm, vmHeader_t *h
case OP_CVIF:
MAYBE_EMIT_CONST();
#ifdef USE_X87
- emit("filds (%%r9, %%rbx, 1)");
- emit("fstps (%%r9, %%rbx, 1)");
+ emit("filds (%%r9, %%rbx, 4)");
+ emit("fstps (%%r9, %%rbx, 4)");
#else
- emit("movl (%%r9, %%rbx, 1), %%eax");
+ emit("movl (%%r9, %%rbx, 4), %%eax");
emit("cvtsi2ss %%eax, %%xmm0");
- emit("movss %%xmm0, (%%r9, %%rbx, 1)");
+ emit("movss %%xmm0, (%%r9, %%rbx, 4)");
#endif
break;
case OP_CVFI:
MAYBE_EMIT_CONST();
#ifdef USE_X87
- emit("flds (%%r9, %%rbx, 1)");
- emit("fnstcw 4(%%r9, %%rbx, 1)");
- emit("movw $0x0F7F, 8(%%r9, %%rbx, 1)"); // round toward zero
- emit("fldcw 8(%%r9, %%rbx, 1)");
- emit("fistpl (%%r9, %%rbx, 1)");
- emit("fldcw 4(%%r9, %%rbx, 1)");
+ emit("flds (%%r9, %%rbx, 4)");
+ emit("fnstcw 4(%%r9, %%rbx, 4)");
+ emit("movw $0x0F7F, 8(%%r9, %%rbx, 4)"); // round toward zero
+ emit("fldcw 8(%%r9, %%rbx, 4)");
+ emit("fistpl (%%r9, %%rbx, 4)");
+ emit("fldcw 4(%%r9, %%rbx, 4)");
#else
- emit("movss (%%r9, %%rbx, 1), %%xmm0");
+ emit("movss (%%r9, %%rbx, 4), %%xmm0");
emit("cvttss2si %%xmm0, %%eax");
- emit("movl %%eax, (%%r9, %%rbx, 1)");
+ emit("movl %%eax, (%%r9, %%rbx, 4)");
#endif
break;
default:
@@ -1029,7 +1014,9 @@ This function is called directly by the
static char* memData;
#endif
-int VM_CallCompiled( vm_t *vm, int *args ) {
+int VM_CallCompiled(vm_t *vm, int *args)
+{
+ int stack[OPSTACK_SIZE + 3];
int programCounter;
int programStack;
int stackOnEntry;
@@ -1037,7 +1024,6 @@ int VM_CallCompiled( vm_t *vm, int *args
byte *image;
void *entryPoint;
int *opStack;
- int stack[OPSTACK_SIZE + 3] = { 0xDEADBEEF };
currentVM = vm;
@@ -1079,22 +1065,30 @@ int VM_CallCompiled( vm_t *vm, int *args
entryPoint = getentrypoint(vm);
opStack = PADP(stack, 4);
+ *opStack = 0xDEADBEEF;
+ opStackRet = 0;
+
__asm__ __volatile__ (
- " movq $0x0,%%rbx \r\n" \
- " movl %5,%%edi \r\n" \
" movq %4,%%r8 \r\n" \
" movq %3,%%r9 \r\n" \
" movq %2,%%r10 \r\n" \
+ " push %%r15 \r\n" \
+ " push %%r14 \r\n" \
+ " push %%r13 \r\n" \
+ " push %%r12 \r\n" \
" subq $24, %%rsp # fix alignment as call pushes one value \r\n" \
" callq *%%r10 \r\n" \
" addq $24, %%rsp \r\n" \
- " movl %%edi, %0 \r\n" \
- " movq %%rbx, %1 \r\n" \
- : "=g" (programStack), "=g" (opStackRet)
+ " pop %%r12 \r\n" \
+ " pop %%r13 \r\n" \
+ " pop %%r14 \r\n" \
+ " pop %%r15 \r\n"
+ : "+D" (programStack), "+b" (opStackRet)
: "g" (entryPoint), "g" (opStack), "g" (vm->dataBase), "g" (programStack)
- : "%rsi", "%rdi", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r15", "%xmm0"
+ : "%rsi", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%xmm0"
);
- if(opStackRet != 4 || *opStack != 0xDEADBEEF)
+
+ if(opStackRet != 1 || *opStack != 0xDEADBEEF)
Com_Error(ERR_DROP, "opStack corrupted in compiled code (offset %ld)", opStackRet);
if ( programStack != stackOnEntry - 48 ) {
Index: code/sys/sys_unix.c
===================================================================
--- code/sys/sys_unix.c.orig
+++ code/sys/sys_unix.c
@@ -36,6 +36,7 @@ Foundation, Inc., 51 Franklin St, Fifth
#include <pwd.h>
#include <libgen.h>
#include <fcntl.h>
+#include <fenv.h>
qboolean stdinIsATTY;
@@ -245,31 +246,6 @@ int Sys_Milliseconds (void)
return curtime;
}
-#if !id386
-/*
-==================
-fastftol
-==================
-*/
-long fastftol( float f )
-{
- return (long)f;
-}
-
-/*
-==================
-Sys_SnapVector
-==================
-*/
-void Sys_SnapVector( float *v )
-{
- v[0] = rint(v[0]);
- v[1] = rint(v[1]);
- v[2] = rint(v[2]);
-}
-#endif
-
-
/*
==================
Sys_RandomBytes
@@ -878,6 +854,12 @@ void Sys_GLimpInit( void )
// NOP
}
+void Sys_SetFloatEnv(void)
+{
+ // rounding towards 0
+ fesetround(FE_TOWARDZERO);
+}
+
/*
==============
Sys_PlatformInit
Index: code/sys/sys_main.c
===================================================================
--- code/sys/sys_main.c.orig
+++ code/sys/sys_main.c
@@ -427,35 +427,23 @@ void Sys_UnloadDll( void *dllHandle )
Sys_LoadDll
Used to load a development dll instead of a virtual machine
-#1 look in fs_homepath
-#2 look in fs_basepath
=================
*/
-void *Sys_LoadDll( const char *name,
- intptr_t (**entryPoint)(int, ...),
- intptr_t (*systemcalls)(intptr_t, ...) )
+void *Sys_LoadDll(const char *name,
+ intptr_t (QDECL **entryPoint)(int, ...),
+ intptr_t (*systemcalls)(intptr_t, ...))
{
- void *libHandle;
- void (*dllEntry)( intptr_t (*syscallptr)(intptr_t, ...) );
- char fname[MAX_OSPATH];
- char *netpath;
+ void *libHandle;
+ void (*dllEntry)(intptr_t (*syscallptr)(intptr_t, ...));
- assert( name );
+ assert(name);
- Com_sprintf(fname, sizeof(fname), "%s" ARCH_STRING DLL_EXT, name);
+ Com_Printf( "Loading DLL file: %s\n", name);
+ libHandle = Sys_LoadLibrary(name);
- netpath = FS_FindDll(fname);
-
- if(!netpath) {
- Com_Printf( "Sys_LoadDll(%s) could not find it\n", fname );
- return NULL;
- }
-
- Com_Printf( "Loading DLL file: %s\n", netpath);
- libHandle = Sys_LoadLibrary(netpath);
-
- if(!libHandle) {
- Com_Printf( "Sys_LoadDll(%s) failed:\n\"%s\"\n", netpath, Sys_LibraryError() );
+ if(!libHandle)
+ {
+ Com_Printf("Sys_LoadDll(%s) failed:\n\"%s\"\n", name, Sys_LibraryError());
return NULL;
}
Index: code/client/snd_wavelet.c
===================================================================
--- code/client/snd_wavelet.c.orig
+++ code/client/snd_wavelet.c
@@ -23,8 +23,6 @@ Foundation, Inc., 51 Franklin St, Fifth
#include "snd_local.h"
-long myftol( float f );
-
#define C0 0.4829629131445341
#define C1 0.8365163037378079
#define C2 0.2241438680420134
Index: code/client/cl_cgame.c
===================================================================
--- code/client/cl_cgame.c.orig
+++ code/client/cl_cgame.c
@@ -595,6 +595,7 @@ intptr_t CL_CgameSystemCalls( intptr_t *
return re.RegisterShaderNoMip( VMA(1) );
case CG_R_REGISTERFONT:
re.RegisterFont( VMA(1), args[2], VMA(3));
+ return 0;
case CG_R_CLEARSCENE:
re.ClearScene();
return 0;
@@ -706,7 +707,7 @@ intptr_t CL_CgameSystemCalls( intptr_t *
case CG_REAL_TIME:
return Com_RealTime( VMA(1) );
case CG_SNAPVECTOR:
- Sys_SnapVector( VMA(1) );
+ Q_SnapVector(VMA(1));
return 0;
case CG_CIN_PLAYCINEMATIC:
Index: code/asm/vm_x86_64.asm
===================================================================
--- /dev/null
+++ code/asm/vm_x86_64.asm
@@ -0,0 +1,76 @@
+; ===========================================================================
+; Copyright (C) 2011 Thilo Schulz <thilo@tjps.eu>
+;
+; This file is part of Quake III Arena source code.
+;
+; Quake III Arena source code is free software; you can redistribute it
+; and/or modify it under the terms of the GNU General Public License as
+; published by the Free Software Foundation; either version 2 of the License,
+; or (at your option) any later version.
+;
+; Quake III Arena source code is distributed in the hope that it will be
+; useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Quake III Arena source code; if not, write to the Free Software
+; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+; ===========================================================================
+
+; Call wrapper for vm_x86 when built with MSVC in 64 bit mode,
+; since MSVC does not support inline x64 assembler code anymore.
+;
+; assumes __fastcall calling convention
+
+DoSyscall PROTO
+
+.code
+
+; Call to static void DoSyscall(int syscallNum, int programStack, int *opStackBase, uint8_t opStackOfs, intptr_t arg)
+
+qsyscall64 PROC
+ sub rsp, 28h ; after this esp will be aligned to 16 byte boundary
+ mov qword ptr [rsp + 20h], rcx ; 5th parameter "arg" is passed on stack
+ mov r9b, bl ; opStackOfs
+ mov r8, rdi ; opStackBase
+ mov edx, esi ; programStack
+ mov ecx, eax ; syscallNum
+ mov rax, DoSyscall ; store call address of DoSyscall in rax
+ call rax
+ add rsp, 28h
+ ret
+qsyscall64 ENDP
+
+
+; Call to compiled code after setting up the register environment for the VM
+; prototype:
+; uint8_t qvmcall64(int *programStack, int *opStack, intptr_t *instructionPointers, byte *dataBase);
+
+qvmcall64 PROC
+ push rsi ; push non-volatile registers to stack
+ push rdi
+ push rbx
+ ; need to save pointer in rcx so we can write back the programData value to caller
+ push rcx
+
+ ; registers r8 and r9 have correct value already thanx to __fastcall
+ xor rbx, rbx ; opStackOfs starts out being 0
+ mov rdi, rdx ; opStack
+ mov esi, dword ptr [rcx] ; programStack
+
+ call qword ptr [r8] ; instructionPointers[0] is also the entry point
+
+ pop rcx
+
+ mov dword ptr [rcx], esi ; write back the programStack value
+ mov al, bl ; return opStack offset
+
+ pop rbx
+ pop rdi
+ pop rsi
+
+ ret
+qvmcall64 ENDP
+
+end
Index: code/qcommon/qcommon.h
===================================================================
--- code/qcommon/qcommon.h.orig
+++ code/qcommon/qcommon.h
@@ -628,7 +628,7 @@ qboolean FS_FileExists( const char *file
qboolean FS_CreatePath (char *OSPath);
-char *FS_FindDll( const char *filename );
+vmInterpret_t FS_FindVM(void **startSearch, char *found, int foundlen, const char *name, int enableDll);
char *FS_BuildOSPath( const char *base, const char *game, const char *qpath );
qboolean FS_CompareZipChecksum(const char *zipfile);
@@ -644,9 +644,9 @@ fileHandle_t FS_FCreateOpenPipeFile( con
// will properly create any needed paths and deal with seperater character issues
fileHandle_t FS_SV_FOpenFileWrite( const char *filename );
-int FS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp );
+long FS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp );
void FS_SV_Rename( const char *from, const char *to );
-int FS_FOpenFileRead( const char *qpath, fileHandle_t *file, qboolean uniqueFILE );
+long FS_FOpenFileRead( const char *qpath, fileHandle_t *file, qboolean uniqueFILE );
// if uniqueFILE is true, then a new FILE will be fopened even if the file
// is found in an already open pak file. If uniqueFILE is false, you must call
// FS_FCloseFile instead of fclose, otherwise the pak FILE would be improperly closed
@@ -665,7 +665,8 @@ int FS_Read( void *buffer, int len, fil
void FS_FCloseFile( fileHandle_t f );
// note: you can't just fclose from another DLL, due to MS libc issues
-int FS_ReadFile( const char *qpath, void **buffer );
+long FS_ReadFileDir(const char *qpath, void *searchPath, void **buffer);
+long FS_ReadFile(const char *qpath, void **buffer);
// returns the length of the file
// a null buffer will just return the file length without loading
// as a quick check for existance. -1 length == not present
@@ -682,7 +683,7 @@ void FS_FreeFile( void *buffer );
void FS_WriteFile( const char *qpath, const void *buffer, int size );
// writes a complete file, creating any subdirectories needed
-int FS_filelength( fileHandle_t f );
+long FS_filelength(fileHandle_t f);
// doesn't work for files that are opened from a pack file
int FS_FTell( fileHandle_t f );
@@ -740,6 +741,7 @@ void FS_FilenameCompletion( const char *
qboolean stripExt, void(*callback)(const char *s), qboolean allowNonPureFilesOnDisk );
const char *FS_GetCurrentGameDir(void);
+qboolean FS_Which(const char *filename, void *searchPath);
/*
==============================================================
Index: Makefile
===================================================================
--- Makefile.orig
+++ Makefile
@@ -172,6 +172,10 @@ ifndef BUILD_SDK_DIFF
SDK_DIFF=0
endif
+ifndef USE_OLD_VM64
+USE_OLD_VM64=0
+endif
+
#############################################################################
BD=$(BUILD_DIR)/debug-$(PLATFORM)-$(ARCH)
@@ -677,11 +681,10 @@ else # ifeq freebsd
ifeq ($(PLATFORM),openbsd)
- #default to i386, no tests done on anything else
- ARCH=i386
+ ARCH=$(shell uname -m)
BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
- -DUSE_ICON
+ -DUSE_ICON -DMAP_ANONYMOUS=MAP_ANON
CLIENT_CFLAGS = $(SDL_CFLAGS)
SERVER_CFLAGS =
@@ -769,7 +772,7 @@ else # ifeq netbsd
ifeq ($(PLATFORM),irix64)
- ARCH=mips #default to MIPS
+ ARCH=mips
CC = c99
MKDIR = mkdir -p
@@ -1664,15 +1667,30 @@ ifeq ($(ARCH),i386)
Q3OBJ += \
$(B)/client/snd_mixa.o \
$(B)/client/matha.o \
- $(B)/client/ftola.o \
- $(B)/client/snapvectora.o
+ $(B)/client/snapvector.o \
+ $(B)/client/ftola.o
endif
ifeq ($(ARCH),x86)
Q3OBJ += \
$(B)/client/snd_mixa.o \
$(B)/client/matha.o \
- $(B)/client/ftola.o \
- $(B)/client/snapvectora.o
+ $(B)/client/snapvector.o \
+ $(B)/client/ftola.o
+endif
+ifeq ($(ARCH),x86_64)
+ Q3OBJ += \
+ $(B)/client/snapvector.o \
+ $(B)/client/ftola.o
+endif
+ifeq ($(ARCH),amd64)
+ Q3OBJ += \
+ $(B)/client/snapvector.o \
+ $(B)/client/ftola.o
+endif
+ifeq ($(ARCH),x64)
+ Q3OBJ += \
+ $(B)/client/snapvector.o \
+ $(B)/client/ftola.o
endif
ifeq ($(USE_VOIP),1)
@@ -1733,19 +1751,42 @@ endif
ifeq ($(HAVE_VM_COMPILED),true)
ifeq ($(ARCH),i386)
- Q3OBJ += $(B)/client/vm_x86.o
+ Q3OBJ += \
+ $(B)/client/vm_x86.o
endif
ifeq ($(ARCH),x86)
- Q3OBJ += $(B)/client/vm_x86.o
+ Q3OBJ += \
+ $(B)/client/vm_x86.o
endif
ifeq ($(ARCH),x86_64)
- Q3OBJ += $(B)/client/vm_x86_64.o $(B)/client/vm_x86_64_assembler.o
+ ifeq ($(USE_OLD_VM64),1)
+ Q3OBJ += \
+ $(B)/client/vm_x86_64.o \
+ $(B)/client/vm_x86_64_assembler.o
+ else
+ Q3OBJ += \
+ $(B)/client/vm_x86.o
+ endif
endif
ifeq ($(ARCH),amd64)
- Q3OBJ += $(B)/client/vm_x86_64.o $(B)/client/vm_x86_64_assembler.o
+ ifeq ($(USE_OLD_VM64),1)
+ Q3OBJ += \
+ $(B)/client/vm_x86_64.o \
+ $(B)/client/vm_x86_64_assembler.o
+ else
+ Q3OBJ += \
+ $(B)/client/vm_x86.o
+ endif
endif
ifeq ($(ARCH),x64)
- Q3OBJ += $(B)/client/vm_x86_64.o $(B)/client/vm_x86_64_assembler.o
+ ifeq ($(USE_OLD_VM64),1)
+ Q3OBJ += \
+ $(B)/client/vm_x86_64.o \
+ $(B)/client/vm_x86_64_assembler.o
+ else
+ Q3OBJ += \
+ $(B)/client/vm_x86.o
+ endif
endif
ifeq ($(ARCH),ppc)
Q3OBJ += $(B)/client/vm_powerpc.o $(B)/client/vm_powerpc_asm.o
@@ -1895,15 +1936,30 @@ Q3DOBJ = \
ifeq ($(ARCH),i386)
Q3DOBJ += \
- $(B)/ded/ftola.o \
- $(B)/ded/snapvectora.o \
- $(B)/ded/matha.o
+ $(B)/ded/matha.o \
+ $(B)/ded/snapvector.o \
+ $(B)/ded/ftola.o
endif
ifeq ($(ARCH),x86)
Q3DOBJ += \
- $(B)/ded/ftola.o \
- $(B)/ded/snapvectora.o \
- $(B)/ded/matha.o
+ $(B)/ded/matha.o \
+ $(B)/ded/snapvector.o \
+ $(B)/ded/ftola.o
+endif
+ifeq ($(ARCH),x86_64)
+ Q3DOBJ += \
+ $(B)/ded/snapvector.o \
+ $(B)/ded/ftola.o
+endif
+ifeq ($(ARCH),amd64)
+ Q3DOBJ += \
+ $(B)/ded/snapvector.o \
+ $(B)/ded/ftola.o
+endif
+ifeq ($(ARCH),x64)
+ Q3DOBJ += \
+ $(B)/ded/snapvector.o \
+ $(B)/ded/ftola.o
endif
ifeq ($(USE_INTERNAL_ZLIB),1)
@@ -1918,19 +1974,42 @@ endif
ifeq ($(HAVE_VM_COMPILED),true)
ifeq ($(ARCH),i386)
- Q3DOBJ += $(B)/ded/vm_x86.o
+ Q3DOBJ += \
+ $(B)/ded/vm_x86.o
endif
ifeq ($(ARCH),x86)
- Q3DOBJ += $(B)/ded/vm_x86.o
+ Q3DOBJ += \
+ $(B)/ded/vm_x86.o
endif
ifeq ($(ARCH),x86_64)
- Q3DOBJ += $(B)/ded/vm_x86_64.o $(B)/ded/vm_x86_64_assembler.o
+ ifeq ($(USE_OLD_VM64),1)
+ Q3DOBJ += \
+ $(B)/ded/vm_x86_64.o \
+ $(B)/ded/vm_x86_64_assembler.o
+ else
+ Q3DOBJ += \
+ $(B)/ded/vm_x86.o
+ endif
endif
ifeq ($(ARCH),amd64)
- Q3DOBJ += $(B)/ded/vm_x86_64.o $(B)/ded/vm_x86_64_assembler.o
+ ifeq ($(USE_OLD_VM64),1)
+ Q3DOBJ += \
+ $(B)/ded/vm_x86_64.o \
+ $(B)/ded/vm_x86_64_assembler.o
+ else
+ Q3DOBJ += \
+ $(B)/ded/vm_x86.o
+ endif
endif
ifeq ($(ARCH),x64)
- Q3DOBJ += $(B)/ded/vm_x86_64.o $(B)/ded/vm_x86_64_assembler.o
+ ifeq ($(USE_OLD_VM64),1)
+ Q3DOBJ += \
+ $(B)/ded/vm_x86_64.o \
+ $(B)/ded/vm_x86_64_assembler.o
+ else
+ Q3DOBJ += \
+ $(B)/ded/vm_x86.o
+ endif
endif
ifeq ($(ARCH),ppc)
Q3DOBJ += $(B)/ded/vm_powerpc.o $(B)/ded/vm_powerpc_asm.o
@@ -2308,6 +2387,10 @@ $(B)/missionpack/vm/ui.qvm: $(MPUIVMOBJ)
$(B)/client/%.o: $(ASMDIR)/%.s
$(DO_AS)
+# k8 so inline assembler knows about SSE
+$(B)/client/%.o: $(ASMDIR)/%.c
+ $(DO_CC) -march=k8
+
$(B)/client/%.o: $(CDIR)/%.c
$(DO_CC)
@@ -2351,6 +2434,10 @@ $(B)/client/%.o: $(SYSDIR)/%.rc
$(B)/ded/%.o: $(ASMDIR)/%.s
$(DO_AS)
+# k8 so inline assembler knows about SSE
+$(B)/ded/%.o: $(ASMDIR)/%.c
+ $(DO_CC) -march=k8
+
$(B)/ded/%.o: $(SDIR)/%.c
$(DO_DED_CC)
Index: code/server/sv_game.c
===================================================================
--- code/server/sv_game.c.orig
+++ code/server/sv_game.c
@@ -427,7 +427,7 @@ intptr_t SV_GameSystemCalls( intptr_t *a
case G_REAL_TIME:
return Com_RealTime( VMA(1) );
case G_SNAPVECTOR:
- Sys_SnapVector( VMA(1) );
+ Q_SnapVector(VMA(1));
return 0;
//====================================
@@ -535,7 +535,7 @@ intptr_t SV_GameSystemCalls( intptr_t *a
case BOTLIB_EA_ACTION:
botlib_export->ea.EA_Action( args[1], args[2] );
- break;
+ return 0;
case BOTLIB_EA_GESTURE:
botlib_export->ea.EA_Gesture( args[1] );
return 0;
@@ -841,7 +841,7 @@ intptr_t SV_GameSystemCalls( intptr_t *a
default:
Com_Error( ERR_DROP, "Bad game system trap: %ld", (long int) args[0] );
}
- return -1;
+ return 0;
}
/*