Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

vm_x86.c (35361B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 // vm_x86.c -- load time compiler and execution environment for x86
     23 
     24 #include "vm_local.h"
     25 
     26 #ifdef __FreeBSD__ // rb0101023
     27 #include <sys/types.h>
     28 #endif
     29 
     30 #ifndef _WIN32
     31 #include <sys/mman.h> // for PROT_ stuff
     32 #endif
     33 
     34 /*
     35 
     36   eax	scratch
     37   ebx	scratch
     38   ecx	scratch (required for shifts)
     39   edx	scratch (required for divisions)
     40   esi	program stack
     41   edi	opstack
     42 
     43 */
     44 
     45 // TTimo: initialised the statics, this fixes a crash when entering a compiled VM 
     46 static	byte	*buf = NULL;
     47 static	byte	*jused = NULL;
     48 static	int		compiledOfs = 0;
     49 static	byte	*code = NULL;
     50 static	int		pc = 0;
     51 
     52 static	int		*instructionPointers = NULL;
     53 
     54 #define FTOL_PTR
     55 
     56 #ifdef _WIN32
     57 
     58 #if defined( FTOL_PTR )
     59 int _ftol( float );
     60 static	int		ftolPtr = (int)_ftol;
     61 #endif
     62 
     63 void AsmCall( void );
     64 static	int		asmCallPtr = (int)AsmCall;
     65 
     66 #else // _WIN32
     67 
     68 #if defined( FTOL_PTR )
     69 // bk001213 - BEWARE: does not work! UI menu etc. broken - stack!
     70 // bk001119 - added: int gftol( float x ) { return (int)x; }
     71 
     72 int qftol( void );     // bk001213 - label, see unix/ftol.nasm
     73 int qftol027F( void ); // bk001215 - fixed FPU control variants
     74 int qftol037F( void );
     75 int qftol0E7F( void ); // bk010102 - fixed bogus bits (duh)
     76 int qftol0F7F( void );
     77 
     78 
     79 static	int		ftolPtr = (int)qftol0F7F;
     80 #endif // FTOL_PTR
     81 
     82 void doAsmCall( void );
     83 static	int		asmCallPtr = (int)doAsmCall;
     84 #endif // !_WIN32
     85 
     86 
     87 static	int		callMask = 0; // bk001213 - init
     88 
     89 static	int	instruction, pass;
     90 static	int	lastConst = 0;
     91 static	int	oc0, oc1, pop0, pop1;
     92 
     93 typedef enum 
     94 {
     95 	LAST_COMMAND_NONE	= 0,
     96 	LAST_COMMAND_MOV_EDI_EAX,
     97 	LAST_COMMAND_SUB_DI_4,
     98 	LAST_COMMAND_SUB_DI_8,
     99 } ELastCommand;
    100 
    101 static	ELastCommand	LastCommand;
    102 
    103 /*
    104 =================
    105 AsmCall
    106 =================
    107 */
    108 #ifdef _WIN32
    109 __declspec( naked ) void AsmCall( void ) {
    110 int		programStack;
    111 int		*opStack;
    112 int		syscallNum;
    113 vm_t*	savedVM;
    114 
    115 __asm {
    116 	mov		eax, dword ptr [edi]
    117 	sub		edi, 4
    118 	or		eax,eax
    119 	jl		systemCall
    120 	// calling another vm function
    121 	shl		eax,2
    122 	add		eax, dword ptr [instructionPointers]
    123 	call	dword ptr [eax]
    124 	mov		eax, dword ptr [edi]
    125 	and		eax, [callMask]
    126 	ret
    127 systemCall:
    128 
    129 	// convert negative num to system call number
    130 	// and store right before the first arg
    131 	neg		eax
    132 	dec		eax
    133 
    134 	push    ebp
    135 	mov     ebp, esp
    136 	sub     esp, __LOCAL_SIZE
    137 
    138 	mov		dword ptr syscallNum, eax	// so C code can get at it
    139 	mov		dword ptr programStack, esi	// so C code can get at it
    140 	mov		dword ptr opStack, edi
    141 
    142 	push	ecx
    143 	push	esi							// we may call recursively, so the
    144 	push	edi							// statics aren't guaranteed to be around
    145 }
    146 
    147 	savedVM = currentVM;
    148 
    149 	// save the stack to allow recursive VM entry
    150 	currentVM->programStack = programStack - 4;
    151 	*(int *)((byte *)currentVM->dataBase + programStack + 4) = syscallNum;
    152 //VM_LogSyscalls(  (int *)((byte *)currentVM->dataBase + programStack + 4) );
    153 	*(opStack+1) = currentVM->systemCall( (int *)((byte *)currentVM->dataBase + programStack + 4) );
    154 
    155 	currentVM = savedVM;
    156 
    157 _asm {
    158 	pop		edi
    159 	pop		esi
    160 	pop		ecx
    161 	add		edi, 4		// we added the return value
    162 
    163 	mov     esp, ebp
    164 	pop     ebp
    165 
    166 	ret
    167 }
    168 
    169 }
    170 
    171 #else //!_WIN32
    172 
    173 static	int		callProgramStack;
    174 static	int		*callOpStack;
    175 static	int		callSyscallNum;
    176 
    177 void callAsmCall(void)
    178 {
    179 	vm_t	*savedVM;
    180 	int		*callOpStack2;
    181 
    182 	savedVM = currentVM;
    183 	callOpStack2 = callOpStack;
    184 
    185 	// save the stack to allow recursive VM entry
    186 	currentVM->programStack = callProgramStack - 4;
    187 	*(int *)((byte *)currentVM->dataBase + callProgramStack + 4) = callSyscallNum;
    188 //VM_LogSyscalls(  (int *)((byte *)currentVM->dataBase + programStack + 4) );
    189 	*(callOpStack2+1) = currentVM->systemCall( (int *)((byte *)currentVM->dataBase + callProgramStack + 4) );
    190 
    191  	currentVM = savedVM;
    192 }
    193 
    194 void AsmCall( void ) {
    195 	__asm__("doAsmCall:      			\n\t" \
    196 			"	movl (%%edi),%%eax			\n\t" \
    197 			"	subl $4,%%edi				\n\t" \
    198 			"   orl %%eax,%%eax				\n\t" \
    199 			"	jl systemCall				\n\t" \
    200 			"	shll $2,%%eax				\n\t" \
    201 			"	addl %3,%%eax				\n\t" \
    202 			"	call *(%%eax)				\n\t" \
    203 		  " movl (%%edi),%%eax   \n\t" \
    204 	    " andl callMask, %%eax \n\t" \
    205 			"	jmp doret					   \n\t" \
    206 			"systemCall:					\n\t" \
    207 			"	negl %%eax					\n\t" \
    208 			"	decl %%eax					\n\t" \
    209 			"	movl %%eax,%0				\n\t" \
    210 			"	movl %%esi,%1				\n\t" \
    211 			"	movl %%edi,%2				\n\t" \
    212 			"	pushl %%ecx					\n\t" \
    213 			"	pushl %%esi					\n\t" \
    214 			"	pushl %%edi					\n\t" \
    215 			"	call callAsmCall			\n\t" \
    216 			"	popl %%edi					\n\t" \
    217 			"	popl %%esi					\n\t" \
    218 			"	popl %%ecx					\n\t" \
    219 			"	addl $4,%%edi				\n\t" \
    220 			"doret:							\n\t" \
    221 			"	ret							\n\t" \
    222 			: "=rm" (callSyscallNum), "=rm" (callProgramStack), "=rm" (callOpStack) \
    223 			: "rm" (instructionPointers) \
    224 			: "ax", "di", "si", "cx" \
    225 	);
    226 }
    227 #endif
    228 
    229 static int	Constant4( void ) {
    230 	int		v;
    231 
    232 	v = code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24);
    233 	pc += 4;
    234 	return v;
    235 }
    236 
    237 static int	Constant1( void ) {
    238 	int		v;
    239 
    240 	v = code[pc];
    241 	pc += 1;
    242 	return v;
    243 }
    244 
    245 static void Emit1( int v ) 
    246 {
    247 	buf[ compiledOfs ] = v;
    248 	compiledOfs++;
    249 
    250 	LastCommand = LAST_COMMAND_NONE;
    251 }
    252 
    253 #if 0
    254 static void Emit2( int v ) {
    255 	Emit1( v & 255 );
    256 	Emit1( ( v >> 8 ) & 255 );
    257 }
    258 #endif
    259 
    260 static void Emit4( int v ) {
    261 	Emit1( v & 255 );
    262 	Emit1( ( v >> 8 ) & 255 );
    263 	Emit1( ( v >> 16 ) & 255 );
    264 	Emit1( ( v >> 24 ) & 255 );
    265 }
    266 
    267 static int Hex( int c ) {
    268 	if ( c >= 'a' && c <= 'f' ) {
    269 		return 10 + c - 'a';
    270 	}
    271 	if ( c >= 'A' && c <= 'F' ) {
    272 		return 10 + c - 'A';
    273 	}
    274 	if ( c >= '0' && c <= '9' ) {
    275 		return c - '0';
    276 	}
    277 
    278 	Com_Error( ERR_DROP, "Hex: bad char '%c'", c );
    279 
    280 	return 0;
    281 }
    282 static void EmitString( const char *string ) {
    283 	int		c1, c2;
    284 	int		v;
    285 
    286 	while ( 1 ) {
    287 		c1 = string[0];
    288 		c2 = string[1];
    289 
    290 		v = ( Hex( c1 ) << 4 ) | Hex( c2 );
    291 		Emit1( v );
    292 
    293 		if ( !string[2] ) {
    294 			break;
    295 		}
    296 		string += 3;
    297 	}
    298 }
    299 
    300 
    301 
    302 static void EmitCommand(ELastCommand command)
    303 {
    304 	switch(command)
    305 	{
    306 		case LAST_COMMAND_MOV_EDI_EAX:
    307 			EmitString( "89 07" );		// mov dword ptr [edi], eax
    308 			break;
    309 
    310 		case LAST_COMMAND_SUB_DI_4:
    311 			EmitString( "83 EF 04" );	// sub edi, 4
    312 			break;
    313 
    314 		case LAST_COMMAND_SUB_DI_8:
    315 			EmitString( "83 EF 08" );	// sub edi, 8
    316 			break;
    317 		default:
    318 			break;
    319 	}
    320 	LastCommand = command;
    321 }
    322 
    323 static void EmitAddEDI4(vm_t *vm) {
    324 	if (LastCommand == LAST_COMMAND_SUB_DI_4 && jused[instruction-1] == 0) 
    325 	{		// sub di,4
    326 		compiledOfs -= 3;
    327 		vm->instructionPointers[ instruction-1 ] = compiledOfs;
    328 		return;
    329 	}
    330 	if (LastCommand == LAST_COMMAND_SUB_DI_8 && jused[instruction-1] == 0) 
    331 	{		// sub di,8
    332 		compiledOfs -= 3;
    333 		vm->instructionPointers[ instruction-1 ] = compiledOfs;
    334 		EmitString( "83 EF 04" );	//	sub edi,4
    335 		return;
    336 	}
    337 	EmitString( "83 C7 04" );	//	add edi,4
    338 }
    339 
    340 static void EmitMovEAXEDI(vm_t *vm) {
    341 	if (LastCommand == LAST_COMMAND_MOV_EDI_EAX) 
    342 	{	// mov [edi], eax
    343 		compiledOfs -= 2;
    344 		vm->instructionPointers[ instruction-1 ] = compiledOfs;
    345 		return;
    346 	}
    347 	if (pop1 == OP_DIVI || pop1 == OP_DIVU || pop1 == OP_MULI || pop1 == OP_MULU ||
    348 		pop1 == OP_STORE4 || pop1 == OP_STORE2 || pop1 == OP_STORE1 ) 
    349 	{	
    350 		return;
    351 	}
    352 	if (pop1 == OP_CONST && buf[compiledOfs-6] == 0xC7 && buf[compiledOfs-5] == 0x07 ) 
    353 	{	// mov edi, 0x123456
    354 		compiledOfs -= 6;
    355 		vm->instructionPointers[ instruction-1 ] = compiledOfs;
    356 		EmitString( "B8" );			// mov	eax, 0x12345678
    357 		Emit4( lastConst );
    358 		return;
    359 	}
    360 	EmitString( "8B 07" );		// mov eax, dword ptr [edi]
    361 }
    362 
    363 qboolean EmitMovEBXEDI(vm_t *vm, int andit) {
    364 	if (LastCommand == LAST_COMMAND_MOV_EDI_EAX) 
    365 	{	// mov [edi], eax
    366 		compiledOfs -= 2;
    367 		vm->instructionPointers[ instruction-1 ] = compiledOfs;
    368 		EmitString( "8B D8");		// mov bx, eax
    369 		return qfalse;
    370 	}
    371 	if (pop1 == OP_DIVI || pop1 == OP_DIVU || pop1 == OP_MULI || pop1 == OP_MULU ||
    372 		pop1 == OP_STORE4 || pop1 == OP_STORE2 || pop1 == OP_STORE1 ) 
    373 	{	
    374 		EmitString( "8B D8");		// mov bx, eax
    375 		return qfalse;
    376 	}
    377 	if (pop1 == OP_CONST && buf[compiledOfs-6] == 0xC7 && buf[compiledOfs-5] == 0x07 ) 
    378 	{		// mov edi, 0x123456
    379 		compiledOfs -= 6;
    380 		vm->instructionPointers[ instruction-1 ] = compiledOfs;
    381 		EmitString( "BB" );			// mov	ebx, 0x12345678
    382 		if (andit) {
    383 			Emit4( lastConst & andit );
    384 		} else {
    385 			Emit4( lastConst );
    386 		}
    387 		return qtrue;
    388 	}
    389 
    390 	EmitString( "8B 1F" );		// mov ebx, dword ptr [edi]
    391 	return qfalse;
    392 }
    393 
    394 /*
    395 =================
    396 VM_Compile
    397 =================
    398 */
    399 void VM_Compile( vm_t *vm, vmHeader_t *header ) {
    400 	int		op;
    401 	int		maxLength;
    402 	int		v;
    403 	int		i;
    404 	qboolean opt;
    405 
    406 	// allocate a very large temp buffer, we will shrink it later
    407 	maxLength = header->codeLength * 8;
    408 	buf = Z_Malloc( maxLength );
    409 	jused = Z_Malloc(header->instructionCount + 2 );
    410 	
    411 	Com_Memset(jused, 0, header->instructionCount+2);
    412 
    413 	for(pass=0;pass<2;pass++) {
    414 	oc0 = -23423;
    415 	oc1 = -234354;
    416 	pop0 = -43435;
    417 	pop1 = -545455;
    418 
    419 	// translate all instructions
    420 	pc = 0;
    421 	instruction = 0;
    422 	code = (byte *)header + header->codeOffset;
    423 	compiledOfs = 0;
    424 
    425 	LastCommand = LAST_COMMAND_NONE;
    426 
    427 	while ( instruction < header->instructionCount ) {
    428 		if ( compiledOfs > maxLength - 16 ) {
    429 			Com_Error( ERR_FATAL, "VM_CompileX86: maxLength exceeded" );
    430 		}
    431 
    432 		vm->instructionPointers[ instruction ] = compiledOfs;
    433 		instruction++;
    434 
    435 		if ( pc > header->codeLength ) {
    436 			Com_Error( ERR_FATAL, "VM_CompileX86: pc > header->codeLength" );
    437 		}
    438 
    439 		op = code[ pc ];
    440 		pc++;
    441 		switch ( op ) {
    442 		case 0:
    443 			break;
    444 		case OP_BREAK:
    445 			EmitString( "CC" );			// int 3
    446 			break;
    447 		case OP_ENTER:
    448 			EmitString( "81 EE" );		// sub	esi, 0x12345678
    449 			Emit4( Constant4() );
    450 			break;
    451 		case OP_CONST:
    452 			if (code[pc+4] == OP_LOAD4) {
    453 				EmitAddEDI4(vm);
    454 				EmitString( "BB" );		// mov	ebx, 0x12345678
    455 				Emit4( (Constant4()&vm->dataMask) + (int)vm->dataBase);
    456 				EmitString( "8B 03" );		// mov	eax, dword ptr [ebx]
    457 				EmitCommand(LAST_COMMAND_MOV_EDI_EAX);		// mov dword ptr [edi], eax
    458 				pc++;						// OP_LOAD4
    459 				instruction += 1;
    460 				break;
    461 			}
    462 			if (code[pc+4] == OP_LOAD2) {
    463 				EmitAddEDI4(vm);
    464 				EmitString( "BB" );		// mov	ebx, 0x12345678
    465 				Emit4( (Constant4()&vm->dataMask) + (int)vm->dataBase);
    466 				EmitString( "0F B7 03" );	// movzx	eax, word ptr [ebx]
    467 				EmitCommand(LAST_COMMAND_MOV_EDI_EAX);		// mov dword ptr [edi], eax
    468 				pc++;						// OP_LOAD4
    469 				instruction += 1;
    470 				break;
    471 			}
    472 			if (code[pc+4] == OP_LOAD1) {
    473 				EmitAddEDI4(vm);
    474 				EmitString( "BB" );		// mov	ebx, 0x12345678
    475 				Emit4( (Constant4()&vm->dataMask) + (int)vm->dataBase);
    476 				EmitString( "0F B6 03" );	// movzx	eax, byte ptr [ebx]
    477 				EmitCommand(LAST_COMMAND_MOV_EDI_EAX);		// mov dword ptr [edi], eax
    478 				pc++;						// OP_LOAD4
    479 				instruction += 1;
    480 				break;
    481 			}
    482 			if (code[pc+4] == OP_STORE4) {
    483 				opt = EmitMovEBXEDI(vm, (vm->dataMask & ~3));
    484 				EmitString( "B8" );			// mov	eax, 0x12345678
    485 				Emit4( Constant4() );
    486 //				if (!opt) {
    487 //					EmitString( "81 E3" );		// and ebx, 0x12345678
    488 //					Emit4( vm->dataMask & ~3 );
    489 //				}
    490 				EmitString( "89 83" );		// mov dword ptr [ebx+0x12345678], eax
    491 				Emit4( (int)vm->dataBase );
    492 				EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    493 				pc++;						// OP_STORE4
    494 				instruction += 1;
    495 				break;
    496 			}
    497 			if (code[pc+4] == OP_STORE2) {
    498 				opt = EmitMovEBXEDI(vm, (vm->dataMask & ~1));
    499 				EmitString( "B8" );			// mov	eax, 0x12345678
    500 				Emit4( Constant4() );
    501 //				if (!opt) {
    502 //					EmitString( "81 E3" );		// and ebx, 0x12345678
    503 //					Emit4( vm->dataMask & ~1 );
    504 //				}
    505 				EmitString( "66 89 83" );	// mov word ptr [ebx+0x12345678], eax
    506 				Emit4( (int)vm->dataBase );
    507 				EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    508 				pc++;						// OP_STORE4
    509 				instruction += 1;
    510 				break;
    511 			}
    512 			if (code[pc+4] == OP_STORE1) {
    513 				opt = EmitMovEBXEDI(vm, vm->dataMask);
    514 				EmitString( "B8" );			// mov	eax, 0x12345678
    515 				Emit4( Constant4() );
    516 //				if (!opt) {
    517 //					EmitString( "81 E3" );	// and ebx, 0x12345678
    518 //					Emit4( vm->dataMask );
    519 //				}
    520 				EmitString( "88 83" );		// mov byte ptr [ebx+0x12345678], eax
    521 				Emit4( (int)vm->dataBase );
    522 				EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    523 				pc++;						// OP_STORE4
    524 				instruction += 1;
    525 				break;
    526 			}
    527 			if (code[pc+4] == OP_ADD) {
    528 				EmitString( "81 07" );		// add dword ptr [edi], 0x1234567
    529 				Emit4( Constant4() );
    530 				pc++;						// OP_ADD
    531 				instruction += 1;
    532 				break;
    533 			}
    534 			if (code[pc+4] == OP_SUB) {
    535 				EmitString( "81 2F" );		// sub dword ptr [edi], 0x1234567
    536 				Emit4( Constant4() );
    537 				pc++;						// OP_ADD
    538 				instruction += 1;
    539 				break;
    540 			}
    541 			EmitAddEDI4(vm);
    542 			EmitString( "C7 07" );		// mov	dword ptr [edi], 0x12345678
    543 			lastConst = Constant4();
    544 			Emit4( lastConst );
    545 			if (code[pc] == OP_JUMP) {
    546 				jused[lastConst] = 1;
    547 			}
    548 			break;
    549 		case OP_LOCAL:
    550 			EmitAddEDI4(vm);
    551 			EmitString( "8D 86" );		// lea eax, [0x12345678 + esi]
    552 			oc0 = oc1;
    553 			oc1 = Constant4();
    554 			Emit4( oc1 );
    555 			EmitCommand(LAST_COMMAND_MOV_EDI_EAX);		// mov dword ptr [edi], eax
    556 			break;
    557 		case OP_ARG:
    558 			EmitMovEAXEDI(vm);			// mov	eax,dword ptr [edi]
    559 			EmitString( "89 86" );		// mov	dword ptr [esi+database],eax
    560 			// FIXME: range check
    561 			Emit4( Constant1() + (int)vm->dataBase );
    562 			EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    563 			break;
    564 		case OP_CALL:
    565 			EmitString( "C7 86" );		// mov dword ptr [esi+database],0x12345678
    566 			Emit4( (int)vm->dataBase );
    567 			Emit4( pc );
    568 			EmitString( "FF 15" );		// call asmCallPtr
    569 			Emit4( (int)&asmCallPtr );
    570 			break;
    571 		case OP_PUSH:
    572 			EmitAddEDI4(vm);
    573 			break;
    574 		case OP_POP:
    575 			EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    576 			break;
    577 		case OP_LEAVE:
    578 			v = Constant4();
    579 			EmitString( "81 C6" );		// add	esi, 0x12345678
    580 			Emit4( v );
    581 			EmitString( "C3" );			// ret
    582 			break;
    583 		case OP_LOAD4:
    584 			if (code[pc] == OP_CONST && code[pc+5] == OP_ADD && code[pc+6] == OP_STORE4) {
    585 				if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) {
    586 					compiledOfs -= 11;
    587 					vm->instructionPointers[ instruction-1 ] = compiledOfs;
    588 				}
    589 				pc++;						// OP_CONST
    590 				v = Constant4();
    591 				EmitMovEBXEDI(vm, vm->dataMask);
    592 				if (v == 1 && oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) {
    593 					EmitString( "FF 83");		// inc dword ptr [ebx + 0x12345678]
    594 					Emit4( (int)vm->dataBase );
    595 				} else {
    596 					EmitString( "8B 83" );		// mov	eax, dword ptr [ebx + 0x12345678]
    597 					Emit4( (int)vm->dataBase );
    598 					EmitString( "05"  );		// add eax, const
    599 					Emit4( v );
    600 					if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) {
    601 						EmitString( "89 83" );		// mov dword ptr [ebx+0x12345678], eax
    602 						Emit4( (int)vm->dataBase );
    603 					} else {
    604 						EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    605 						EmitString( "8B 1F" );		// mov	ebx, dword ptr [edi]
    606 						EmitString( "89 83" );		// mov dword ptr [ebx+0x12345678], eax
    607 						Emit4( (int)vm->dataBase );
    608 					}
    609 				}
    610 				EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    611 				pc++;						// OP_ADD
    612 				pc++;						// OP_STORE
    613 				instruction += 3;
    614 				break;
    615 			}
    616 
    617 			if (code[pc] == OP_CONST && code[pc+5] == OP_SUB && code[pc+6] == OP_STORE4) {
    618 				if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) {
    619 					compiledOfs -= 11;
    620 					vm->instructionPointers[ instruction-1 ] = compiledOfs;
    621 				}
    622 				EmitMovEBXEDI(vm, vm->dataMask);
    623 				EmitString( "8B 83" );		// mov	eax, dword ptr [ebx + 0x12345678]
    624 				Emit4( (int)vm->dataBase );
    625 				pc++;						// OP_CONST
    626 				v = Constant4();
    627 				if (v == 1 && oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) {
    628 					EmitString( "FF 8B");		// dec dword ptr [ebx + 0x12345678]
    629 					Emit4( (int)vm->dataBase );
    630 				} else {
    631 					EmitString( "2D"  );		// sub eax, const
    632 					Emit4( v );
    633 					if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) {
    634 						EmitString( "89 83" );		// mov dword ptr [ebx+0x12345678], eax
    635 						Emit4( (int)vm->dataBase );
    636 					} else {
    637 						EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    638 						EmitString( "8B 1F" );		// mov	ebx, dword ptr [edi]
    639 						EmitString( "89 83" );		// mov dword ptr [ebx+0x12345678], eax
    640 						Emit4( (int)vm->dataBase );
    641 					}
    642 				}
    643 				EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    644 				pc++;						// OP_SUB
    645 				pc++;						// OP_STORE
    646 				instruction += 3;
    647 				break;
    648 			}
    649 
    650 			if (buf[compiledOfs-2] == 0x89 && buf[compiledOfs-1] == 0x07) {
    651 				compiledOfs -= 2;
    652 				vm->instructionPointers[ instruction-1 ] = compiledOfs;
    653 				EmitString( "8B 80");	// mov eax, dword ptr [eax + 0x1234567]
    654 				Emit4( (int)vm->dataBase );
    655 				EmitCommand(LAST_COMMAND_MOV_EDI_EAX);		// mov dword ptr [edi], eax
    656 				break;
    657 			}
    658 			EmitMovEBXEDI(vm, vm->dataMask);
    659 			EmitString( "8B 83" );		// mov	eax, dword ptr [ebx + 0x12345678]
    660 			Emit4( (int)vm->dataBase );
    661 			EmitCommand(LAST_COMMAND_MOV_EDI_EAX);		// mov dword ptr [edi], eax
    662 			break;
    663 		case OP_LOAD2:
    664 			EmitMovEBXEDI(vm, vm->dataMask);
    665 			EmitString( "0F B7 83" );	// movzx	eax, word ptr [ebx + 0x12345678]
    666 			Emit4( (int)vm->dataBase );
    667 			EmitCommand(LAST_COMMAND_MOV_EDI_EAX);		// mov dword ptr [edi], eax
    668 			break;
    669 		case OP_LOAD1:
    670 			EmitMovEBXEDI(vm, vm->dataMask);
    671 			EmitString( "0F B6 83" );	// movzx eax, byte ptr [ebx + 0x12345678]
    672 			Emit4( (int)vm->dataBase );
    673 			EmitCommand(LAST_COMMAND_MOV_EDI_EAX);		// mov dword ptr [edi], eax
    674 			break;
    675 		case OP_STORE4:
    676 			EmitMovEAXEDI(vm);	
    677 			EmitString( "8B 5F FC" );	// mov	ebx, dword ptr [edi-4]
    678 //			if (pop1 != OP_CALL) {
    679 //				EmitString( "81 E3" );		// and ebx, 0x12345678
    680 //				Emit4( vm->dataMask & ~3 );
    681 //			}
    682 			EmitString( "89 83" );		// mov dword ptr [ebx+0x12345678], eax
    683 			Emit4( (int)vm->dataBase );
    684 			EmitCommand(LAST_COMMAND_SUB_DI_8);		// sub edi, 8
    685 			break;
    686 		case OP_STORE2:
    687 			EmitMovEAXEDI(vm);	
    688 			EmitString( "8B 5F FC" );	// mov	ebx, dword ptr [edi-4]
    689 //			EmitString( "81 E3" );		// and ebx, 0x12345678
    690 //			Emit4( vm->dataMask & ~1 );
    691 			EmitString( "66 89 83" );	// mov word ptr [ebx+0x12345678], eax
    692 			Emit4( (int)vm->dataBase );
    693 			EmitCommand(LAST_COMMAND_SUB_DI_8);		// sub edi, 8
    694 			break;
    695 		case OP_STORE1:
    696 			EmitMovEAXEDI(vm);	
    697 			EmitString( "8B 5F FC" );	// mov	ebx, dword ptr [edi-4]
    698 //			EmitString( "81 E3" );		// and ebx, 0x12345678
    699 //			Emit4( vm->dataMask );
    700 			EmitString( "88 83" );		// mov byte ptr [ebx+0x12345678], eax
    701 			Emit4( (int)vm->dataBase );
    702 			EmitCommand(LAST_COMMAND_SUB_DI_8);		// sub edi, 8
    703 			break;
    704 
    705 		case OP_EQ:
    706 			EmitCommand(LAST_COMMAND_SUB_DI_8);		// sub edi, 8
    707 			EmitString( "8B 47 04" );	// mov	eax, dword ptr [edi+4]
    708 			EmitString( "3B 47 08" );	// cmp	eax, dword ptr [edi+8]
    709 			EmitString( "75 06" );		// jne +6
    710 			EmitString( "FF 25" );		// jmp	[0x12345678]
    711 			v = Constant4();
    712 			jused[v] = 1;
    713 			Emit4( (int)vm->instructionPointers + v*4 );
    714 			break;
    715 		case OP_NE:
    716 			EmitCommand(LAST_COMMAND_SUB_DI_8);		// sub edi, 8
    717 			EmitString( "8B 47 04" );	// mov	eax, dword ptr [edi+4]
    718 			EmitString( "3B 47 08" );	// cmp	eax, dword ptr [edi+8]
    719 			EmitString( "74 06" );		// je +6
    720 			EmitString( "FF 25" );		// jmp	[0x12345678]
    721 			v = Constant4();
    722 			jused[v] = 1;
    723 			Emit4( (int)vm->instructionPointers + v*4 );
    724 			break;
    725 		case OP_LTI:
    726 			EmitCommand(LAST_COMMAND_SUB_DI_8);		// sub edi, 8
    727 			EmitString( "8B 47 04" );	// mov	eax, dword ptr [edi+4]
    728 			EmitString( "3B 47 08" );	// cmp	eax, dword ptr [edi+8]
    729 			EmitString( "7D 06" );		// jnl +6
    730 			EmitString( "FF 25" );		// jmp	[0x12345678]
    731 			v = Constant4();
    732 			jused[v] = 1;
    733 			Emit4( (int)vm->instructionPointers + v*4 );
    734 			break;
    735 		case OP_LEI:
    736 			EmitCommand(LAST_COMMAND_SUB_DI_8);		// sub edi, 8
    737 			EmitString( "8B 47 04" );	// mov	eax, dword ptr [edi+4]
    738 			EmitString( "3B 47 08" );	// cmp	eax, dword ptr [edi+8]
    739 			EmitString( "7F 06" );		// jnle +6
    740 			EmitString( "FF 25" );		// jmp	[0x12345678]
    741 			v = Constant4();
    742 			jused[v] = 1;
    743 			Emit4( (int)vm->instructionPointers + v*4 );
    744 			break;
    745 		case OP_GTI:
    746 			EmitCommand(LAST_COMMAND_SUB_DI_8);		// sub edi, 8
    747 			EmitString( "8B 47 04" );	// mov	eax, dword ptr [edi+4]
    748 			EmitString( "3B 47 08" );	// cmp	eax, dword ptr [edi+8]
    749 			EmitString( "7E 06" );		// jng +6
    750 			EmitString( "FF 25" );		// jmp	[0x12345678]
    751 			v = Constant4();
    752 			jused[v] = 1;
    753 			Emit4( (int)vm->instructionPointers + v*4 );
    754 			break;
    755 		case OP_GEI:
    756 			EmitCommand(LAST_COMMAND_SUB_DI_8);		// sub edi, 8
    757 			EmitString( "8B 47 04" );	// mov	eax, dword ptr [edi+4]
    758 			EmitString( "3B 47 08" );	// cmp	eax, dword ptr [edi+8]
    759 			EmitString( "7C 06" );		// jnge +6
    760 			EmitString( "FF 25" );		// jmp	[0x12345678]
    761 			v = Constant4();
    762 			jused[v] = 1;
    763 			Emit4( (int)vm->instructionPointers + v*4 );
    764 			break;
    765 		case OP_LTU:
    766 			EmitCommand(LAST_COMMAND_SUB_DI_8);		// sub edi, 8
    767 			EmitString( "8B 47 04" );	// mov	eax, dword ptr [edi+4]
    768 			EmitString( "3B 47 08" );	// cmp	eax, dword ptr [edi+8]
    769 			EmitString( "73 06" );		// jnb +6
    770 			EmitString( "FF 25" );		// jmp	[0x12345678]
    771 			v = Constant4();
    772 			jused[v] = 1;
    773 			Emit4( (int)vm->instructionPointers + v*4 );
    774 			break;
    775 		case OP_LEU:
    776 			EmitCommand(LAST_COMMAND_SUB_DI_8);		// sub edi, 8
    777 			EmitString( "8B 47 04" );	// mov	eax, dword ptr [edi+4]
    778 			EmitString( "3B 47 08" );	// cmp	eax, dword ptr [edi+8]
    779 			EmitString( "77 06" );		// jnbe +6
    780 			EmitString( "FF 25" );		// jmp	[0x12345678]
    781 			v = Constant4();
    782 			jused[v] = 1;
    783 			Emit4( (int)vm->instructionPointers + v*4 );
    784 			break;
    785 		case OP_GTU:
    786 			EmitCommand(LAST_COMMAND_SUB_DI_8);		// sub edi, 8
    787 			EmitString( "8B 47 04" );	// mov	eax, dword ptr [edi+4]
    788 			EmitString( "3B 47 08" );	// cmp	eax, dword ptr [edi+8]
    789 			EmitString( "76 06" );		// jna +6
    790 			EmitString( "FF 25" );		// jmp	[0x12345678]
    791 			v = Constant4();
    792 			jused[v] = 1;
    793 			Emit4( (int)vm->instructionPointers + v*4 );
    794 			break;
    795 		case OP_GEU:
    796 			EmitCommand(LAST_COMMAND_SUB_DI_8);		// sub edi, 8
    797 			EmitString( "8B 47 04" );	// mov	eax, dword ptr [edi+4]
    798 			EmitString( "3B 47 08" );	// cmp	eax, dword ptr [edi+8]
    799 			EmitString( "72 06" );		// jnae +6
    800 			EmitString( "FF 25" );		// jmp	[0x12345678]
    801 			v = Constant4();
    802 			jused[v] = 1;
    803 			Emit4( (int)vm->instructionPointers + v*4 );
    804 			break;
    805 		case OP_EQF:
    806 			EmitCommand(LAST_COMMAND_SUB_DI_8);		// sub edi, 8
    807 			EmitString( "D9 47 04" );	// fld dword ptr [edi+4]
    808 			EmitString( "D8 5F 08" );	// fcomp dword ptr [edi+8]
    809 			EmitString( "DF E0" );		// fnstsw ax
    810 			EmitString( "F6 C4 40" );	// test	ah,0x40
    811 			EmitString( "74 06" );		// je +6
    812 			EmitString( "FF 25" );		// jmp	[0x12345678]
    813 			v = Constant4();
    814 			jused[v] = 1;
    815 			Emit4( (int)vm->instructionPointers + v*4 );
    816 			break;			
    817 		case OP_NEF:
    818 			EmitCommand(LAST_COMMAND_SUB_DI_8);		// sub edi, 8
    819 			EmitString( "D9 47 04" );	// fld dword ptr [edi+4]
    820 			EmitString( "D8 5F 08" );	// fcomp dword ptr [edi+8]
    821 			EmitString( "DF E0" );		// fnstsw ax
    822 			EmitString( "F6 C4 40" );	// test	ah,0x40
    823 			EmitString( "75 06" );		// jne +6
    824 			EmitString( "FF 25" );		// jmp	[0x12345678]
    825 			v = Constant4();
    826 			jused[v] = 1;
    827 			Emit4( (int)vm->instructionPointers + v*4 );
    828 			break;			
    829 		case OP_LTF:
    830 			EmitCommand(LAST_COMMAND_SUB_DI_8);		// sub edi, 8
    831 			EmitString( "D9 47 04" );	// fld dword ptr [edi+4]
    832 			EmitString( "D8 5F 08" );	// fcomp dword ptr [edi+8]
    833 			EmitString( "DF E0" );		// fnstsw ax
    834 			EmitString( "F6 C4 01" );	// test	ah,0x01
    835 			EmitString( "74 06" );		// je +6
    836 			EmitString( "FF 25" );		// jmp	[0x12345678]
    837 			v = Constant4();
    838 			jused[v] = 1;
    839 			Emit4( (int)vm->instructionPointers + v*4 );
    840 			break;			
    841 		case OP_LEF:
    842 			EmitCommand(LAST_COMMAND_SUB_DI_8);		// sub edi, 8
    843 			EmitString( "D9 47 04" );	// fld dword ptr [edi+4]
    844 			EmitString( "D8 5F 08" );	// fcomp dword ptr [edi+8]
    845 			EmitString( "DF E0" );		// fnstsw ax
    846 			EmitString( "F6 C4 41" );	// test	ah,0x41
    847 			EmitString( "74 06" );		// je +6
    848 			EmitString( "FF 25" );		// jmp	[0x12345678]
    849 			v = Constant4();
    850 			jused[v] = 1;
    851 			Emit4( (int)vm->instructionPointers + v*4 );
    852 			break;			
    853 		case OP_GTF:
    854 			EmitCommand(LAST_COMMAND_SUB_DI_8);		// sub edi, 8
    855 			EmitString( "D9 47 04" );	// fld dword ptr [edi+4]
    856 			EmitString( "D8 5F 08" );	// fcomp dword ptr [edi+8]
    857 			EmitString( "DF E0" );		// fnstsw ax
    858 			EmitString( "F6 C4 41" );	// test	ah,0x41
    859 			EmitString( "75 06" );		// jne +6
    860 			EmitString( "FF 25" );		// jmp	[0x12345678]
    861 			v = Constant4();
    862 			jused[v] = 1;
    863 			Emit4( (int)vm->instructionPointers + v*4 );
    864 			break;			
    865 		case OP_GEF:
    866 			EmitCommand(LAST_COMMAND_SUB_DI_8);		// sub edi, 8
    867 			EmitString( "D9 47 04" );	// fld dword ptr [edi+4]
    868 			EmitString( "D8 5F 08" );	// fcomp dword ptr [edi+8]
    869 			EmitString( "DF E0" );		// fnstsw ax
    870 			EmitString( "F6 C4 01" );	// test	ah,0x01
    871 			EmitString( "75 06" );		// jne +6
    872 			EmitString( "FF 25" );		// jmp	[0x12345678]
    873 			v = Constant4();
    874 			jused[v] = 1;
    875 			Emit4( (int)vm->instructionPointers + v*4 );
    876 			break;			
    877 		case OP_NEGI:
    878 			EmitString( "F7 1F" );		// neg dword ptr [edi]
    879 			break;
    880 		case OP_ADD:
    881 			EmitMovEAXEDI(vm);			// mov eax, dword ptr [edi]
    882 			EmitString( "01 47 FC" );	// add dword ptr [edi-4],eax
    883 			EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    884 			break;
    885 		case OP_SUB:
    886 			EmitMovEAXEDI(vm);			// mov eax, dword ptr [edi]
    887 			EmitString( "29 47 FC" );	// sub dword ptr [edi-4],eax
    888 			EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    889 			break;
    890 		case OP_DIVI:
    891 			EmitString( "8B 47 FC" );	// mov eax,dword ptr [edi-4]
    892 			EmitString( "99" );			// cdq
    893 			EmitString( "F7 3F" );		// idiv dword ptr [edi]
    894 			EmitString( "89 47 FC" );	// mov dword ptr [edi-4],eax
    895 			EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    896 			break;
    897 		case OP_DIVU:
    898 			EmitString( "8B 47 FC" );	// mov eax,dword ptr [edi-4]
    899 			EmitString( "33 D2" );		// xor edx, edx
    900 			EmitString( "F7 37" );		// div dword ptr [edi]
    901 			EmitString( "89 47 FC" );	// mov dword ptr [edi-4],eax
    902 			EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    903 			break;
    904 		case OP_MODI:
    905 			EmitString( "8B 47 FC" );	// mov eax,dword ptr [edi-4]
    906 			EmitString( "99" );			// cdq
    907 			EmitString( "F7 3F" );		// idiv dword ptr [edi]
    908 			EmitString( "89 57 FC" );	// mov dword ptr [edi-4],edx
    909 			EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    910 			break;
    911 		case OP_MODU:
    912 			EmitString( "8B 47 FC" );	// mov eax,dword ptr [edi-4]
    913 			EmitString( "33 D2" );		// xor edx, edx
    914 			EmitString( "F7 37" );		// div dword ptr [edi]
    915 			EmitString( "89 57 FC" );	// mov dword ptr [edi-4],edx
    916 			EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    917 			break;
    918 		case OP_MULI:
    919 			EmitString( "8B 47 FC" );	// mov eax,dword ptr [edi-4]
    920 			EmitString( "F7 2F" );		// imul dword ptr [edi]
    921 			EmitString( "89 47 FC" );	// mov dword ptr [edi-4],eax
    922 			EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    923 			break;
    924 		case OP_MULU:
    925 			EmitString( "8B 47 FC" );	// mov eax,dword ptr [edi-4]
    926 			EmitString( "F7 27" );		// mul dword ptr [edi]
    927 			EmitString( "89 47 FC" );	// mov dword ptr [edi-4],eax
    928 			EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    929 			break;
    930 		case OP_BAND:
    931 			EmitMovEAXEDI(vm);			// mov eax, dword ptr [edi]
    932 			EmitString( "21 47 FC" );	// and dword ptr [edi-4],eax
    933 			EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    934 			break;
    935 		case OP_BOR:
    936 			EmitMovEAXEDI(vm);			// mov eax, dword ptr [edi]
    937 			EmitString( "09 47 FC" );	// or dword ptr [edi-4],eax
    938 			EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    939 			break;
    940 		case OP_BXOR:
    941 			EmitMovEAXEDI(vm);			// mov eax, dword ptr [edi]
    942 			EmitString( "31 47 FC" );	// xor dword ptr [edi-4],eax
    943 			EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    944 			break;
    945 		case OP_BCOM:
    946 			EmitString( "F7 17" );		// not dword ptr [edi]
    947 			break;
    948 		case OP_LSH:
    949 			EmitString( "8B 0F" );		// mov ecx, dword ptr [edi]
    950 			EmitString( "D3 67 FC" );	// shl dword ptr [edi-4], cl
    951 			EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    952 			break;
    953 		case OP_RSHI:
    954 			EmitString( "8B 0F" );		// mov ecx, dword ptr [edi]
    955 			EmitString( "D3 7F FC" );	// sar dword ptr [edi-4], cl
    956 			EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    957 			break;
    958 		case OP_RSHU:
    959 			EmitString( "8B 0F" );		// mov ecx, dword ptr [edi]
    960 			EmitString( "D3 6F FC" );	// shr dword ptr [edi-4], cl
    961 			EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    962 			break;
    963 		case OP_NEGF:
    964 			EmitString( "D9 07" );		// fld dword ptr [edi]
    965 			EmitString( "D9 E0" );		// fchs
    966 			EmitString( "D9 1F" );		// fstp dword ptr [edi]
    967 			break;
    968 		case OP_ADDF:
    969 			EmitString( "D9 47 FC" );	// fld dword ptr [edi-4]
    970 			EmitString( "D8 07" );		// fadd dword ptr [edi]
    971 			EmitString( "D9 5F FC" );	// fstp dword ptr [edi-4]
    972 			EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    973 			break;
    974 		case OP_SUBF:
    975 			EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    976 			EmitString( "D9 07" );		// fld dword ptr [edi]
    977 			EmitString( "D8 67 04" );	// fsub dword ptr [edi+4]
    978 			EmitString( "D9 1F" );		// fstp dword ptr [edi]
    979 			break;
    980 		case OP_DIVF:
    981 			EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    982 			EmitString( "D9 07" );		// fld dword ptr [edi]
    983 			EmitString( "D8 77 04" );	// fdiv dword ptr [edi+4]
    984 			EmitString( "D9 1F" );		// fstp dword ptr [edi]
    985 			break;
    986 		case OP_MULF:
    987 			EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
    988 			EmitString( "D9 07" );		// fld dword ptr [edi]
    989 			EmitString( "D8 4f 04" );	// fmul dword ptr [edi+4]
    990 			EmitString( "D9 1F" );		// fstp dword ptr [edi]
    991 			break;
    992 		case OP_CVIF:
    993 			EmitString( "DB 07" );		// fild dword ptr [edi]
    994 			EmitString( "D9 1F" );		// fstp dword ptr [edi]
    995 			break;
    996 		case OP_CVFI:
    997 #ifndef FTOL_PTR // WHENHELLISFROZENOVER  // bk001213 - was used in 1.17
    998 			// not IEEE complient, but simple and fast
    999 		  EmitString( "D9 07" );		// fld dword ptr [edi]
   1000 			EmitString( "DB 1F" );		// fistp dword ptr [edi]
   1001 #else // FTOL_PTR
   1002 			// call the library conversion function
   1003 			EmitString( "D9 07" );		// fld dword ptr [edi]
   1004 			EmitString( "FF 15" );		// call ftolPtr
   1005 			Emit4( (int)&ftolPtr );
   1006 			EmitCommand(LAST_COMMAND_MOV_EDI_EAX);		// mov dword ptr [edi], eax
   1007 #endif
   1008 			break;
   1009 		case OP_SEX8:
   1010 			EmitString( "0F BE 07" );	// movsx eax, byte ptr [edi]
   1011 			EmitCommand(LAST_COMMAND_MOV_EDI_EAX);		// mov dword ptr [edi], eax
   1012 			break;
   1013 		case OP_SEX16:
   1014 			EmitString( "0F BF 07" );	// movsx eax, word ptr [edi]
   1015 			EmitCommand(LAST_COMMAND_MOV_EDI_EAX);		// mov dword ptr [edi], eax
   1016 			break;
   1017 
   1018 		case OP_BLOCK_COPY:
   1019 			// FIXME: range check
   1020 			EmitString( "56" );			// push esi
   1021 			EmitString( "57" );			// push edi
   1022 			EmitString( "8B 37" );		// mov esi,[edi] 
   1023 			EmitString( "8B 7F FC" );	// mov edi,[edi-4] 
   1024 			EmitString( "B9" );			// mov ecx,0x12345678
   1025 			Emit4( Constant4() >> 2 );
   1026 			EmitString( "B8" );			// mov eax, datamask
   1027 			Emit4( vm->dataMask );
   1028 			EmitString( "BB" );			// mov ebx, database
   1029 			Emit4( (int)vm->dataBase );
   1030 			EmitString( "23 F0" );		// and esi, eax
   1031 			EmitString( "03 F3" );		// add esi, ebx
   1032 			EmitString( "23 F8" );		// and edi, eax
   1033 			EmitString( "03 FB" );		// add edi, ebx
   1034 			EmitString( "F3 A5" );		// rep movsd
   1035 			EmitString( "5F" );			// pop edi
   1036 			EmitString( "5E" );			// pop esi
   1037 			EmitCommand(LAST_COMMAND_SUB_DI_8);		// sub edi, 8
   1038 			break;
   1039 
   1040 		case OP_JUMP:
   1041 			EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
   1042 			EmitString( "8B 47 04" );	// mov eax,dword ptr [edi+4]
   1043 			// FIXME: range check
   1044 			EmitString( "FF 24 85" );	// jmp dword ptr [instructionPointers + eax * 4]
   1045 			Emit4( (int)vm->instructionPointers );
   1046 			break;
   1047 		default:
   1048 			Com_Error( ERR_DROP, "VM_CompileX86: bad opcode %i at offset %i", op, pc );
   1049 		}
   1050 		pop0 = pop1;
   1051 		pop1 = op;
   1052 	}
   1053 	}
   1054 
   1055 	// copy to an exact size buffer on the hunk
   1056 	vm->codeLength = compiledOfs;
   1057 	vm->codeBase = Hunk_Alloc( compiledOfs, h_low );
   1058 	Com_Memcpy( vm->codeBase, buf, compiledOfs );
   1059 	Z_Free( buf );
   1060 	Z_Free( jused );
   1061 	Com_Printf( "VM file %s compiled to %i bytes of code\n", vm->name, compiledOfs );
   1062 
   1063 	// offset all the instruction pointers for the new location
   1064 	for ( i = 0 ; i < header->instructionCount ; i++ ) {
   1065 		vm->instructionPointers[i] += (int)vm->codeBase;
   1066 	}
   1067 
   1068 #if 0 // ndef _WIN32
   1069 	// Must make the newly generated code executable
   1070 	{
   1071 		int r;
   1072 		unsigned long addr;
   1073 		int psize = getpagesize();
   1074 
   1075 		addr = ((int)vm->codeBase & ~(psize-1)) - psize;
   1076 
   1077 		r = mprotect((char*)addr, vm->codeLength + (int)vm->codeBase - addr + psize, 
   1078 			PROT_READ | PROT_WRITE | PROT_EXEC );
   1079 
   1080 		if (r < 0)
   1081 			Com_Error( ERR_FATAL, "mprotect failed to change PROT_EXEC" );
   1082 	}
   1083 #endif
   1084 
   1085 }
   1086 
   1087 /*
   1088 ==============
   1089 VM_CallCompiled
   1090 
   1091 This function is called directly by the generated code
   1092 ==============
   1093 */
   1094 #ifndef DLL_ONLY // bk010215 - for DLL_ONLY dedicated servers/builds w/o VM
   1095 int	VM_CallCompiled( vm_t *vm, int *args ) {
   1096 	int		stack[1024];
   1097 	int		programCounter;
   1098 	int		programStack;
   1099 	int		stackOnEntry;
   1100 	byte	*image;
   1101 	void	*entryPoint;
   1102 	void	*opStack;
   1103 	int		*oldInstructionPointers;
   1104 
   1105 	oldInstructionPointers = instructionPointers;
   1106 
   1107 	currentVM = vm;
   1108 	instructionPointers = vm->instructionPointers;
   1109 
   1110 	// interpret the code
   1111 	vm->currentlyInterpreting = qtrue;
   1112 
   1113 	callMask = vm->dataMask;
   1114 
   1115 	// we might be called recursively, so this might not be the very top
   1116 	programStack = vm->programStack;
   1117 	stackOnEntry = programStack;
   1118 
   1119 	// set up the stack frame 
   1120 	image = vm->dataBase;
   1121 
   1122 	programCounter = 0;
   1123 
   1124 	programStack -= 48;
   1125 
   1126 	*(int *)&image[ programStack + 44] = args[9];
   1127 	*(int *)&image[ programStack + 40] = args[8];
   1128 	*(int *)&image[ programStack + 36] = args[7];
   1129 	*(int *)&image[ programStack + 32] = args[6];
   1130 	*(int *)&image[ programStack + 28] = args[5];
   1131 	*(int *)&image[ programStack + 24] = args[4];
   1132 	*(int *)&image[ programStack + 20] = args[3];
   1133 	*(int *)&image[ programStack + 16] = args[2];
   1134 	*(int *)&image[ programStack + 12] = args[1];
   1135 	*(int *)&image[ programStack + 8 ] = args[0];
   1136 	*(int *)&image[ programStack + 4 ] = 0;	// return stack
   1137 	*(int *)&image[ programStack ] = -1;	// will terminate the loop on return
   1138 
   1139 	// off we go into generated code...
   1140 	entryPoint = vm->codeBase;
   1141 	opStack = &stack;
   1142 
   1143 #ifdef _WIN32
   1144 	__asm  {
   1145 		pushad
   1146 		mov		esi, programStack;
   1147 		mov		edi, opStack
   1148 		call	entryPoint
   1149 		mov		programStack, esi
   1150 		mov		opStack, edi
   1151 		popad
   1152 	}
   1153 #else
   1154 	{
   1155 		static int memProgramStack;
   1156 		static void *memOpStack;
   1157 		static void *memEntryPoint;
   1158 
   1159 		memProgramStack	= programStack;
   1160 		memOpStack      = opStack;     
   1161 		memEntryPoint   = entryPoint;  
   1162 		
   1163 		__asm__("	pushal				\r\n" \
   1164 				"	movl %0,%%esi		\r\n" \
   1165 				"	movl %1,%%edi		\r\n" \
   1166 				"	call *%2			\r\n" \
   1167 				"	movl %%esi,%0		\r\n" \
   1168 				"	movl %%edi,%1		\r\n" \
   1169 				"	popal				\r\n" \
   1170 				: "=m" (memProgramStack), "=m" (memOpStack) \
   1171 				: "m" (memEntryPoint), "0" (memProgramStack), "1" (memOpStack) \
   1172 				: "si", "di" \
   1173 		);
   1174 
   1175 		programStack = memProgramStack;
   1176 		opStack      = memOpStack;
   1177 	}
   1178 #endif
   1179 
   1180 	if ( opStack != &stack[1] ) {
   1181 		Com_Error( ERR_DROP, "opStack corrupted in compiled code" );
   1182 	}
   1183 	if ( programStack != stackOnEntry - 48 ) {
   1184 		Com_Error( ERR_DROP, "programStack corrupted in compiled code" );
   1185 	}
   1186 
   1187 	vm->programStack = stackOnEntry;
   1188 
   1189 	// in case we were recursively called by another vm
   1190 	instructionPointers = oldInstructionPointers;
   1191 
   1192 	return *(int *)opStack;
   1193 }
   1194 #endif // !DLL_ONLY
   1195 
   1196