summaryrefslogtreecommitdiff
path: root/src/qcommon
diff options
context:
space:
mode:
Diffstat (limited to 'src/qcommon')
-rw-r--r--src/qcommon/vm_local.h1
-rw-r--r--src/qcommon/vm_x86.c918
2 files changed, 625 insertions, 294 deletions
diff --git a/src/qcommon/vm_local.h b/src/qcommon/vm_local.h
index 42120206..60709054 100644
--- a/src/qcommon/vm_local.h
+++ b/src/qcommon/vm_local.h
@@ -152,6 +152,7 @@ struct vm_s {
qboolean compiled;
byte *codeBase;
+ int entryOfs;
int codeLength;
int *instructionPointers;
diff --git a/src/qcommon/vm_x86.c b/src/qcommon/vm_x86.c
index afa29d4c..8a24c650 100644
--- a/src/qcommon/vm_x86.c
+++ b/src/qcommon/vm_x86.c
@@ -57,12 +57,11 @@ static void VM_Destroy_Compiled(vm_t* self);
#define VMFREE_BUFFERS() do {Z_Free(buf); Z_Free(jused);} while(0)
static byte *buf = NULL;
static byte *jused = NULL;
+static int jusedSize = 0;
static int compiledOfs = 0;
static byte *code = NULL;
static int pc = 0;
-static int *instructionPointers = NULL;
-
#define FTOL_PTR
#ifdef _MSC_VER
@@ -88,15 +87,10 @@ static int ftolPtr = (int)qftol0F7F;
#endif
-void AsmCall(void);
-static void (*const asmCallPtr)(void) = AsmCall;
-
-
-static int callMask = 0;
-
static int instruction, pass;
static int lastConst = 0;
static int oc0, oc1, pop0, pop1;
+static int jlabel;
typedef enum
{
@@ -108,144 +102,23 @@ typedef enum
static ELastCommand LastCommand;
-/*
-=================
-AsmCall
-=================
-*/
-#ifdef _MSC_VER
-__declspec( naked ) void AsmCall( void ) {
-int programStack;
-int *opStack;
-int syscallNum;
-vm_t* savedVM;
-
-__asm {
- mov eax, dword ptr [edi]
- sub edi, 4
- test eax,eax
- jl systemCall
- // calling another vm function
- shl eax,2
- add eax, dword ptr [instructionPointers]
- call dword ptr [eax]
- mov eax, dword ptr [edi]
- and eax, [callMask]
- ret
-systemCall:
-
- // convert negative num to system call number
- // and store right before the first arg
- not eax
-
- push ebp
- mov ebp, esp
- sub esp, __LOCAL_SIZE
-
- mov dword ptr syscallNum, eax // so C code can get at it
- mov dword ptr programStack, esi // so C code can get at it
- mov dword ptr opStack, edi
-
- push ecx
- push esi // we may call recursively, so the
- push edi // statics aren't guaranteed to be around
-}
-
- savedVM = currentVM;
-
- // save the stack to allow recursive VM entry
- currentVM->programStack = programStack - 4;
- *(int *)((byte *)currentVM->dataBase + programStack + 4) = syscallNum;
-//VM_LogSyscalls( (int *)((byte *)currentVM->dataBase + programStack + 4) );
- *(opStack+1) = currentVM->systemCall( (int *)((byte *)currentVM->dataBase + programStack + 4) );
-
- currentVM = savedVM;
-
-_asm {
- pop edi
- pop esi
- pop ecx
- add edi, 4 // we added the return value
-
- mov esp, ebp
- pop ebp
-
- ret
-}
-
+static void ErrJump( void )
+{
+ Com_Error( ERR_DROP, "program tried to execute code outside VM\n" );
+ exit(1);
}
-#else //!_MSC_VER
+static void (*const errJumpPtr)(void) = ErrJump;
-#if defined(__MINGW32__) || defined(MACOS_X) // _ is prepended to compiled symbols
-#define CMANGVAR(sym) "_"#sym
-#define CMANGFUNC(sym) "_"#sym
-#elif defined(__ICC) && (__ICC >= 1000)
-#define CMANGVAR(sym) #sym".0"
-#define CMANGFUNC(sym) #sym
-#else
-#define CMANGVAR(sym) #sym
-#define CMANGFUNC(sym) #sym
-#endif
-
-static void __attribute__((cdecl, used)) CallAsmCall(int const syscallNum,
- int const programStack, int* const opStack)
+static int NextConstant4(void)
{
- vm_t *const vm = currentVM;
- intptr_t *const data = (intptr_t*)(vm->dataBase + programStack + 4);
-
- // save the stack to allow recursive VM entry
- vm->programStack = programStack - 4;
- *data = syscallNum;
- opStack[1] = vm->systemCall(data);
-
- currentVM = vm;
+ return (code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24));
}
-__asm__(
- ".text\n\t"
- ".p2align 4,,15\n\t"
-#if defined __ELF__
- ".type " CMANGFUNC(AsmCall) ", @function\n"
-#endif
- CMANGFUNC(AsmCall) ":\n\t"
- "movl (%edi), %eax\n\t"
- "subl $4, %edi\n\t"
- "testl %eax, %eax\n\t"
- "jl 0f\n\t"
- "shll $2, %eax\n\t"
- "addl " CMANGVAR(instructionPointers) ", %eax\n\t"
- "call *(%eax)\n\t"
- "movl (%edi), %eax\n\t"
- "andl " CMANGVAR(callMask) ", %eax\n\t"
- "ret\n"
- "0:\n\t" // system call
- "notl %eax\n\t"
- "pushl %ebp\n\t"
- "movl %esp, %ebp\n\t"
- "andl $-16, %esp\n\t" // align the stack so engine can use sse
- "pushl %ecx\n\t"
- "pushl %edi\n\t" // opStack
- "pushl %esi\n\t" // programStack
- "pushl %eax\n\t" // syscallNum
- "call " CMANGFUNC(CallAsmCall) "\n\t"
- "addl $12, %esp\n\t"
- "popl %ecx\n\t"
- "movl %ebp, %esp\n\t"
- "popl %ebp\n\t"
- "addl $4, %edi\n\t"
- "ret\n\t"
-#if defined __ELF__
- ".size " CMANGFUNC(AsmCall)", .-" CMANGFUNC(AsmCall)
-#endif
-);
-
-#endif
-
static int Constant4( void ) {
int v;
- v = code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24);
+ v = NextConstant4();
pc += 4;
return v;
}
@@ -337,15 +210,19 @@ static void EmitCommand(ELastCommand command)
LastCommand = command;
}
-static void EmitAddEDI4(vm_t *vm) {
- if (LastCommand == LAST_COMMAND_SUB_DI_4 && jused[instruction-1] == 0)
- { // sub di,4
+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 && jused[instruction-1] == 0)
- { // sub di,8
+ if ( LastCommand == LAST_COMMAND_SUB_DI_8 )
+ { // sub edi, 8
compiledOfs -= 3;
vm->instructionPointers[ instruction-1 ] = compiledOfs;
EmitString( "83 EF 04" ); // sub edi,4
@@ -355,6 +232,10 @@ static void EmitAddEDI4(vm_t *vm) {
}
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;
@@ -374,25 +255,51 @@ static void EmitMovEAXEDI(vm_t *vm) {
Emit4( lastConst );
return;
}
- EmitString( "8B 07" ); // mov eax, dword ptr [edi]
+ 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
+ {
+ 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;
+ }
+ EmitString( "8B 0F" ); // mov ecx, dword ptr [edi]
}
+
qboolean EmitMovEBXEDI(vm_t *vm, int andit) {
- if (LastCommand == LAST_COMMAND_MOV_EDI_EAX)
- { // mov [edi], eax
+ 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;
}
- if (pop1 == OP_DIVI || pop1 == OP_DIVU || pop1 == OP_MULI || pop1 == OP_MULU ||
+ 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;
}
- if (pop1 == OP_CONST && buf[compiledOfs-6] == 0xC7 && buf[compiledOfs-5] == 0x07 )
- { // mov edi, 0x123456
+ 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
@@ -404,7 +311,7 @@ qboolean EmitMovEBXEDI(vm_t *vm, int andit) {
return qtrue;
}
- EmitString( "8B 1F" ); // mov ebx, dword ptr [edi]
+ EmitString( "8B 1F" ); // mov ebx, dword ptr [edi]
return qfalse;
}
@@ -418,6 +325,499 @@ qboolean EmitMovEBXEDI(vm_t *vm, int andit) {
jused[x] = 1; \
} while(0)
+#define SET_JMPOFS(x) do { buf[(x)] = compiledOfs - ((x) + 1); } while(0)
+
+/*
+=================
+DoSyscall
+Uses asm to get arguments from stack to work around different calling conventions
+=================
+*/
+
+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
+#ifdef _MSC_VER
+ __asm
+ {
+ mov dword ptr syscallNum, eax
+ mov dword ptr programStack, esi
+ mov dword ptr opStack, edi
+ }
+#else
+ __asm__ volatile(
+ ""
+ : "=a" (syscallNum), "=S" (programStack), "=D" (opStack)
+ :
+ : "memory"
+ );
+#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);
+
+ currentVM = savedVM;
+}
+
+/*
+=================
+EmitCallProcedure
+=================
+*/
+
+int EmitCallProcedure(vm_t *vm)
+{
+ int jmpSystemCall, jmpBadAddr;
+ int retval;
+
+ EmitString("8B 07"); // mov eax, dword ptr [edi]
+ EmitString("83 EF 04"); // sub edi, 4
+ EmitString("85 C0"); // test eax, eax
+
+ // Jump to syscall code
+ EmitString("7C"); // jl systemCall
+ jmpSystemCall = compiledOfs++;
+
+ /************ Call inside VM ************/
+
+ EmitString("81 F8"); // cmp eax, vm->instructionCount
+ Emit4(vm->instructionCount);
+
+ // Error jump if invalid jump target
+ EmitString("73"); // jae badAddr
+ jmpBadAddr = compiledOfs++;
+
+ 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
+
+ // badAddr:
+ SET_JMPOFS(jmpBadAddr);
+ EmitString("B8"); // mov eax, ErrJump
+ Emit4((intptr_t) ErrJump);
+ EmitString("FF D0"); // call eax
+
+ /************ System Call ************/
+
+ // systemCall:
+ 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
+
+ // have opStack reg point at return value
+ EmitString("83 C7 04"); // add edi, 4
+ EmitString("C3"); // ret
+
+ return retval;
+}
+
+void EmitCall(vm_t *vm, int sysCallOfs)
+{
+ 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);
+ }
+ }
+
+ EmitString("FF D1"); // call ecx
+ EmitString("59"); // pop ecx
+}
+
+/*
+=================
+EmitCallConst
+=================
+*/
+
+void EmitCallConst(vm_t *vm, int cdest, int sysCallOfs)
+{
+ if(cdest < 0)
+ {
+ EmitString("B8"); // mov eax, cdest
+ Emit4(cdest);
+
+ EmitCall(vm, sysCallOfs);
+ }
+ else
+ {
+ JUSED(cdest);
+ EmitString("FF 15"); // call dword ptr [vm->instructionPointers + cdest]
+ Emit4((intptr_t) &vm->instructionPointers[cdest]);
+ }
+}
+
+
+/*
+=================
+ConstOptimize
+=================
+*/
+qboolean ConstOptimize(vm_t *vm, int sysCallOfs)
+{
+ int v, opt;
+ int op1;
+
+ // we can safely perform optimizations only in case if
+ // we are 100% sure that next instruction is not a jump label
+ if (vm->jumpTableTargets && !jused[instruction])
+ op1 = code[pc+4];
+ else
+ return qfalse;
+
+ 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
+ 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
+ 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
+ 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
+ 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
+ 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
+ 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 );
+ }
+ EmitCommand( LAST_COMMAND_MOV_EDI_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 );
+ }
+ EmitCommand( LAST_COMMAND_MOV_EDI_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 );
+ }
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );
+ pc++; // OP_MULI
+ instruction += 1;
+ return qtrue;
+
+ case OP_LSH:
+ v = NextConstant4();
+ 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
+ instruction += 1;
+ return qtrue;
+
+ case OP_RSHI:
+ v = NextConstant4();
+ 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
+ instruction += 1;
+ return qtrue;
+
+ case OP_RSHU:
+ v = NextConstant4();
+ 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
+ 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 );
+ }
+ EmitCommand( LAST_COMMAND_MOV_EDI_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 );
+ }
+ EmitCommand( LAST_COMMAND_MOV_EDI_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 );
+ }
+ 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 );
+ 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_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;
+ 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
+ else
+ EmitString( "7D 06" ); // jge +6
+ EmitString( "FF 25" ); // jmp [0x12345678]
+ v = Constant4();
+ JUSED(v);
+ Emit4( (int)vm->instructionPointers + v*4 );
+ 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 );
+ pc += 1; // OP_JUMP
+ instruction += 1;
+ return qtrue;
+
+ case OP_CALL:
+ if ( NextConstant4() < 0 )
+ break;
+ v = Constant4();
+ EmitCallConst(vm, v, sysCallOfs);
+
+ pc += 1; // OP_CALL
+ instruction += 1;
+ return qtrue;
+
+ default:
+ break;
+ }
+
+ return qfalse;
+}
+
+
/*
=================
VM_Compile
@@ -428,15 +828,24 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
int maxLength;
int v;
int i;
- qboolean opt;
- int jusedSize = header->instructionCount + 2;
+ int sysCallOfs;
+
+ jusedSize = header->instructionCount + 2;
// allocate a very large temp buffer, we will shrink it later
maxLength = header->codeLength * 8;
buf = Z_Malloc(maxLength);
jused = Z_Malloc(jusedSize);
+ code = Z_Malloc(header->codeLength+32);
Com_Memset(jused, 0, jusedSize);
+ Com_Memset(buf, 0, maxLength);
+
+ // copy code in larger buffer and put some zeros at the end
+ // so we can safely look ahead for a few instructions in it
+ // without a chance to get false-positive because of some garbage bytes
+ Com_Memset(code, 0, header->codeLength+32);
+ Com_Memcpy(code, (byte *)header + header->codeOffset, header->codeLength );
// ensure that the optimisation pass knows about all the jump
// table targets
@@ -444,6 +853,11 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
jused[ *(int *)(vm->jumpTableTargets + ( i * sizeof( int ) ) ) ] = 1;
}
+ // Start buffer with x86-VM specific procedures
+ compiledOfs = 0;
+ sysCallOfs = EmitCallProcedure(vm);
+ vm->entryOfs = compiledOfs;
+
for(pass=0;pass<2;pass++) {
oc0 = -23423;
oc1 = -234354;
@@ -453,8 +867,8 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
// translate all instructions
pc = 0;
instruction = 0;
- code = (byte *)header + header->codeOffset;
- compiledOfs = 0;
+ //code = (byte *)header + header->codeOffset;
+ compiledOfs = vm->entryOfs;
LastCommand = LAST_COMMAND_NONE;
@@ -467,6 +881,12 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
}
vm->instructionPointers[ instruction ] = compiledOfs;
+
+ if ( !vm->jumpTableTargets )
+ jlabel = 1;
+ else
+ jlabel = jused[ instruction ];
+
instruction++;
if(pc > header->codeLength)
@@ -488,95 +908,9 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
Emit4( Constant4() );
break;
case OP_CONST:
- if (code[pc+4] == 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
- pc++; // OP_LOAD4
- instruction += 1;
+ if(ConstOptimize(vm, sysCallOfs))
break;
- }
- if (code[pc+4] == 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
- pc++; // OP_LOAD4
- instruction += 1;
- break;
- }
- if (code[pc+4] == 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
- pc++; // OP_LOAD4
- instruction += 1;
- break;
- }
- if (code[pc+4] == 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
- pc++; // OP_STORE4
- instruction += 1;
- break;
- }
- if (code[pc+4] == 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_STORE4
- instruction += 1;
- break;
- }
- if (code[pc+4] == 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
- instruction += 1;
- break;
- }
- if (code[pc+4] == OP_ADD) {
- EmitString( "81 07" ); // add dword ptr [edi], 0x1234567
- Emit4( Constant4() );
- pc++; // OP_ADD
- instruction += 1;
- break;
- }
- if (code[pc+4] == OP_SUB) {
- EmitString( "81 2F" ); // sub dword ptr [edi], 0x1234567
- Emit4( Constant4() );
- pc++; // OP_ADD
- instruction += 1;
- break;
- }
+
EmitAddEDI4(vm);
EmitString( "C7 07" ); // mov dword ptr [edi], 0x12345678
lastConst = Constant4();
@@ -596,16 +930,11 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
case OP_ARG:
EmitMovEAXEDI(vm); // mov eax,dword ptr [edi]
EmitString( "89 86" ); // mov dword ptr [esi+database],eax
- // FIXME: range check
- Emit4( Constant1() + (int)vm->dataBase );
+ Emit4((Constant1() & vm->dataMask & 0xFF) + (int) vm->dataBase);
EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
break;
case OP_CALL:
- EmitString( "C7 86" ); // mov dword ptr [esi+database],0x12345678
- Emit4( (int)vm->dataBase );
- Emit4( pc );
- EmitString( "FF 15" ); // call asmCallPtr
- Emit4( (int)&asmCallPtr );
+ EmitCall(vm, 0);
break;
case OP_PUSH:
EmitAddEDI4(vm);
@@ -742,9 +1071,9 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
break;
case OP_EQ:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4]
- EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
+ 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();
@@ -752,9 +1081,9 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
Emit4( (int)vm->instructionPointers + v*4 );
break;
case OP_NE:
- EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4]
- EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
+ 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();
@@ -762,9 +1091,9 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
Emit4( (int)vm->instructionPointers + v*4 );
break;
case OP_LTI:
+ EmitMovEAXEDI( vm );
EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4]
- EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
+ EmitString( "39 47 04" ); // cmp dword ptr [edi+4], eax
EmitString( "7D 06" ); // jnl +6
EmitString( "FF 25" ); // jmp [0x12345678]
v = Constant4();
@@ -772,9 +1101,9 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
Emit4( (int)vm->instructionPointers + v*4 );
break;
case OP_LEI:
+ EmitMovEAXEDI( vm );
EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4]
- EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
+ EmitString( "39 47 04" ); // cmp dword ptr [edi+4], eax
EmitString( "7F 06" ); // jnle +6
EmitString( "FF 25" ); // jmp [0x12345678]
v = Constant4();
@@ -782,9 +1111,9 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
Emit4( (int)vm->instructionPointers + v*4 );
break;
case OP_GTI:
+ EmitMovEAXEDI( vm );
EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4]
- EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
+ EmitString( "39 47 04" ); // cmp eax, dword ptr [edi+4]
EmitString( "7E 06" ); // jng +6
EmitString( "FF 25" ); // jmp [0x12345678]
v = Constant4();
@@ -792,9 +1121,9 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
Emit4( (int)vm->instructionPointers + v*4 );
break;
case OP_GEI:
+ EmitMovEAXEDI( vm );
EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4]
- EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
+ EmitString( "39 47 04" ); // cmp eax, dword ptr [edi+4]
EmitString( "7C 06" ); // jnge +6
EmitString( "FF 25" ); // jmp [0x12345678]
v = Constant4();
@@ -802,9 +1131,9 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
Emit4( (int)vm->instructionPointers + v*4 );
break;
case OP_LTU:
+ EmitMovEAXEDI( vm );
EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4]
- EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
+ EmitString( "39 47 04" ); // cmp eax, dword ptr [edi+4]
EmitString( "73 06" ); // jnb +6
EmitString( "FF 25" ); // jmp [0x12345678]
v = Constant4();
@@ -812,9 +1141,9 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
Emit4( (int)vm->instructionPointers + v*4 );
break;
case OP_LEU:
+ EmitMovEAXEDI( vm );
EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4]
- EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
+ EmitString( "39 47 04" ); // cmp eax, dword ptr [edi+4]
EmitString( "77 06" ); // jnbe +6
EmitString( "FF 25" ); // jmp [0x12345678]
v = Constant4();
@@ -822,9 +1151,9 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
Emit4( (int)vm->instructionPointers + v*4 );
break;
case OP_GTU:
+ EmitMovEAXEDI( vm );
EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4]
- EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
+ EmitString( "39 47 04" ); // cmp eax, dword ptr [edi+4]
EmitString( "76 06" ); // jna +6
EmitString( "FF 25" ); // jmp [0x12345678]
v = Constant4();
@@ -832,9 +1161,9 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
Emit4( (int)vm->instructionPointers + v*4 );
break;
case OP_GEU:
+ EmitMovEAXEDI( vm );
EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
- EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4]
- EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
+ EmitString( "39 47 04" ); // cmp eax, dword ptr [edi+4]
EmitString( "72 06" ); // jnae +6
EmitString( "FF 25" ); // jmp [0x12345678]
v = Constant4();
@@ -914,7 +1243,9 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
Emit4( (int)vm->instructionPointers + v*4 );
break;
case OP_NEGI:
- EmitString( "F7 1F" ); // neg dword ptr [edi]
+ EmitMovEAXEDI( vm );
+ EmitString( "F7 D8" ); // neg eax
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );
break;
case OP_ADD:
EmitMovEAXEDI(vm); // mov eax, dword ptr [edi]
@@ -985,18 +1316,21 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
EmitString( "F7 17" ); // not dword ptr [edi]
break;
case OP_LSH:
- EmitString( "8B 0F" ); // mov ecx, dword ptr [edi]
- EmitString( "D3 67 FC" ); // shl dword ptr [edi-4], cl
+ //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
break;
case OP_RSHI:
- EmitString( "8B 0F" ); // mov ecx, dword ptr [edi]
- EmitString( "D3 7F FC" ); // sar dword ptr [edi-4], cl
+ //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
break;
case OP_RSHU:
- EmitString( "8B 0F" ); // mov ecx, dword ptr [edi]
- EmitString( "D3 6F FC" ); // shr dword ptr [edi-4], cl
+ //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
break;
case OP_NEGF:
@@ -1077,11 +1411,15 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
break;
case OP_JUMP:
- EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
- EmitString( "8B 47 04" ); // mov eax,dword ptr [edi+4]
- // FIXME: range check
- EmitString( "FF 24 85" ); // jmp dword ptr [instructionPointers + eax * 4]
- Emit4( (int)vm->instructionPointers );
+ EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ EmitString( "8B 47 04" ); // mov eax,dword ptr [edi+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]
+ Emit4((intptr_t) vm->instructionPointers);
+ EmitString( "FF 15" ); // call errJumpPtr
+ Emit4((intptr_t) &errJumpPtr);
break;
default:
VMFREE_BUFFERS();
@@ -1092,7 +1430,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
}
}
- // copy to an exact size buffer on the hunk
+ // copy to an exact sized buffer with the appropriate permission bits
vm->codeLength = compiledOfs;
#ifdef VM_X86_MMAP
vm->codeBase = mmap(NULL, compiledOfs, PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
@@ -1124,6 +1462,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
}
#endif
+ Z_Free( code );
Z_Free( buf );
Z_Free( jused );
Com_Printf( "VM file %s compiled to %i bytes of code\n", vm->name, compiledOfs );
@@ -1161,18 +1500,12 @@ int VM_CallCompiled( vm_t *vm, int *args ) {
int stackOnEntry;
byte *image;
void *opStack;
- int *oldInstructionPointers;
-
- oldInstructionPointers = instructionPointers;
currentVM = vm;
- instructionPointers = vm->instructionPointers;
// interpret the code
vm->currentlyInterpreting = qtrue;
- callMask = vm->dataMask;
-
// we might be called recursively, so this might not be the very top
programStack = vm->programStack;
stackOnEntry = programStack;
@@ -1202,7 +1535,7 @@ int VM_CallCompiled( vm_t *vm, int *args ) {
{
#ifdef _MSC_VER
- void *entryPoint = vm->codeBase;
+ void *entryPoint = vm->codeBase + vm->entryOfs;
__asm {
pushad
@@ -1225,7 +1558,7 @@ int VM_CallCompiled( vm_t *vm, int *args ) {
"call *%6"
: "+S" (programStack), "+D" (opStack),
"=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
- : "mr" (vm->codeBase)
+ : "mr" (vm->codeBase + vm->entryOfs)
: "cc", "memory"
);
#endif
@@ -1240,8 +1573,5 @@ int VM_CallCompiled( vm_t *vm, int *args ) {
vm->programStack = stackOnEntry;
- // in case we were recursively called by another vm
- instructionPointers = oldInstructionPointers;
-
return *(int *)opStack;
}