vm_x86.c 35 KB

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