3e9809c
From ffac0e67574891072f74db3769b5ca7e252853b1 Mon Sep 17 00:00:00 2001
3e9809c
From: Thilo Schulz <arny@ats.s.bawue.de>
3e9809c
Date: Wed, 8 Aug 2012 09:34:03 +0000
3e9809c
Subject: [PATCH] Move argument passing from VM to engine to global variables
3e9809c
 which allows to get rid of lots of OS specific stuff and also fixes errors
3e9809c
 that happens when compilers add lots of boilerplate to the DoSyscall()
3e9809c
 function
3e9809c
3e9809c
[jlayton: a little wiggling to merge into r2102]
3e9809c
3e9809c
---
3e9809c
 code/asm/vm_x86_64.asm | 18 ----------
3e9809c
 code/qcommon/vm_x86.c  | 91 ++++++++++++++++++++++----------------------------
3e9809c
 2 files changed, 40 insertions(+), 69 deletions(-)
3e9809c
3e9809c
diff --git a/code/asm/vm_x86_64.asm b/code/asm/vm_x86_64.asm
3e9809c
index 030b6987db94..87e04f4dbbd3 100644
3e9809c
--- a/code/asm/vm_x86_64.asm
3e9809c
+++ b/code/asm/vm_x86_64.asm
3e9809c
@@ -23,26 +23,8 @@
3e9809c
 ;
3e9809c
 ; assumes __fastcall calling convention
3e9809c
 
3e9809c
-DoSyscall PROTO
3e9809c
-
3e9809c
 .code
3e9809c
 
3e9809c
-; Call to static void DoSyscall(int syscallNum, int programStack, int *opStackBase, uint8_t opStackOfs, intptr_t arg)
3e9809c
-
3e9809c
-qsyscall64 PROC
3e9809c
-  sub rsp, 28h						; after this esp will be aligned to 16 byte boundary
3e9809c
-  mov qword ptr [rsp + 20h], rcx	; 5th parameter "arg" is passed on stack
3e9809c
-  mov r9b, bl						; opStackOfs
3e9809c
-  mov r8, rdi						; opStackBase
3e9809c
-  mov edx, esi						; programStack
3e9809c
-  mov ecx, eax						; syscallNum
3e9809c
-  mov rax, DoSyscall				; store call address of DoSyscall in rax
3e9809c
-  call rax
3e9809c
-  add rsp, 28h
3e9809c
-  ret
3e9809c
-qsyscall64 ENDP
3e9809c
-
3e9809c
-
3e9809c
 ; Call to compiled code after setting up the register environment for the VM
3e9809c
 ; prototype:
3e9809c
 ; uint8_t qvmcall64(int *programStack, int *opStack, intptr_t *instructionPointers, byte *dataBase);
3e9809c
diff --git a/code/qcommon/vm_x86.c b/code/qcommon/vm_x86.c
3e9809c
index aa63d048471e..080fe54ec15d 100644
3e9809c
--- a/code/qcommon/vm_x86.c
3e9809c
+++ b/code/qcommon/vm_x86.c
3e9809c
@@ -389,55 +389,28 @@ static void ErrJump(void)
3e9809c
 /*
3e9809c
 =================
3e9809c
 DoSyscall
3e9809c
-Uses asm to retrieve arguments from registers to work around different calling conventions
3e9809c
+
3e9809c
+Assembler helper routines will write its arguments directly to global variables so as to
3e9809c
+work around different calling conventions
3e9809c
 =================
3e9809c
 */
3e9809c
 
3e9809c
-#if defined(_MSC_VER) && idx64
3e9809c
-
3e9809c
-extern void qsyscall64(void);
3e9809c
-extern uint8_t qvmcall64(int *programStack, int *opStack, intptr_t *instructionPointers, byte *dataBase);
3e9809c
+int vm_syscallNum;
3e9809c
+int vm_programStack;
3e9809c
+int *vm_opStackBase;
3e9809c
+uint8_t vm_opStackOfs;
3e9809c
+intptr_t vm_arg;
3e9809c
 
3e9809c
-// Microsoft does not support inline assembler on x64 platforms. Meh.
3e9809c
-void DoSyscall(int syscallNum, int programStack, int *opStackBase, uint8_t opStackOfs, intptr_t arg)
3e9809c
-{
3e9809c
-#else
3e9809c
 static void DoSyscall(void)
3e9809c
 {
3e9809c
-	int syscallNum;
3e9809c
-	int programStack;
3e9809c
-	int *opStackBase;
3e9809c
-	uint8_t opStackOfs;
3e9809c
-	intptr_t arg;
3e9809c
-#endif
3e9809c
-
3e9809c
 	vm_t *savedVM;
3e9809c
 
3e9809c
-#if defined(_MSC_VER)
3e9809c
-  #if !idx64
3e9809c
-	__asm
3e9809c
-	{
3e9809c
-		mov	dword ptr syscallNum, eax
3e9809c
-		mov	dword ptr programStack, esi
3e9809c
-		mov	byte ptr opStackOfs, bl
3e9809c
-		mov	dword ptr opStackBase, edi
3e9809c
-		mov	dword ptr arg, ecx
3e9809c
-	}
3e9809c
-  #endif
3e9809c
-#else
3e9809c
-	__asm__ volatile(
3e9809c
-		""
3e9809c
-		: "=a" (syscallNum), "=S" (programStack), "=D" (opStackBase), "=b" (opStackOfs),
3e9809c
-		  "=c" (arg)
3e9809c
-		);
3e9809c
-#endif
3e9809c
-
3e9809c
 	// save currentVM so as to allow for recursive VM entry
3e9809c
 	savedVM = currentVM;
3e9809c
 	// modify VM stack pointer for recursive VM entry
3e9809c
-	currentVM->programStack = programStack - 4;
3e9809c
+	currentVM->programStack = vm_programStack - 4;
3e9809c
 
3e9809c
-	if(syscallNum < 0)
3e9809c
+	if(vm_syscallNum < 0)
3e9809c
 	{
3e9809c
 		int *data;
3e9809c
 #if idx64
3e9809c
@@ -445,34 +418,34 @@ static void DoSyscall(void)
3e9809c
 		intptr_t args[11];
3e9809c
 #endif
3e9809c
 		
3e9809c
-		data = (int *) (savedVM->dataBase + programStack + 4);
3e9809c
+		data = (int *) (savedVM->dataBase + vm_programStack + 4);
3e9809c
 
3e9809c
 #if idx64
3e9809c
-		args[0] = ~syscallNum;
3e9809c
+		args[0] = ~vm_syscallNum;
3e9809c
 		for(index = 1; index < ARRAY_LEN(args); index++)
3e9809c
 			args[index] = data[index];
3e9809c
 			
3e9809c
-		opStackBase[opStackOfs + 1] = savedVM->systemCall(args);
3e9809c
+		vm_opStackBase[vm_opStackOfs + 1] = savedVM->systemCall(args);
3e9809c
 #else
3e9809c
-		data[0] = ~syscallNum;
3e9809c
-		opStackBase[opStackOfs + 1] = savedVM->systemCall(data);
3e9809c
+		data[0] = ~vm_syscallNum;
3e9809c
+		vm_opStackBase[vm_opStackOfs + 1] = savedVM->systemCall(data);
3e9809c
 #endif
3e9809c
 	}
3e9809c
 	else
3e9809c
 	{
3e9809c
-		switch(syscallNum)
3e9809c
+		switch(vm_syscallNum)
3e9809c
 		{
3e9809c
 		case VM_JMP_VIOLATION:
3e9809c
 			ErrJump();
3e9809c
 		break;
3e9809c
 		case VM_BLOCK_COPY: 
3e9809c
-			if(opStackOfs < 1)
3e9809c
+			if(vm_opStackOfs < 1)
3e9809c
 				Com_Error(ERR_DROP, "VM_BLOCK_COPY failed due to corrupted opStack");
3e9809c
 			
3e9809c
-			VM_BlockCopy(opStackBase[(opStackOfs - 1)], opStackBase[opStackOfs], arg);
3e9809c
+			VM_BlockCopy(vm_opStackBase[(vm_opStackOfs - 1)], vm_opStackBase[vm_opStackOfs], vm_arg);
3e9809c
 		break;
3e9809c
 		default:
3e9809c
-			Com_Error(ERR_DROP, "Unknown VM operation %d", syscallNum);
3e9809c
+			Com_Error(ERR_DROP, "Unknown VM operation %d", vm_syscallNum);
3e9809c
 		break;
3e9809c
 		}
3e9809c
 	}
3e9809c
@@ -503,13 +476,8 @@ Call to DoSyscall()
3e9809c
 int EmitCallDoSyscall(vm_t *vm)
3e9809c
 {
3e9809c
 	// use edx register to store DoSyscall address
3e9809c
-#if defined(_MSC_VER) && idx64
3e9809c
-	EmitRexString(0x48, "BA");		// mov edx, qsyscall64
3e9809c
-	EmitPtr(qsyscall64);
3e9809c
-#else
3e9809c
 	EmitRexString(0x48, "BA");		// mov edx, DoSyscall
3e9809c
 	EmitPtr(DoSyscall);
3e9809c
-#endif
3e9809c
 
3e9809c
 	// Push important registers to stack as we can't really make
3e9809c
 	// any assumptions about calling conventions.
3e9809c
@@ -521,6 +489,27 @@ int EmitCallDoSyscall(vm_t *vm)
3e9809c
 	EmitRexString(0x41, "51");		// push r9
3e9809c
 #endif
3e9809c
 
3e9809c
+	// write arguments to global vars
3e9809c
+	// syscall number
3e9809c
+	EmitString("A3");			// mov [0x12345678], eax
3e9809c
+	EmitPtr(&vm_syscallNum);
3e9809c
+	// vm_programStack value
3e9809c
+	EmitString("89 F0");			// mov eax, esi
3e9809c
+	EmitString("A3");			// mov [0x12345678], eax
3e9809c
+	EmitPtr(&vm_programStack);
3e9809c
+	// vm_opStackOfs 
3e9809c
+	EmitString("88 D8");			// mov al, bl
3e9809c
+	EmitString("A2");			// mov [0x12345678], al
3e9809c
+	EmitPtr(&vm_opStackOfs);
3e9809c
+	// vm_opStackBase
3e9809c
+	EmitRexString(0x48, "89 F8");		// mov eax, edi
3e9809c
+	EmitRexString(0x48, "A3");		// mov [0x12345678], eax
3e9809c
+	EmitPtr(&vm_opStackBase);
3e9809c
+	// vm_arg
3e9809c
+	EmitString("89 C8");			// mov eax, ecx
3e9809c
+	EmitString("A3");			// mov [0x12345678], eax
3e9809c
+	EmitPtr(&vm_arg);
3e9809c
+	
3e9809c
 	// align the stack pointer to a 16-byte-boundary
3e9809c
 	EmitString("55");			// push ebp
3e9809c
 	EmitRexString(0x48, "89 E5");		// mov ebp, esp