aboutsummaryrefslogtreecommitdiffstats
path: root/code/qcommon/vm_x86.c
diff options
context:
space:
mode:
authortma <tma@edf5b092-35ff-0310-97b2-ce42778d08ea>2008-08-17 23:22:06 +0000
committertma <tma@edf5b092-35ff-0310-97b2-ce42778d08ea>2008-08-17 23:22:06 +0000
commit6d6a8ce9e2c428d60f8498f4d702231f4e37dba8 (patch)
tree5b493dde8013a936b44fac44263c48dfe5b0be48 /code/qcommon/vm_x86.c
parent3d1d011c5dc4fa5815b36c39f174b5d1cc930a2a (diff)
downloadioquake3-aero-6d6a8ce9e2c428d60f8498f4d702231f4e37dba8.tar.gz
ioquake3-aero-6d6a8ce9e2c428d60f8498f4d702231f4e37dba8.zip
* More robust x86 vm entrypoint/callback assembly (Tron)
git-svn-id: svn://svn.icculus.org/quake3/trunk@1448 edf5b092-35ff-0310-97b2-ce42778d08ea
Diffstat (limited to 'code/qcommon/vm_x86.c')
-rw-r--r--code/qcommon/vm_x86.c170
1 files changed, 74 insertions, 96 deletions
diff --git a/code/qcommon/vm_x86.c b/code/qcommon/vm_x86.c
index 04f5496..8d1521b 100644
--- a/code/qcommon/vm_x86.c
+++ b/code/qcommon/vm_x86.c
@@ -53,7 +53,6 @@ static void VM_Destroy_Compiled(vm_t* self);
*/
-// 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 @@ int _ftol( float );
static int ftolPtr = (int)_ftol;
#endif
-void AsmCall( void );
-static int asmCallPtr = (int)AsmCall;
-
#else // _MSC_VER
#if defined( FTOL_PTR )
@@ -88,10 +84,11 @@ int qftol0F7F( void );
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;
@@ -124,7 +121,7 @@ vm_t* savedVM;
__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 @@ systemCall:
// 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,68 +176,58 @@ _asm {
#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;
-
- savedVM = currentVM;
- callOpStack2 = callOpStack;
+ vm_t *const vm = currentVM;
+ intptr_t *const data = (intptr_t*)(vm->dataBase + programStack + 4);
// 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 ) {
@@ -1142,7 +1128,6 @@ int VM_CallCompiled( vm_t *vm, int *args ) {
int programStack;
int stackOnEntry;
byte *image;
- void *entryPoint;
void *opStack;
int *oldInstructionPointers;
@@ -1181,45 +1166,38 @@ int VM_CallCompiled( vm_t *vm, int *args ) {
*(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;
-
- 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" \
+ /* 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;
+
+ __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" );