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