📄 vm_x86.c
字号:
EmitString( "72 06" ); // jnae +6
EmitString( "FF 25" ); // jmp [0x12345678]
v = Constant4();
jused[v] = 1;
Emit4( (int)vm->instructionPointers + v*4 );
break;
case OP_EQF:
EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
EmitString( "D9 47 04" ); // fld dword ptr [edi+4]
EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8]
EmitString( "DF E0" ); // fnstsw ax
EmitString( "F6 C4 40" ); // test ah,0x40
EmitString( "74 06" ); // je +6
EmitString( "FF 25" ); // jmp [0x12345678]
v = Constant4();
jused[v] = 1;
Emit4( (int)vm->instructionPointers + v*4 );
break;
case OP_NEF:
EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
EmitString( "D9 47 04" ); // fld dword ptr [edi+4]
EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8]
EmitString( "DF E0" ); // fnstsw ax
EmitString( "F6 C4 40" ); // test ah,0x40
EmitString( "75 06" ); // jne +6
EmitString( "FF 25" ); // jmp [0x12345678]
v = Constant4();
jused[v] = 1;
Emit4( (int)vm->instructionPointers + v*4 );
break;
case OP_LTF:
EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
EmitString( "D9 47 04" ); // fld dword ptr [edi+4]
EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8]
EmitString( "DF E0" ); // fnstsw ax
EmitString( "F6 C4 01" ); // test ah,0x01
EmitString( "74 06" ); // je +6
EmitString( "FF 25" ); // jmp [0x12345678]
v = Constant4();
jused[v] = 1;
Emit4( (int)vm->instructionPointers + v*4 );
break;
case OP_LEF:
EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
EmitString( "D9 47 04" ); // fld dword ptr [edi+4]
EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8]
EmitString( "DF E0" ); // fnstsw ax
EmitString( "F6 C4 41" ); // test ah,0x41
EmitString( "74 06" ); // je +6
EmitString( "FF 25" ); // jmp [0x12345678]
v = Constant4();
jused[v] = 1;
Emit4( (int)vm->instructionPointers + v*4 );
break;
case OP_GTF:
EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
EmitString( "D9 47 04" ); // fld dword ptr [edi+4]
EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8]
EmitString( "DF E0" ); // fnstsw ax
EmitString( "F6 C4 41" ); // test ah,0x41
EmitString( "75 06" ); // jne +6
EmitString( "FF 25" ); // jmp [0x12345678]
v = Constant4();
jused[v] = 1;
Emit4( (int)vm->instructionPointers + v*4 );
break;
case OP_GEF:
EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
EmitString( "D9 47 04" ); // fld dword ptr [edi+4]
EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8]
EmitString( "DF E0" ); // fnstsw ax
EmitString( "F6 C4 01" ); // test ah,0x01
EmitString( "75 06" ); // jne +6
EmitString( "FF 25" ); // jmp [0x12345678]
v = Constant4();
jused[v] = 1;
Emit4( (int)vm->instructionPointers + v*4 );
break;
case OP_NEGI:
EmitString( "F7 1F" ); // neg dword ptr [edi]
break;
case OP_ADD:
EmitMovEAXEDI(vm); // mov eax, dword ptr [edi]
EmitString( "01 47 FC" ); // add dword ptr [edi-4],eax
EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
break;
case OP_SUB:
EmitMovEAXEDI(vm); // mov eax, dword ptr [edi]
EmitString( "29 47 FC" ); // sub dword ptr [edi-4],eax
EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
break;
case OP_DIVI:
EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
EmitString( "99" ); // cdq
EmitString( "F7 3F" ); // idiv dword ptr [edi]
EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax
EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
break;
case OP_DIVU:
EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
EmitString( "33 D2" ); // xor edx, edx
EmitString( "F7 37" ); // div dword ptr [edi]
EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax
EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
break;
case OP_MODI:
EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
EmitString( "99" ); // cdq
EmitString( "F7 3F" ); // idiv dword ptr [edi]
EmitString( "89 57 FC" ); // mov dword ptr [edi-4],edx
EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
break;
case OP_MODU:
EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
EmitString( "33 D2" ); // xor edx, edx
EmitString( "F7 37" ); // div dword ptr [edi]
EmitString( "89 57 FC" ); // mov dword ptr [edi-4],edx
EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
break;
case OP_MULI:
EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
EmitString( "F7 2F" ); // imul dword ptr [edi]
EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax
EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
break;
case OP_MULU:
EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
EmitString( "F7 27" ); // mul dword ptr [edi]
EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax
EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
break;
case OP_BAND:
EmitMovEAXEDI(vm); // mov eax, dword ptr [edi]
EmitString( "21 47 FC" ); // and dword ptr [edi-4],eax
EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
break;
case OP_BOR:
EmitMovEAXEDI(vm); // mov eax, dword ptr [edi]
EmitString( "09 47 FC" ); // or dword ptr [edi-4],eax
EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
break;
case OP_BXOR:
EmitMovEAXEDI(vm); // mov eax, dword ptr [edi]
EmitString( "31 47 FC" ); // xor dword ptr [edi-4],eax
EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
break;
case OP_BCOM:
EmitString( "F7 17" ); // not dword ptr [edi]
break;
case OP_LSH:
EmitString( "8B 0F" ); // mov ecx, dword ptr [edi]
EmitString( "D3 67 FC" ); // shl dword ptr [edi-4], cl
EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
break;
case OP_RSHI:
EmitString( "8B 0F" ); // mov ecx, dword ptr [edi]
EmitString( "D3 7F FC" ); // sar dword ptr [edi-4], cl
EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
break;
case OP_RSHU:
EmitString( "8B 0F" ); // mov ecx, dword ptr [edi]
EmitString( "D3 6F FC" ); // shr dword ptr [edi-4], cl
EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
break;
case OP_NEGF:
EmitString( "D9 07" ); // fld dword ptr [edi]
EmitString( "D9 E0" ); // fchs
EmitString( "D9 1F" ); // fstp dword ptr [edi]
break;
case OP_ADDF:
EmitString( "D9 47 FC" ); // fld dword ptr [edi-4]
EmitString( "D8 07" ); // fadd dword ptr [edi]
EmitString( "D9 5F FC" ); // fstp dword ptr [edi-4]
EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
break;
case OP_SUBF:
EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
EmitString( "D9 07" ); // fld dword ptr [edi]
EmitString( "D8 67 04" ); // fsub dword ptr [edi+4]
EmitString( "D9 1F" ); // fstp dword ptr [edi]
break;
case OP_DIVF:
EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
EmitString( "D9 07" ); // fld dword ptr [edi]
EmitString( "D8 77 04" ); // fdiv dword ptr [edi+4]
EmitString( "D9 1F" ); // fstp dword ptr [edi]
break;
case OP_MULF:
EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
EmitString( "D9 07" ); // fld dword ptr [edi]
EmitString( "D8 4f 04" ); // fmul dword ptr [edi+4]
EmitString( "D9 1F" ); // fstp dword ptr [edi]
break;
case OP_CVIF:
EmitString( "DB 07" ); // fild dword ptr [edi]
EmitString( "D9 1F" ); // fstp dword ptr [edi]
break;
case OP_CVFI:
#ifndef FTOL_PTR // WHENHELLISFROZENOVER // bk001213 - was used in 1.17
// not IEEE complient, but simple and fast
EmitString( "D9 07" ); // fld dword ptr [edi]
EmitString( "DB 1F" ); // fistp dword ptr [edi]
#else // FTOL_PTR
// call the library conversion function
EmitString( "D9 07" ); // fld dword ptr [edi]
EmitString( "FF 15" ); // call ftolPtr
Emit4( (int)&ftolPtr );
EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
#endif
break;
case OP_SEX8:
EmitString( "0F BE 07" ); // movsx eax, byte ptr [edi]
EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
break;
case OP_SEX16:
EmitString( "0F BF 07" ); // movsx eax, word ptr [edi]
EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
break;
case OP_BLOCK_COPY:
// FIXME: range check
EmitString( "56" ); // push esi
EmitString( "57" ); // push edi
EmitString( "8B 37" ); // mov esi,[edi]
EmitString( "8B 7F FC" ); // mov edi,[edi-4]
EmitString( "B9" ); // mov ecx,0x12345678
Emit4( Constant4() >> 2 );
EmitString( "B8" ); // mov eax, datamask
Emit4( vm->dataMask );
EmitString( "BB" ); // mov ebx, database
Emit4( (int)vm->dataBase );
EmitString( "23 F0" ); // and esi, eax
EmitString( "03 F3" ); // add esi, ebx
EmitString( "23 F8" ); // and edi, eax
EmitString( "03 FB" ); // add edi, ebx
EmitString( "F3 A5" ); // rep movsd
EmitString( "5F" ); // pop edi
EmitString( "5E" ); // pop esi
EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
break;
case OP_JUMP:
EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
EmitString( "8B 47 04" ); // mov eax,dword ptr [edi+4]
// FIXME: range check
EmitString( "FF 24 85" ); // jmp dword ptr [instructionPointers + eax * 4]
Emit4( (int)vm->instructionPointers );
break;
default:
Com_Error( ERR_DROP, "VM_CompileX86: bad opcode %i at offset %i", op, pc );
}
pop0 = pop1;
pop1 = op;
}
}
// copy to an exact size buffer on the hunk
vm->codeLength = compiledOfs;
vm->codeBase = Hunk_Alloc( compiledOfs, h_low );
Com_Memcpy( vm->codeBase, buf, compiledOfs );
Z_Free( buf );
Z_Free( jused );
Com_Printf( "VM file %s compiled to %i bytes of code\n", vm->name, compiledOfs );
// offset all the instruction pointers for the new location
for ( i = 0 ; i < header->instructionCount ; i++ ) {
vm->instructionPointers[i] += (int)vm->codeBase;
}
#if 0 // ndef _WIN32
// Must make the newly generated code executable
{
int r;
unsigned long addr;
int psize = getpagesize();
addr = ((int)vm->codeBase & ~(psize-1)) - psize;
r = mprotect((char*)addr, vm->codeLength + (int)vm->codeBase - addr + psize,
PROT_READ | PROT_WRITE | PROT_EXEC );
if (r < 0)
Com_Error( ERR_FATAL, "mprotect failed to change PROT_EXEC" );
}
#endif
}
/*
==============
VM_CallCompiled
This function is called directly by the generated code
==============
*/
#ifndef DLL_ONLY // bk010215 - for DLL_ONLY dedicated servers/builds w/o VM
int VM_CallCompiled( vm_t *vm, int *args ) {
int stack[1024];
int programCounter;
int programStack;
int stackOnEntry;
byte *image;
void *entryPoint;
void *opStack;
int *oldInstructionPointers;
oldInstructionPointers = instructionPointers;
currentVM = vm;
instructionPointers = vm->instructionPointers;
// interpret the code
vm->currentlyInterpreting = qtrue;
callMask = vm->dataMask;
// we might be called recursively, so this might not be the very top
programStack = vm->programStack;
stackOnEntry = programStack;
// set up the stack frame
image = vm->dataBase;
programCounter = 0;
programStack -= 48;
*(int *)&image[ programStack + 44] = args[9];
*(int *)&image[ programStack + 40] = args[8];
*(int *)&image[ programStack + 36] = args[7];
*(int *)&image[ programStack + 32] = args[6];
*(int *)&image[ programStack + 28] = args[5];
*(int *)&image[ programStack + 24] = args[4];
*(int *)&image[ programStack + 20] = args[3];
*(int *)&image[ programStack + 16] = args[2];
*(int *)&image[ programStack + 12] = args[1];
*(int *)&image[ programStack + 8 ] = args[0];
*(int *)&image[ programStack + 4 ] = 0; // return stack
*(int *)&image[ programStack ] = -1; // will terminate the loop on return
// off we go into generated code...
entryPoint = vm->codeBase;
opStack = &stack;
#ifdef _WIN32
__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 \r\n" \
" movl %0,%%esi \r\n" \
" movl %1,%%edi \r\n" \
" call *%2 \r\n" \
" movl %%esi,%0 \r\n" \
" movl %%edi,%1 \r\n" \
" popal \r\n" \
: "=m" (memProgramStack), "=m" (memOpStack) \
: "m" (memEntryPoint), "0" (memProgramStack), "1" (memOpStack) \
: "si", "di" \
);
programStack = memProgramStack;
opStack = memOpStack;
}
#endif
if ( opStack != &stack[1] ) {
Com_Error( ERR_DROP, "opStack corrupted in compiled code" );
}
if ( programStack != stackOnEntry - 48 ) {
Com_Error( ERR_DROP, "programStack corrupted in compiled code" );
}
vm->programStack = stackOnEntry;
// in case we were recursively called by another vm
instructionPointers = oldInstructionPointers;
return *(int *)opStack;
}
#endif // !DLL_ONLY
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -