r1448 - trunk/code/qcommon

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Sun Aug 17 19:22:06 EDT 2008


Author: tma
Date: 2008-08-17 19:22:06 -0400 (Sun, 17 Aug 2008)
New Revision: 1448

Modified:
   trunk/code/qcommon/vm_x86.c
Log:
* More robust x86 vm entrypoint/callback assembly (Tron)


Modified: trunk/code/qcommon/vm_x86.c
===================================================================
--- trunk/code/qcommon/vm_x86.c	2008-08-14 07:59:34 UTC (rev 1447)
+++ trunk/code/qcommon/vm_x86.c	2008-08-17 23:22:06 UTC (rev 1448)
@@ -53,7 +53,6 @@
 
 */
 
-// TTimo: initialised the statics, this fixes a crash when entering a compiled VM 
 static	byte	*buf = NULL;
 static	byte	*jused = NULL;
 static	int		compiledOfs = 0;
@@ -71,9 +70,6 @@
 static	int		ftolPtr = (int)_ftol;
 #endif
 
-void AsmCall( void );
-static	int		asmCallPtr = (int)AsmCall;
-
 #else // _MSC_VER
 
 #if defined( FTOL_PTR )
@@ -88,11 +84,12 @@
 static	int		ftolPtr = (int)qftol0F7F;
 #endif // FTOL_PTR
 
-void doAsmCall( void );
-static	int		asmCallPtr = (int)doAsmCall;
 #endif
 
+void AsmCall(void);
+static void (*const asmCallPtr)(void) = AsmCall;
 
+
 static	int		callMask = 0;
 
 static	int	instruction, pass;
@@ -124,7 +121,7 @@
 __asm {
 	mov		eax, dword ptr [edi]
 	sub		edi, 4
-	or		eax,eax
+	test	eax,eax
 	jl		systemCall
 	// calling another vm function
 	shl		eax,2
@@ -137,8 +134,7 @@
 
 	// convert negative num to system call number
 	// and store right before the first arg
-	neg		eax
-	dec		eax
+	not		eax
 
 	push    ebp
 	mov     ebp, esp
@@ -180,70 +176,60 @@
 #else //!_MSC_VER
 
 #if defined(__MINGW32__) || defined(MACOS_X) // _ is prepended to compiled symbols
-#define CMANG(sym) "_"#sym
+#	define CMANG(sym) "_"#sym
 #else
-#define CMANG(sym) #sym
+#	define CMANG(sym) #sym
 #endif
 
-static	int		callProgramStack;
-static	int		*callOpStack;
-static	int		callSyscallNum;
-
-void callAsmCall(void)
+static void __attribute__((cdecl, used)) CallAsmCall(int const syscallNum,
+		int const programStack, int* const opStack)
 {
-	vm_t	*savedVM;
-	int		*callOpStack2;
+	vm_t     *const vm   = currentVM;
+	intptr_t *const data = (intptr_t*)(vm->dataBase + programStack + 4);
 
-	savedVM = currentVM;
-	callOpStack2 = callOpStack;
-
 	// save the stack to allow recursive VM entry
-	currentVM->programStack = callProgramStack - 4;
-	*(int *)((byte *)currentVM->dataBase + callProgramStack + 4) = callSyscallNum;
-	//VM_LogSyscalls((int *)((byte *)currentVM->dataBase + callProgramStack + 4) );
-	*(callOpStack2+1) = currentVM->systemCall( (intptr_t *)((byte *)currentVM->dataBase + callProgramStack + 4) );
+	vm->programStack = programStack - 4;
+	*data = syscallNum;
+	opStack[1] = vm->systemCall(data);
 
- 	currentVM = savedVM;
+	currentVM = vm;
 }
 
-// Note the C space function AsmCall is never actually called, and is in fact
-// arbitrarily named (though this is not true for the MSC version).  When a vm
-// makes a system call, control jumps straight to the doAsmCall label.
-void AsmCall( void ) {
-	__asm__( CMANG(doAsmCall) ":				\n\t" \
-		"	movl (%%edi),%%eax			\n\t" \
-		"	subl $4,%%edi				\n\t" \
-		"	orl %%eax,%%eax				\n\t" \
-		"	jl systemCall				\n\t" \
-		"	shll $2,%%eax				\n\t" \
-		"	addl %3,%%eax				\n\t" \
-		"	call *(%%eax)				\n\t" \
-		"	movl (%%edi),%%eax			\n\t" \
-		"	andl " CMANG(callMask) ", %%eax		\n\t" \
-		"	jmp doret				\n\t" \
-		"systemCall:					\n\t" \
-		"	negl %%eax				\n\t" \
-		"	decl %%eax				\n\t" \
-		"	movl %%eax,%0				\n\t" \
-		"	movl %%esi,%1				\n\t" \
-		"	movl %%edi,%2				\n\t" \
-		"	pushl %%ecx				\n\t" \
-		"	pushl %%esi				\n\t" \
-		"	pushl %%edi				\n\t" \
-		"	call " CMANG(callAsmCall) "		\n\t" \
-		"	popl %%edi				\n\t" \
-		"	popl %%esi				\n\t" \
-		"	popl %%ecx				\n\t" \
-		"	addl $4,%%edi				\n\t" \
-		"doret:						\n\t" \
-		"	ret					\n\t" \
-		: "=rm" (callSyscallNum), "=rm" (callProgramStack), "=rm" (callOpStack) \
-		: "m" (instructionPointers) \
-		: "ax", "di", "si", "cx" \
-	);
-}
+__asm__(
+	".text\n\t"
+	".p2align 4,,15\n\t"
+#if defined __ELF__
+	".type " CMANG(AsmCall) ", @function\n"
 #endif
+	CMANG(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  " CMANG(instructionPointers) ", %eax\n\t"
+	"call  *(%eax)\n\t"
+	"movl  (%edi), %eax\n\t"
+	"andl  " CMANG(callMask) ", %eax\n\t"
+	"ret\n"
+	"0:\n\t" // system call
+	"notl  %eax\n\t"
+	"pushl %ecx\n\t"
+	"pushl %edi\n\t" // opStack
+	"pushl %esi\n\t" // programStack
+	"pushl %eax\n\t" // syscallNum
+	"call  " CMANG(CallAsmCall) "\n\t"
+	"addl  $12, %esp\n\t"
+	"popl  %ecx\n\t"
+	"addl  $4, %edi\n\t"
+	"ret\n\t"
+#if defined __ELF__
+	".size " CMANG(AsmCall)", .-" CMANG(AsmCall)
+#endif
+);
 
+#endif
+
 static int	Constant4( void ) {
 	int		v;
 
@@ -1142,7 +1128,6 @@
 	int		programStack;
 	int		stackOnEntry;
 	byte	*image;
-	void	*entryPoint;
 	void	*opStack;
 	int		*oldInstructionPointers;
 
@@ -1181,45 +1166,38 @@
 	*(int *)&image[ programStack ] = -1;	// will terminate the loop on return
 
 	// off we go into generated code...
-	entryPoint = vm->codeBase;
 	opStack = &stack;
 
+	{
 #ifdef _MSC_VER
-	__asm  {
-		pushad
-		mov		esi, programStack;
-		mov		edi, opStack
-		call	entryPoint
-		mov		programStack, esi
-		mov		opStack, edi
-		popad
-	}
+		void *entryPoint = vm->codeBase;
+
+		__asm {
+			pushad
+			mov    esi, programStack
+			mov    edi, opStack
+			call   entryPoint
+			mov    programStack, esi
+			mov    opStack, edi
+			popad
+		}
 #else
-	{
-		static int memProgramStack;
-		static void *memOpStack;
-		static void *memEntryPoint;
+		/* 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;
 
-		memProgramStack	= programStack;
-		memOpStack      = opStack;     
-		memEntryPoint   = entryPoint;  
-		
-		__asm__("	pushal				\n" \
-				"	movl %0,%%esi		\n" \
-				"	movl %1,%%edi		\n" \
-				"	call *%2			\n" \
-				"	movl %%esi,%0		\n" \
-				"	movl %%edi,%1		\n" \
-				"	popal				\n" \
-				: "=m" (memProgramStack), "=m" (memOpStack) \
-				: "m" (memEntryPoint), "m" (memProgramStack), "m" (memOpStack) \
-				: "si", "di" \
+		__asm__ volatile(
+			"call *%6"
+			: "+S" (programStack), "+D" (opStack),
+			  "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+			: "mr" (vm->codeBase)
+			: "cc", "memory"
 		);
-
-		programStack = memProgramStack;
-		opStack      = memOpStack;
-	}
 #endif
+	}
 
 	if ( opStack != &stack[1] ) {
 		Com_Error( ERR_DROP, "opStack corrupted in compiled code" );




More information about the quake3-commits mailing list