From bdaff032dd15ebe90236c4c23baf9dcf294496cd Mon Sep 17 00:00:00 2001 From: Thilo Schulz Date: Mon, 6 Jun 2011 14:29:45 +0000 Subject: - Use EmitCallDoSyscall() to call the jump violations function which guarantees 16-byte stack alignment - Add x64 code for MSVC _asm() blocks, not tested yet. --- src/qcommon/vm_x86.c | 131 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 89 insertions(+), 42 deletions(-) diff --git a/src/qcommon/vm_x86.c b/src/qcommon/vm_x86.c index 0f806e5f..e609bc1e 100644 --- a/src/qcommon/vm_x86.c +++ b/src/qcommon/vm_x86.c @@ -106,7 +106,8 @@ typedef enum typedef enum { - VM_BLOCK_COPY = 0, + VM_JMP_VIOLATION = 0, + VM_BLOCK_COPY = 1 } ESysCallType; static ELastCommand LastCommand; @@ -393,17 +394,20 @@ void EmitMovEDXStack(vm_t *vm, int andit) #define SET_JMPOFS(x) do { buf[(x)] = compiledOfs - ((x) + 1); } while(0) + +/* +================= +ErrJump +Error handler for jump/call to invalid instruction number +================= +*/ + static void ErrJump(void) { Com_Error(ERR_DROP, "program tried to execute code outside VM"); exit(1); } -#define ERRJUMP() \ - EmitRexString(0x48, "B8"); \ - EmitPtr(ErrJump); \ - EmitRexString(0x48, "FF D0") - /* ================= DoBlockCopy @@ -446,11 +450,16 @@ static void DoSyscall(void) #ifdef _MSC_VER __asm { - mov dword ptr syscallNum, eax - mov dword ptr programStack, esi - mov dword ptr opStackBase, edi - mov dword ptr opStackOfs, ebx - mov dword ptr arg, ecx + mov dword ptr syscallNum, eax + mov dword ptr programStack, esi + mov dword ptr opStackOfs, ebx +#ifdef idx64 + mov qword ptr opStackBase, rdi + mov qword ptr arg, rcx +#else + mov dword ptr opStackBase, edi + mov dword ptr arg, ecx +#endif } #else __asm__ volatile( @@ -492,6 +501,9 @@ static void DoSyscall(void) { switch(syscallNum) { + case VM_JMP_VIOLATION: + ErrJump(); + break; case VM_BLOCK_COPY: if(opStackOfs < 1) Com_Error(ERR_DROP, "VM_BLOCK_COPY failed due to corrupted opStack"); @@ -505,6 +517,19 @@ static void DoSyscall(void) } } +/* +================= +EmitCallRel +Relative call to vm->codeBase + callOfs +================= +*/ + +void EmitCallRel(vm_t *vm, int callOfs) +{ + EmitString("E8"); // call 0x12345678 + Emit4(callOfs - compiledOfs - 4); +} + /* ================= EmitCallDoSyscall @@ -533,7 +558,7 @@ int EmitCallDoSyscall(vm_t *vm) EmitRexString(0x48, "89 E5"); // mov ebp, esp EmitRexString(0x48, "83 E4 F0"); // and esp, 0xFFFFFFF0 - // call the syscall wrapper function + // call the syscall wrapper function DoSyscall() EmitString("FF D2"); // call edx @@ -556,15 +581,17 @@ int EmitCallDoSyscall(vm_t *vm) /* ================= -EmitCallRel -Relative call to vm->codeBase + callOfs +EmitCallErrJump +Emit the code that triggers execution of the jump violation handler ================= */ -void EmitCallRel(vm_t *vm, int callOfs) +static void EmitCallErrJump(vm_t *vm, int sysCallOfs) { - EmitString("E8"); // call 0x12345678 - Emit4(callOfs - compiledOfs - 4); + EmitString("B8"); // mov eax, 0x12345678 + Emit4(VM_JMP_VIOLATION); + + EmitCallRel(vm, sysCallOfs); } /* @@ -583,7 +610,7 @@ int EmitCallProcedure(vm_t *vm, int sysCallOfs) STACK_POP(1); // sub bl, 1 EmitString("85 C0"); // test eax, eax - // Jump to syscall code + // Jump to syscall code, 1 byte offset should suffice EmitString("7C"); // jl systemCall jmpSystemCall = compiledOfs++; @@ -607,7 +634,7 @@ int EmitCallProcedure(vm_t *vm, int sysCallOfs) // badAddr: SET_JMPOFS(jmpBadAddr); - ERRJUMP(); + EmitCallErrJump(vm, sysCallOfs); /************ System Call ************/ @@ -658,7 +685,7 @@ void EmitCallIns(vm_t *vm, int cdest) EmitString("E8"); // call 0x12345678 // we only know all the jump addresses in the third pass - if(pass) + if(pass == 2) Emit4(vm->instructionPointers[cdest] - compiledOfs - 4); else compiledOfs += 4; @@ -1082,7 +1109,7 @@ void VM_Compile(vm_t *vm, vmHeader_t *header) int maxLength; int v; int i; - int callProcOfsSyscall, callProcOfs; + int callProcOfsSyscall, callProcOfs, callDoSyscallOfs; jusedSize = header->instructionCount + 2; @@ -1109,8 +1136,10 @@ void VM_Compile(vm_t *vm, vmHeader_t *header) // Start buffer with x86-VM specific procedures compiledOfs = 0; + + callDoSyscallOfs = compiledOfs; callProcOfs = EmitCallDoSyscall(vm); - callProcOfsSyscall = EmitCallProcedure(vm, 0); + callProcOfsSyscall = EmitCallProcedure(vm, callDoSyscallOfs); vm->entryOfs = compiledOfs; for(pass=0; pass < 3; pass++) { @@ -1623,7 +1652,7 @@ void VM_Compile(vm_t *vm, vmHeader_t *header) EmitString("B9"); // mov ecx, 0x12345678 Emit4(Constant4()); - EmitCallRel(vm, 0); + EmitCallRel(vm, callDoSyscallOfs); EmitCommand(LAST_COMMAND_SUB_BL_2); // sub bl, 2 break; @@ -1641,7 +1670,7 @@ void VM_Compile(vm_t *vm, vmHeader_t *header) EmitString("FF 24 85"); // jmp dword ptr [instructionPointers + eax * 4] Emit4((intptr_t) vm->instructionPointers); #endif - ERRJUMP(); + EmitCallErrJump(vm, callDoSyscallOfs); break; default: VMFREE_BUFFERS(); @@ -1721,7 +1750,7 @@ int VM_CallCompiled(vm_t *vm, int *args) int stack[OPSTACK_SIZE + 7]; void *entryPoint; int programCounter; - intptr_t programStack, stackOnEntry; + int programStack, stackOnEntry; byte *image; int *opStack, *opStackOnEntry; int opStackOfs; @@ -1763,24 +1792,42 @@ int VM_CallCompiled(vm_t *vm, int *args) #ifdef _MSC_VER __asm { -#ifndef idx64 - pushad -#endif - mov esi, programStack - mov edi, opStack - mov ebx, opStackOfs #ifdef idx64 -#warning look up calling conventions and push/pop if necessary - mov r8, vm->instructionPointers - mov r9, vm->dataBase -#endif - call entryPoint - mov opStackOfs, ebx - mov opStack, edi - mov programStack, esi -#ifndef idx64 + // non-volatile registers according to x64 calling convention + push rsi + push rdi + push rbx + + mov esi, dword ptr programStack + mov rdi, qword ptr opStack + mov ebx, dword ptr opStackOfs + mov r8, qword ptr vm->instructionPointers + mov r9, qword ptr vm->dataBase + + call entryPoint + + mov dword ptr opStackOfs, ebx + mov qword ptr opStack, rdi + mov dword ptr programStack, esi + + pop rbx + pop rdi + pop rsi +#else + pushad + + mov esi, dword ptr programStack + mov edi, dword ptr opStack + mov ebx, dword ptr opStackOfs + + call entryPoint + + mov dword ptr opStackOfs, ebx + mov dword ptr opStack, edi + mov dword ptr programStack, esi + popad -#endif +#endif } #elif defined(idx64) __asm__ volatile( @@ -1798,7 +1845,7 @@ int VM_CallCompiled(vm_t *vm, int *args) "pop %%r15\r\n" : "+S" (programStack), "+D" (opStack), "+b" (opStackOfs) : "g" (vm->instructionPointers), "g" (vm->dataBase), "g" (entryPoint) - : "cc", "memory", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%xmm0" + : "cc", "memory", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11" ); #else __asm__ volatile( -- cgit