From 6d6a8ce9e2c428d60f8498f4d702231f4e37dba8 Mon Sep 17 00:00:00 2001 From: tma Date: Sun, 17 Aug 2008 23:22:06 +0000 Subject: * More robust x86 vm entrypoint/callback assembly (Tron) git-svn-id: svn://svn.icculus.org/quake3/trunk@1448 edf5b092-35ff-0310-97b2-ce42778d08ea --- code/qcommon/vm_x86.c | 170 ++++++++++++++++++++++---------------------------- 1 file changed, 74 insertions(+), 96 deletions(-) (limited to 'code/qcommon') 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" ); -- cgit v1.2.3