summaryrefslogtreecommitdiff
path: root/src/qcommon
diff options
context:
space:
mode:
authorThilo Schulz <arny@ats.s.bawue.de>2011-06-16 01:11:45 +0000
committerTim Angus <tim@ngus.net>2013-01-10 21:28:21 +0000
commit1d26bab126400b065525340c9b6a377fbf9069f0 (patch)
tree29edb28448c9a3d8a4a9ef422871e4022eae65b7 /src/qcommon
parent2dd04e69725fcb96b43aeac13aa03c8a863e9cd3 (diff)
Various fixes to vm_interpreted.c: - Add opStack protection - Fix dataMask check for OP_BLOCK_COPY - Add instruction number check for conditional jumps - Make errors in VM_PrepareInterpreter nonfatal
Diffstat (limited to 'src/qcommon')
-rw-r--r--src/qcommon/vm.c22
-rw-r--r--src/qcommon/vm_interpreted.c260
-rw-r--r--src/qcommon/vm_local.h2
-rw-r--r--src/qcommon/vm_x86.c24
-rw-r--r--src/qcommon/vm_x86_64.c17
5 files changed, 156 insertions, 169 deletions
diff --git a/src/qcommon/vm.c b/src/qcommon/vm.c
index ce131c2b..caf10863 100644
--- a/src/qcommon/vm.c
+++ b/src/qcommon/vm.c
@@ -950,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);
+}
diff --git a/src/qcommon/vm_interpreted.c b/src/qcommon/vm_interpreted.c
index 2b9ffea6..4ce518a7 100644
--- a/src/qcommon/vm_interpreted.c
+++ b/src/qcommon/vm_interpreted.c
@@ -193,9 +193,8 @@ void VM_PrepareInterpreter( vm_t *vm, vmHeader_t *header ) {
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, vmHeader_t *header ) {
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 *args ) {
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 *args ) {
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 *args ) {
// 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] = (int) ((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];
}
diff --git a/src/qcommon/vm_local.h b/src/qcommon/vm_local.h
index ee44133a..8f23a25e 100644
--- a/src/qcommon/vm_local.h
+++ b/src/qcommon/vm_local.h
@@ -191,3 +191,5 @@ vmSymbol_t *VM_ValueToFunctionSymbol( vm_t *vm, int value );
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);
diff --git a/src/qcommon/vm_x86.c b/src/qcommon/vm_x86.c
index 9e30e32f..b6b301e2 100644
--- a/src/qcommon/vm_x86.c
+++ b/src/qcommon/vm_x86.c
@@ -389,28 +389,6 @@ static void ErrJump(void)
/*
=================
-DoBlockCopy
-Executes OP_BLOCK_COPY
-=================
-*/
-
-void DoBlockCopy(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!");
- }
-
- memcpy(currentVM->dataBase + dest, currentVM->dataBase + src, n);
-}
-
-/*
-=================
DoSyscall
Uses asm to retrieve arguments from registers to work around different calling conventions
=================
@@ -494,7 +472,7 @@ static void DoSyscall(void)
if(opStackOfs < 1)
Com_Error(ERR_DROP, "VM_BLOCK_COPY failed due to corrupted opStack");
- DoBlockCopy(opStackBase[opStackOfs - 1], opStackBase[opStackOfs], arg);
+ VM_BlockCopy(opStackBase[(opStackOfs - 1)], opStackBase[opStackOfs], arg);
break;
default:
Com_Error(ERR_DROP, "Unknown VM operation %d", syscallNum);
diff --git a/src/qcommon/vm_x86_64.c b/src/qcommon/vm_x86_64.c
index c77ab6a3..93b56a37 100644
--- a/src/qcommon/vm_x86_64.c
+++ b/src/qcommon/vm_x86_64.c
@@ -382,21 +382,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!");
@@ -783,7 +768,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
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");