* More robust x86 vm entrypoint/callback assembly (Tron)

This commit is contained in:
Tim Angus 2008-08-17 23:22:06 +00:00
parent d781a25157
commit 1af6eb9592

View file

@ -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
}
#else
{
static int memProgramStack;
static void *memOpStack;
static void *memEntryPoint;
#ifdef _MSC_VER
void *entryPoint = vm->codeBase;
memProgramStack = programStack;
memOpStack = opStack;
memEntryPoint = entryPoint;
__asm {
pushad
mov esi, programStack
mov edi, opStack
call entryPoint
mov programStack, esi
mov opStack, edi
popad
}
#else
/* 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__(" 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" );