mirror of
https://github.com/UberGames/lilium-voyager.git
synced 2025-02-21 18:50:57 +00:00
* More robust x86 vm entrypoint/callback assembly (Tron)
This commit is contained in:
parent
d781a25157
commit
1af6eb9592
1 changed files with 74 additions and 96 deletions
|
@ -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 *buf = NULL;
|
||||||
static byte *jused = NULL;
|
static byte *jused = NULL;
|
||||||
static int compiledOfs = 0;
|
static int compiledOfs = 0;
|
||||||
|
@ -71,9 +70,6 @@ int _ftol( float );
|
||||||
static int ftolPtr = (int)_ftol;
|
static int ftolPtr = (int)_ftol;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void AsmCall( void );
|
|
||||||
static int asmCallPtr = (int)AsmCall;
|
|
||||||
|
|
||||||
#else // _MSC_VER
|
#else // _MSC_VER
|
||||||
|
|
||||||
#if defined( FTOL_PTR )
|
#if defined( FTOL_PTR )
|
||||||
|
@ -88,10 +84,11 @@ int qftol0F7F( void );
|
||||||
static int ftolPtr = (int)qftol0F7F;
|
static int ftolPtr = (int)qftol0F7F;
|
||||||
#endif // FTOL_PTR
|
#endif // FTOL_PTR
|
||||||
|
|
||||||
void doAsmCall( void );
|
|
||||||
static int asmCallPtr = (int)doAsmCall;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void AsmCall(void);
|
||||||
|
static void (*const asmCallPtr)(void) = AsmCall;
|
||||||
|
|
||||||
|
|
||||||
static int callMask = 0;
|
static int callMask = 0;
|
||||||
|
|
||||||
|
@ -124,7 +121,7 @@ vm_t* savedVM;
|
||||||
__asm {
|
__asm {
|
||||||
mov eax, dword ptr [edi]
|
mov eax, dword ptr [edi]
|
||||||
sub edi, 4
|
sub edi, 4
|
||||||
or eax,eax
|
test eax,eax
|
||||||
jl systemCall
|
jl systemCall
|
||||||
// calling another vm function
|
// calling another vm function
|
||||||
shl eax,2
|
shl eax,2
|
||||||
|
@ -137,8 +134,7 @@ systemCall:
|
||||||
|
|
||||||
// convert negative num to system call number
|
// convert negative num to system call number
|
||||||
// and store right before the first arg
|
// and store right before the first arg
|
||||||
neg eax
|
not eax
|
||||||
dec eax
|
|
||||||
|
|
||||||
push ebp
|
push ebp
|
||||||
mov ebp, esp
|
mov ebp, esp
|
||||||
|
@ -180,68 +176,58 @@ _asm {
|
||||||
#else //!_MSC_VER
|
#else //!_MSC_VER
|
||||||
|
|
||||||
#if defined(__MINGW32__) || defined(MACOS_X) // _ is prepended to compiled symbols
|
#if defined(__MINGW32__) || defined(MACOS_X) // _ is prepended to compiled symbols
|
||||||
#define CMANG(sym) "_"#sym
|
# define CMANG(sym) "_"#sym
|
||||||
#else
|
#else
|
||||||
#define CMANG(sym) #sym
|
# define CMANG(sym) #sym
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int callProgramStack;
|
static void __attribute__((cdecl, used)) CallAsmCall(int const syscallNum,
|
||||||
static int *callOpStack;
|
int const programStack, int* const opStack)
|
||||||
static int callSyscallNum;
|
|
||||||
|
|
||||||
void callAsmCall(void)
|
|
||||||
{
|
{
|
||||||
vm_t *savedVM;
|
vm_t *const vm = currentVM;
|
||||||
int *callOpStack2;
|
intptr_t *const data = (intptr_t*)(vm->dataBase + programStack + 4);
|
||||||
|
|
||||||
savedVM = currentVM;
|
|
||||||
callOpStack2 = callOpStack;
|
|
||||||
|
|
||||||
// save the stack to allow recursive VM entry
|
// save the stack to allow recursive VM entry
|
||||||
currentVM->programStack = callProgramStack - 4;
|
vm->programStack = programStack - 4;
|
||||||
*(int *)((byte *)currentVM->dataBase + callProgramStack + 4) = callSyscallNum;
|
*data = syscallNum;
|
||||||
//VM_LogSyscalls((int *)((byte *)currentVM->dataBase + callProgramStack + 4) );
|
opStack[1] = vm->systemCall(data);
|
||||||
*(callOpStack2+1) = currentVM->systemCall( (intptr_t *)((byte *)currentVM->dataBase + callProgramStack + 4) );
|
|
||||||
|
|
||||||
currentVM = savedVM;
|
currentVM = vm;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note the C space function AsmCall is never actually called, and is in fact
|
__asm__(
|
||||||
// arbitrarily named (though this is not true for the MSC version). When a vm
|
".text\n\t"
|
||||||
// makes a system call, control jumps straight to the doAsmCall label.
|
".p2align 4,,15\n\t"
|
||||||
void AsmCall( void ) {
|
#if defined __ELF__
|
||||||
__asm__( CMANG(doAsmCall) ": \n\t" \
|
".type " CMANG(AsmCall) ", @function\n"
|
||||||
" movl (%%edi),%%eax \n\t" \
|
#endif
|
||||||
" subl $4,%%edi \n\t" \
|
CMANG(AsmCall) ":\n\t"
|
||||||
" orl %%eax,%%eax \n\t" \
|
"movl (%edi), %eax\n\t"
|
||||||
" jl systemCall \n\t" \
|
"subl $4, %edi\n\t"
|
||||||
" shll $2,%%eax \n\t" \
|
"testl %eax, %eax\n\t"
|
||||||
" addl %3,%%eax \n\t" \
|
"jl 0f\n\t"
|
||||||
" call *(%%eax) \n\t" \
|
"shll $2, %eax\n\t"
|
||||||
" movl (%%edi),%%eax \n\t" \
|
"addl " CMANG(instructionPointers) ", %eax\n\t"
|
||||||
" andl " CMANG(callMask) ", %%eax \n\t" \
|
"call *(%eax)\n\t"
|
||||||
" jmp doret \n\t" \
|
"movl (%edi), %eax\n\t"
|
||||||
"systemCall: \n\t" \
|
"andl " CMANG(callMask) ", %eax\n\t"
|
||||||
" negl %%eax \n\t" \
|
"ret\n"
|
||||||
" decl %%eax \n\t" \
|
"0:\n\t" // system call
|
||||||
" movl %%eax,%0 \n\t" \
|
"notl %eax\n\t"
|
||||||
" movl %%esi,%1 \n\t" \
|
"pushl %ecx\n\t"
|
||||||
" movl %%edi,%2 \n\t" \
|
"pushl %edi\n\t" // opStack
|
||||||
" pushl %%ecx \n\t" \
|
"pushl %esi\n\t" // programStack
|
||||||
" pushl %%esi \n\t" \
|
"pushl %eax\n\t" // syscallNum
|
||||||
" pushl %%edi \n\t" \
|
"call " CMANG(CallAsmCall) "\n\t"
|
||||||
" call " CMANG(callAsmCall) " \n\t" \
|
"addl $12, %esp\n\t"
|
||||||
" popl %%edi \n\t" \
|
"popl %ecx\n\t"
|
||||||
" popl %%esi \n\t" \
|
"addl $4, %edi\n\t"
|
||||||
" popl %%ecx \n\t" \
|
"ret\n\t"
|
||||||
" addl $4,%%edi \n\t" \
|
#if defined __ELF__
|
||||||
"doret: \n\t" \
|
".size " CMANG(AsmCall)", .-" CMANG(AsmCall)
|
||||||
" ret \n\t" \
|
#endif
|
||||||
: "=rm" (callSyscallNum), "=rm" (callProgramStack), "=rm" (callOpStack) \
|
);
|
||||||
: "m" (instructionPointers) \
|
|
||||||
: "ax", "di", "si", "cx" \
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int Constant4( void ) {
|
static int Constant4( void ) {
|
||||||
|
@ -1142,7 +1128,6 @@ int VM_CallCompiled( vm_t *vm, int *args ) {
|
||||||
int programStack;
|
int programStack;
|
||||||
int stackOnEntry;
|
int stackOnEntry;
|
||||||
byte *image;
|
byte *image;
|
||||||
void *entryPoint;
|
|
||||||
void *opStack;
|
void *opStack;
|
||||||
int *oldInstructionPointers;
|
int *oldInstructionPointers;
|
||||||
|
|
||||||
|
@ -1181,45 +1166,38 @@ int VM_CallCompiled( vm_t *vm, int *args ) {
|
||||||
*(int *)&image[ programStack ] = -1; // will terminate the loop on return
|
*(int *)&image[ programStack ] = -1; // will terminate the loop on return
|
||||||
|
|
||||||
// off we go into generated code...
|
// off we go into generated code...
|
||||||
entryPoint = vm->codeBase;
|
|
||||||
opStack = &stack;
|
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;
|
#ifdef _MSC_VER
|
||||||
static void *memOpStack;
|
void *entryPoint = vm->codeBase;
|
||||||
static void *memEntryPoint;
|
|
||||||
|
|
||||||
memProgramStack = programStack;
|
__asm {
|
||||||
memOpStack = opStack;
|
pushad
|
||||||
memEntryPoint = entryPoint;
|
mov esi, programStack
|
||||||
|
mov edi, opStack
|
||||||
__asm__(" pushal \n" \
|
call entryPoint
|
||||||
" movl %0,%%esi \n" \
|
mov programStack, esi
|
||||||
" movl %1,%%edi \n" \
|
mov opStack, edi
|
||||||
" call *%2 \n" \
|
popad
|
||||||
" movl %%esi,%0 \n" \
|
}
|
||||||
" movl %%edi,%1 \n" \
|
#else
|
||||||
" popal \n" \
|
/* These registers are used as scratch registers and are destroyed after the
|
||||||
: "=m" (memProgramStack), "=m" (memOpStack) \
|
* call. Do not use clobber, so they can be used as input for the asm. */
|
||||||
: "m" (memEntryPoint), "m" (memProgramStack), "m" (memOpStack) \
|
unsigned eax;
|
||||||
: "si", "di" \
|
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
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if ( opStack != &stack[1] ) {
|
if ( opStack != &stack[1] ) {
|
||||||
Com_Error( ERR_DROP, "opStack corrupted in compiled code" );
|
Com_Error( ERR_DROP, "opStack corrupted in compiled code" );
|
||||||
|
|
Loading…
Reference in a new issue