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