summaryrefslogtreecommitdiff
path: root/src/virtualmachine
diff options
context:
space:
mode:
authorSimon Robertshaw <simon@hardwired.org.uk>2012-09-11 12:13:24 (GMT)
committer Simon Robertshaw <simon@hardwired.org.uk>2012-09-11 12:13:24 (GMT)
commit771d5df5c9796bb5d6f6c4cae453b138dd17f192 (patch)
treee983ce2d53697785c42a79ccb60336cc6e314932 /src/virtualmachine
parent89c50d8be20969931a493e09ac2681bfcc850c23 (diff)
downloadpowder-771d5df5c9796bb5d6f6c4cae453b138dd17f192.zip
powder-771d5df5c9796bb5d6f6c4cae453b138dd17f192.tar.gz
Fix buffer overflow with HTTP headers caused by recent \r\n commit"
Diffstat (limited to 'src/virtualmachine')
-rw-r--r--src/virtualmachine/JustInTime.cpp921
1 files changed, 921 insertions, 0 deletions
diff --git a/src/virtualmachine/JustInTime.cpp b/src/virtualmachine/JustInTime.cpp
new file mode 100644
index 0000000..9306892
--- /dev/null
+++ b/src/virtualmachine/JustInTime.cpp
@@ -0,0 +1,921 @@
+#include "VirtualMachine.h"
+
+namespace vm
+{
+ #define OP(n) OP##n
+ /*
+
+ eax scratch
+ ebx scratch
+ ecx scratch (required for shifts)
+ edx scratch (required for divisions)
+ esi program stack
+ edi opstack
+
+ */
+
+ // TTimo: initialised the statics, this fixes a crash when entering a compiled VM
+ static unsigned char *buf = NULL;
+ static unsigned char *jused = NULL;
+ static int compiledOfs = 0;
+ static int pc = 0;
+
+ static int callMask = 0; // bk001213 - init
+
+ static int instruction, pass;
+ static int lastConst = 0;
+ static int oc0, oc1, pop0, pop1;
+
+ static int *instructionPointers = NULL;
+
+ typedef enum
+ {
+ LAST_COMMAND_NONE = 0,
+ LAST_COMMAND_MOV_EDI_EAX,
+ LAST_COMMAND_SUB_DI_4,
+ LAST_COMMAND_SUB_DI_8,
+ } ELastCommand;
+
+ static ELastCommand LastCommand;
+
+ void VirtualMachine::Compile()
+ {
+ Instruction op;
+ int maxLength;
+ int v;
+ int i;
+ bool opt;
+
+ // allocate a very large temp buffer, we will shrink it later
+ maxLength = romSize * 8;
+ buf = new unsigned char[maxLength];
+ jused = new unsigned char[romSize + 2];
+ std::fill(jused, jused+romSize+2, 0);
+
+ for(pass=0; pass<2; pass++) {
+ oc0 = -23423;
+ oc1 = -234354;
+ pop0 = -43435;
+ pop1 = -545455;
+
+ // translate all instructions
+ pc = 0;
+ instruction = 0;
+ compiledOfs = 0;
+
+ LastCommand = LAST_COMMAND_NONE;
+
+ while (instruction < romSize)
+ {
+ if (compiledOfs > maxLength - 16)
+ {
+ throw JITException("Compile: maxLength exceeded");
+ }
+
+ instructionPointers[instruction] = compiledOfs;
+ instruction++;
+
+ if (pc > romSize)
+ {
+ throw JITException("Compile: program counter run off the edge");
+ }
+
+ op = rom[pc];
+ pc++;
+ switch ( op.Operation )
+ {
+ case 0:
+ break;
+ case OP(BREAK):
+ emitInstruction( "CC" ); // int 3
+ break;
+ case OP(ENTER):
+ emitInstruction( "81 EE" ); // sub esi, 0x12345678
+ emit4( constant4() );
+ break;
+ case OP(CONST):
+ if (rom[pc].Operation == OP(LOAD4))
+ {
+ emitAddEDI4();
+ emitInstruction( "BB" ); // mov ebx, 0x12345678
+ emit4( (constant4()&ramMask) + (int)ram);
+ emitInstruction( "8B 03" ); // mov eax, dword ptr [ebx]
+ emitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
+ pc++; // OP(LOAD4)
+ instruction += 1;
+ break;
+ }
+ if (rom[pc].Operation == OP(LOAD2))
+ {
+ emitAddEDI4();
+ emitInstruction( "BB" ); // mov ebx, 0x12345678
+ emit4( (constant4()&ramMask) + (int)ram);
+ emitInstruction( "0F B7 03" ); // movzx eax, word ptr [ebx]
+ emitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
+ pc++; // OP(LOAD4)
+ instruction += 1;
+ break;
+ }
+ if (rom[pc].Operation == OP(LOAD1))
+ {
+ emitAddEDI4();
+ emitInstruction( "BB" ); // mov ebx, 0x12345678
+ emit4( (constant4()&ramMask) + (int)ram);
+ emitInstruction( "0F B6 03" ); // movzx eax, byte ptr [ebx]
+ emitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
+ pc++; // OP(LOAD4)
+ instruction += 1;
+ break;
+ }
+ if (rom[pc].Operation == OP(STORE4))
+ {
+ opt = emitMovEBXEDI((ramMask & ~3));
+ emitInstruction( "B8" ); // mov eax, 0x12345678
+ emit4( constant4() );
+ // if (!opt) {
+ // emitInstruction( "81 E3" ); // and ebx, 0x12345678
+ // emit4( ramMask & ~3 );
+ // }
+ emitInstruction( "89 83" ); // mov dword ptr [ebx+0x12345678], eax
+ emit4( (int)ram );
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ pc++; // OP(STORE4)
+ instruction += 1;
+ break;
+ }
+ if (rom[pc].Operation == OP(STORE2))
+ {
+ opt = emitMovEBXEDI((ramMask & ~1));
+ emitInstruction( "B8" ); // mov eax, 0x12345678
+ emit4( constant4() );
+ // if (!opt) {
+ // emitInstruction( "81 E3" ); // and ebx, 0x12345678
+ // emit4( ramMask & ~1 );
+ // }
+ emitInstruction( "66 89 83" ); // mov word ptr [ebx+0x12345678], eax
+ emit4( (int)ram );
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ pc++; // OP(STORE4)
+ instruction += 1;
+ break;
+ }
+ if (rom[pc].Operation == OP(STORE1))
+ {
+ opt = emitMovEBXEDI(ramMask);
+ emitInstruction( "B8" ); // mov eax, 0x12345678
+ emit4( constant4() );
+ // if (!opt) {
+ // emitInstruction( "81 E3" ); // and ebx, 0x12345678
+ // emit4( ramMask );
+ // }
+ emitInstruction( "88 83" ); // mov byte ptr [ebx+0x12345678], eax
+ emit4( (int)ram );
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ pc++; // OP(STORE4)
+ instruction += 1;
+ break;
+ }
+ if (rom[pc].Operation == OP(ADD))
+ {
+ emitInstruction( "81 07" ); // add dword ptr [edi], 0x1234567
+ emit4( constant4() );
+ pc++; // OP(ADD)
+ instruction += 1;
+ break;
+ }
+ if (rom[pc].Operation == OP(SUB))
+ {
+ emitInstruction( "81 2F" ); // sub dword ptr [edi], 0x1234567
+ emit4( constant4() );
+ pc++; // OP(ADD)
+ instruction += 1;
+ break;
+ }
+ emitAddEDI4();
+ emitInstruction( "C7 07" ); // mov dword ptr [edi], 0x12345678
+ lastConst = constant4();
+ emit4( lastConst );
+ if (rom[pc].Operation == OP(JUMP))
+ {
+ jused[lastConst] = 1;
+ }
+ break;
+ case OP(LOCAL):
+ emitAddEDI4();
+ emitInstruction( "8D 86" ); // lea eax, [0x12345678 + esi]
+ oc0 = oc1;
+ oc1 = constant4();
+ emit4( oc1 );
+ emitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
+ break;
+ case OP(ARG):
+ emitMovEAXEDI(); // mov eax,dword ptr [edi]
+ emitInstruction( "89 86" ); // mov dword ptr [esi+ram],eax
+ // FIXME: range check
+ emit4( constant1() + (int)ram );
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ break;
+ case OP(CALL):
+ emitInstruction( "C7 86" ); // mov dword ptr [esi+ram],0x12345678
+ emit4( (int)ram );
+ emit4( pc );
+ emitInstruction( "FF 15" ); // call asmCallPtr
+ //emit4( (int)&asmCallPtr );
+ emit4(0);
+ break;
+ case OP(PUSH):
+ emitAddEDI4();
+ break;
+ case OP(POP):
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ break;
+ case OP(LEAVE):
+ v = constant4();
+ emitInstruction( "81 C6" ); // add esi, 0x12345678
+ emit4( v );
+ emitInstruction( "C3" ); // ret
+ break;
+ case OP(LOAD4):
+ if (rom[pc].Operation == OP(CONST) && rom[pc+1].Operation == OP(ADD) && rom[pc+2].Operation == OP(STORE4))
+ {
+ if (oc0 == oc1 && pop0 == OP(LOCAL) && pop1 == OP(LOCAL))
+ {
+ compiledOfs -= 11;
+ instructionPointers[ instruction-1 ] = compiledOfs;
+ }
+ pc++; // OP(CONST)
+ v = constant4();
+ emitMovEBXEDI(ramMask);
+ if (v == 1 && oc0 == oc1 && pop0 == OP(LOCAL) && pop1 == OP(LOCAL))
+ {
+ emitInstruction( "FF 83"); // inc dword ptr [ebx + 0x12345678]
+ emit4( (int)ram );
+ }
+ else
+ {
+ emitInstruction( "8B 83" ); // mov eax, dword ptr [ebx + 0x12345678]
+ emit4( (int)ram );
+ emitInstruction( "05" ); // add eax, const
+ emit4( v );
+ if (oc0 == oc1 && pop0 == OP(LOCAL) && pop1 == OP(LOCAL))
+ {
+ emitInstruction( "89 83" ); // mov dword ptr [ebx+0x12345678], eax
+ emit4( (int)ram );
+ }
+ else
+ {
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ emitInstruction( "8B 1F" ); // mov ebx, dword ptr [edi]
+ emitInstruction( "89 83" ); // mov dword ptr [ebx+0x12345678], eax
+ emit4( (int)ram );
+ }
+ }
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ pc++; // OP(ADD)
+ pc++; // OP(STORE)
+ instruction += 3;
+ break;
+ }
+
+ if (rom[pc].Operation == OP(CONST) && rom[pc+1].Operation == OP(SUB) && rom[pc+2].Operation == OP(STORE4))
+ {
+ if (oc0 == oc1 && pop0 == OP(LOCAL) && pop1 == OP(LOCAL)) {
+ compiledOfs -= 11;
+ instructionPointers[ instruction-1 ] = compiledOfs;
+ }
+ emitMovEBXEDI(ramMask);
+ emitInstruction( "8B 83" ); // mov eax, dword ptr [ebx + 0x12345678]
+ emit4( (int)ram );
+ pc++; // OP(CONST)
+ v = constant4();
+ if (v == 1 && oc0 == oc1 && pop0 == OP(LOCAL) && pop1 == OP(LOCAL))
+ {
+ emitInstruction( "FF 8B"); // dec dword ptr [ebx + 0x12345678]
+ emit4( (int)ram );
+ }
+ else
+ {
+ emitInstruction( "2D" ); // sub eax, const
+ emit4( v );
+ if (oc0 == oc1 && pop0 == OP(LOCAL) && pop1 == OP(LOCAL))
+ {
+ emitInstruction( "89 83" ); // mov dword ptr [ebx+0x12345678], eax
+ emit4( (int)ram );
+ }
+ else
+ {
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ emitInstruction( "8B 1F" ); // mov ebx, dword ptr [edi]
+ emitInstruction( "89 83" ); // mov dword ptr [ebx+0x12345678], eax
+ emit4( (int)ram );
+ }
+ }
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ pc++; // OP(SUB)
+ pc++; // OP(STORE)
+ instruction += 3;
+ break;
+ }
+
+ if (buf[compiledOfs-2] == 0x89 && buf[compiledOfs-1] == 0x07)
+ {
+ compiledOfs -= 2;
+ instructionPointers[ instruction-1 ] = compiledOfs;
+ emitInstruction( "8B 80"); // mov eax, dword ptr [eax + 0x1234567]
+ emit4( (int)ram );
+ emitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
+ break;
+ }
+ emitMovEBXEDI(ramMask);
+ emitInstruction( "8B 83" ); // mov eax, dword ptr [ebx + 0x12345678]
+ emit4( (int)ram );
+ emitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
+ break;
+ case OP(LOAD2):
+ emitMovEBXEDI(ramMask);
+ emitInstruction( "0F B7 83" ); // movzx eax, word ptr [ebx + 0x12345678]
+ emit4( (int)ram );
+ emitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
+ break;
+ case OP(LOAD1):
+ emitMovEBXEDI(ramMask);
+ emitInstruction( "0F B6 83" ); // movzx eax, byte ptr [ebx + 0x12345678]
+ emit4( (int)ram );
+ emitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
+ break;
+ case OP(STORE4):
+ emitMovEAXEDI();
+ emitInstruction( "8B 5F FC" ); // mov ebx, dword ptr [edi-4]
+ // if (pop1 != OP(CALL)) {
+ // emitInstruction( "81 E3" ); // and ebx, 0x12345678
+ // emit4( ramMask & ~3 );
+ // }
+ emitInstruction( "89 83" ); // mov dword ptr [ebx+0x12345678], eax
+ emit4( (int)ram );
+ emitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ break;
+ case OP(STORE2):
+ emitMovEAXEDI();
+ emitInstruction( "8B 5F FC" ); // mov ebx, dword ptr [edi-4]
+ // emitInstruction( "81 E3" ); // and ebx, 0x12345678
+ // emit4( ramMask & ~1 );
+ emitInstruction( "66 89 83" ); // mov word ptr [ebx+0x12345678], eax
+ emit4( (int)ram );
+ emitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ break;
+ case OP(STORE1):
+ emitMovEAXEDI();
+ emitInstruction( "8B 5F FC" ); // mov ebx, dword ptr [edi-4]
+ // emitInstruction( "81 E3" ); // and ebx, 0x12345678
+ // emit4( ramMask );
+ emitInstruction( "88 83" ); // mov byte ptr [ebx+0x12345678], eax
+ emit4( (int)ram );
+ emitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ break;
+
+ case OP(EQ):
+ emitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ emitInstruction( "8B 47 04" ); // mov eax, dword ptr [edi+4]
+ emitInstruction( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
+ emitInstruction( "75 06" ); // jne +6
+ emitInstruction( "FF 25" ); // jmp [0x12345678]
+ v = constant4();
+ jused[v] = 1;
+ emit4( (int)instructionPointers + v*4 );
+ break;
+ case OP(NE):
+ emitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ emitInstruction( "8B 47 04" ); // mov eax, dword ptr [edi+4]
+ emitInstruction( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
+ emitInstruction( "74 06" ); // je +6
+ emitInstruction( "FF 25" ); // jmp [0x12345678]
+ v = constant4();
+ jused[v] = 1;
+ emit4( (int)instructionPointers + v*4 );
+ break;
+ case OP(LTI):
+ emitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ emitInstruction( "8B 47 04" ); // mov eax, dword ptr [edi+4]
+ emitInstruction( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
+ emitInstruction( "7D 06" ); // jnl +6
+ emitInstruction( "FF 25" ); // jmp [0x12345678]
+ v = constant4();
+ jused[v] = 1;
+ emit4( (int)instructionPointers + v*4 );
+ break;
+ case OP(LEI):
+ emitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ emitInstruction( "8B 47 04" ); // mov eax, dword ptr [edi+4]
+ emitInstruction( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
+ emitInstruction( "7F 06" ); // jnle +6
+ emitInstruction( "FF 25" ); // jmp [0x12345678]
+ v = constant4();
+ jused[v] = 1;
+ emit4( (int)instructionPointers + v*4 );
+ break;
+ case OP(GTI):
+ emitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ emitInstruction( "8B 47 04" ); // mov eax, dword ptr [edi+4]
+ emitInstruction( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
+ emitInstruction( "7E 06" ); // jng +6
+ emitInstruction( "FF 25" ); // jmp [0x12345678]
+ v = constant4();
+ jused[v] = 1;
+ emit4( (int)instructionPointers + v*4 );
+ break;
+ case OP(GEI):
+ emitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ emitInstruction( "8B 47 04" ); // mov eax, dword ptr [edi+4]
+ emitInstruction( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
+ emitInstruction( "7C 06" ); // jnge +6
+ emitInstruction( "FF 25" ); // jmp [0x12345678]
+ v = constant4();
+ jused[v] = 1;
+ emit4( (int)instructionPointers + v*4 );
+ break;
+ case OP(LTU):
+ emitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ emitInstruction( "8B 47 04" ); // mov eax, dword ptr [edi+4]
+ emitInstruction( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
+ emitInstruction( "73 06" ); // jnb +6
+ emitInstruction( "FF 25" ); // jmp [0x12345678]
+ v = constant4();
+ jused[v] = 1;
+ emit4( (int)instructionPointers + v*4 );
+ break;
+ case OP(LEU):
+ emitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ emitInstruction( "8B 47 04" ); // mov eax, dword ptr [edi+4]
+ emitInstruction( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
+ emitInstruction( "77 06" ); // jnbe +6
+ emitInstruction( "FF 25" ); // jmp [0x12345678]
+ v = constant4();
+ jused[v] = 1;
+ emit4( (int)instructionPointers + v*4 );
+ break;
+ case OP(GTU):
+ emitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ emitInstruction( "8B 47 04" ); // mov eax, dword ptr [edi+4]
+ emitInstruction( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
+ emitInstruction( "76 06" ); // jna +6
+ emitInstruction( "FF 25" ); // jmp [0x12345678]
+ v = constant4();
+ jused[v] = 1;
+ emit4( (int)instructionPointers + v*4 );
+ break;
+ case OP(GEU):
+ emitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ emitInstruction( "8B 47 04" ); // mov eax, dword ptr [edi+4]
+ emitInstruction( "3B 47 08" ); // cmp eax, dword ptr [edi+8]
+ emitInstruction( "72 06" ); // jnae +6
+ emitInstruction( "FF 25" ); // jmp [0x12345678]
+ v = constant4();
+ jused[v] = 1;
+ emit4( (int)instructionPointers + v*4 );
+ break;
+ case OP(EQF):
+ emitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ emitInstruction( "D9 47 04" ); // fld dword ptr [edi+4]
+ emitInstruction( "D8 5F 08" ); // fcomp dword ptr [edi+8]
+ emitInstruction( "DF E0" ); // fnstsw ax
+ emitInstruction( "F6 C4 40" ); // test ah,0x40
+ emitInstruction( "74 06" ); // je +6
+ emitInstruction( "FF 25" ); // jmp [0x12345678]
+ v = constant4();
+ jused[v] = 1;
+ emit4( (int)instructionPointers + v*4 );
+ break;
+ case OP(NEF):
+ emitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ emitInstruction( "D9 47 04" ); // fld dword ptr [edi+4]
+ emitInstruction( "D8 5F 08" ); // fcomp dword ptr [edi+8]
+ emitInstruction( "DF E0" ); // fnstsw ax
+ emitInstruction( "F6 C4 40" ); // test ah,0x40
+ emitInstruction( "75 06" ); // jne +6
+ emitInstruction( "FF 25" ); // jmp [0x12345678]
+ v = constant4();
+ jused[v] = 1;
+ emit4( (int)instructionPointers + v*4 );
+ break;
+ case OP(LTF):
+ emitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ emitInstruction( "D9 47 04" ); // fld dword ptr [edi+4]
+ emitInstruction( "D8 5F 08" ); // fcomp dword ptr [edi+8]
+ emitInstruction( "DF E0" ); // fnstsw ax
+ emitInstruction( "F6 C4 01" ); // test ah,0x01
+ emitInstruction( "74 06" ); // je +6
+ emitInstruction( "FF 25" ); // jmp [0x12345678]
+ v = constant4();
+ jused[v] = 1;
+ emit4( (int)instructionPointers + v*4 );
+ break;
+ case OP(LEF):
+ emitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ emitInstruction( "D9 47 04" ); // fld dword ptr [edi+4]
+ emitInstruction( "D8 5F 08" ); // fcomp dword ptr [edi+8]
+ emitInstruction( "DF E0" ); // fnstsw ax
+ emitInstruction( "F6 C4 41" ); // test ah,0x41
+ emitInstruction( "74 06" ); // je +6
+ emitInstruction( "FF 25" ); // jmp [0x12345678]
+ v = constant4();
+ jused[v] = 1;
+ emit4( (int)instructionPointers + v*4 );
+ break;
+ case OP(GTF):
+ emitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ emitInstruction( "D9 47 04" ); // fld dword ptr [edi+4]
+ emitInstruction( "D8 5F 08" ); // fcomp dword ptr [edi+8]
+ emitInstruction( "DF E0" ); // fnstsw ax
+ emitInstruction( "F6 C4 41" ); // test ah,0x41
+ emitInstruction( "75 06" ); // jne +6
+ emitInstruction( "FF 25" ); // jmp [0x12345678]
+ v = constant4();
+ jused[v] = 1;
+ emit4( (int)instructionPointers + v*4 );
+ break;
+ case OP(GEF):
+ emitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ emitInstruction( "D9 47 04" ); // fld dword ptr [edi+4]
+ emitInstruction( "D8 5F 08" ); // fcomp dword ptr [edi+8]
+ emitInstruction( "DF E0" ); // fnstsw ax
+ emitInstruction( "F6 C4 01" ); // test ah,0x01
+ emitInstruction( "75 06" ); // jne +6
+ emitInstruction( "FF 25" ); // jmp [0x12345678]
+ v = constant4();
+ jused[v] = 1;
+ emit4( (int)instructionPointers + v*4 );
+ break;
+ case OP(NEGI):
+ emitInstruction( "F7 1F" ); // neg dword ptr [edi]
+ break;
+ case OP(ADD):
+ emitMovEAXEDI(); // mov eax, dword ptr [edi]
+ emitInstruction( "01 47 FC" ); // add dword ptr [edi-4],eax
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ break;
+ case OP(SUB):
+ emitMovEAXEDI(); // mov eax, dword ptr [edi]
+ emitInstruction( "29 47 FC" ); // sub dword ptr [edi-4],eax
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ break;
+ case OP(DIVI):
+ emitInstruction( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
+ emitInstruction( "99" ); // cdq
+ emitInstruction( "F7 3F" ); // idiv dword ptr [edi]
+ emitInstruction( "89 47 FC" ); // mov dword ptr [edi-4],eax
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ break;
+ case OP(DIVU):
+ emitInstruction( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
+ emitInstruction( "33 D2" ); // xor edx, edx
+ emitInstruction( "F7 37" ); // div dword ptr [edi]
+ emitInstruction( "89 47 FC" ); // mov dword ptr [edi-4],eax
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ break;
+ case OP(MODI):
+ emitInstruction( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
+ emitInstruction( "99" ); // cdq
+ emitInstruction( "F7 3F" ); // idiv dword ptr [edi]
+ emitInstruction( "89 57 FC" ); // mov dword ptr [edi-4],edx
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ break;
+ case OP(MODU):
+ emitInstruction( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
+ emitInstruction( "33 D2" ); // xor edx, edx
+ emitInstruction( "F7 37" ); // div dword ptr [edi]
+ emitInstruction( "89 57 FC" ); // mov dword ptr [edi-4],edx
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ break;
+ case OP(MULI):
+ emitInstruction( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
+ emitInstruction( "F7 2F" ); // imul dword ptr [edi]
+ emitInstruction( "89 47 FC" ); // mov dword ptr [edi-4],eax
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ break;
+ case OP(MULU):
+ emitInstruction( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
+ emitInstruction( "F7 27" ); // mul dword ptr [edi]
+ emitInstruction( "89 47 FC" ); // mov dword ptr [edi-4],eax
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ break;
+ case OP(BAND):
+ emitMovEAXEDI(); // mov eax, dword ptr [edi]
+ emitInstruction( "21 47 FC" ); // and dword ptr [edi-4],eax
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ break;
+ case OP(BOR):
+ emitMovEAXEDI(); // mov eax, dword ptr [edi]
+ emitInstruction( "09 47 FC" ); // or dword ptr [edi-4],eax
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ break;
+ case OP(BXOR):
+ emitMovEAXEDI(); // mov eax, dword ptr [edi]
+ emitInstruction( "31 47 FC" ); // xor dword ptr [edi-4],eax
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ break;
+ case OP(BCOM):
+ emitInstruction( "F7 17" ); // not dword ptr [edi]
+ break;
+ case OP(LSH):
+ emitInstruction( "8B 0F" ); // mov ecx, dword ptr [edi]
+ emitInstruction( "D3 67 FC" ); // shl dword ptr [edi-4], cl
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ break;
+ case OP(RSHI):
+ emitInstruction( "8B 0F" ); // mov ecx, dword ptr [edi]
+ emitInstruction( "D3 7F FC" ); // sar dword ptr [edi-4], cl
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ break;
+ case OP(RSHU):
+ emitInstruction( "8B 0F" ); // mov ecx, dword ptr [edi]
+ emitInstruction( "D3 6F FC" ); // shr dword ptr [edi-4], cl
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ break;
+ case OP(NEGF):
+ emitInstruction( "D9 07" ); // fld dword ptr [edi]
+ emitInstruction( "D9 E0" ); // fchs
+ emitInstruction( "D9 1F" ); // fstp dword ptr [edi]
+ break;
+ case OP(ADDF):
+ emitInstruction( "D9 47 FC" ); // fld dword ptr [edi-4]
+ emitInstruction( "D8 07" ); // fadd dword ptr [edi]
+ emitInstruction( "D9 5F FC" ); // fstp dword ptr [edi-4]
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ break;
+ case OP(SUBF):
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ emitInstruction( "D9 07" ); // fld dword ptr [edi]
+ emitInstruction( "D8 67 04" ); // fsub dword ptr [edi+4]
+ emitInstruction( "D9 1F" ); // fstp dword ptr [edi]
+ break;
+ case OP(DIVF):
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ emitInstruction( "D9 07" ); // fld dword ptr [edi]
+ emitInstruction( "D8 77 04" ); // fdiv dword ptr [edi+4]
+ emitInstruction( "D9 1F" ); // fstp dword ptr [edi]
+ break;
+ case OP(MULF):
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ emitInstruction( "D9 07" ); // fld dword ptr [edi]
+ emitInstruction( "D8 4f 04" ); // fmul dword ptr [edi+4]
+ emitInstruction( "D9 1F" ); // fstp dword ptr [edi]
+ break;
+ case OP(CVIF):
+ emitInstruction( "DB 07" ); // fild dword ptr [edi]
+ emitInstruction( "D9 1F" ); // fstp dword ptr [edi]
+ break;
+ case OP(CVFI):
+ #ifndef FTOL_PTR // WHENHELLISFROZENOVER // bk001213 - was used in 1.17
+ // not IEEE complient, but simple and fast
+ emitInstruction( "D9 07" ); // fld dword ptr [edi]
+ emitInstruction( "DB 1F" ); // fistp dword ptr [edi]
+ #else // FTOL_PTR
+ // call the library conversion function
+ emitInstruction( "D9 07" ); // fld dword ptr [edi]
+ emitInstruction( "FF 15" ); // call ftolPtr
+ emit4( (int)&ftolPtr );
+ emitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
+ #endif
+ break;
+ case OP(SEX8):
+ emitInstruction( "0F BE 07" ); // movsx eax, byte ptr [edi]
+ emitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
+ break;
+ case OP(SEX16):
+ emitInstruction( "0F BF 07" ); // movsx eax, word ptr [edi]
+ emitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax
+ break;
+
+ case OP(BLOCK_COPY):
+ // FIXME: range check
+ emitInstruction( "56" ); // push esi
+ emitInstruction( "57" ); // push edi
+ emitInstruction( "8B 37" ); // mov esi,[edi]
+ emitInstruction( "8B 7F FC" ); // mov edi,[edi-4]
+ emitInstruction( "B9" ); // mov ecx,0x12345678
+ emit4( constant4() >> 2 );
+ emitInstruction( "B8" ); // mov eax, ramMask
+ emit4( ramMask );
+ emitInstruction( "BB" ); // mov ebx, ram
+ emit4( (int)ram );
+ emitInstruction( "23 F0" ); // and esi, eax
+ emitInstruction( "03 F3" ); // add esi, ebx
+ emitInstruction( "23 F8" ); // and edi, eax
+ emitInstruction( "03 FB" ); // add edi, ebx
+ emitInstruction( "F3 A5" ); // rep movsd
+ emitInstruction( "5F" ); // pop edi
+ emitInstruction( "5E" ); // pop esi
+ emitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8
+ break;
+
+ case OP(JUMP):
+ emitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+ emitInstruction( "8B 47 04" ); // mov eax,dword ptr [edi+4]
+ // FIXME: range check
+ emitInstruction( "FF 24 85" ); // jmp dword ptr [instructionPointers + eax * 4]
+ emit4( (int)instructionPointers );
+ break;
+ default:
+ throw JITException("Compile: bad opcode");
+ }
+ pop0 = pop1;
+ pop1 = op.Operation;
+ }
+ }
+
+ // copy to an exact size buffer on the hunk
+ //codeLength = compiledOfs;
+ //codeBase = Hunk_Alloc( compiledOfs, h_low );
+
+ //Com_Memcpy( codeBase, buf, compiledOfs );
+
+ delete[] buf;
+ delete[] jused;
+
+ //printf( "VM file %s compiled to %i bytes of code\n", name, compiledOfs);
+
+ // offset all the instruction pointers for the new location
+ for ( i = 0 ; i < /*header->instructionCount*/ romSize ; i++ ) {
+ instructionPointers[i] += (int)codeBase;
+ }
+
+ #if 0 // ndef _WIN32
+ // Must make the newly generated code executable
+ {
+ int r;
+ unsigned long addr;
+ int psize = getpagesize();
+
+ addr = ((int)codeBase & ~(psize-1)) - psize;
+
+ r = mprotect((char*)addr, codeLength + (int)codeBase - addr + psize,
+ PROT_READ | PROT_WRITE | PROT_EXEC );
+
+ if (r < 0)
+ Com_Error( ERR_FATAL, "mprotect failed to change PROT_EXEC" );
+ }
+ #endif
+
+ }
+
+ int VirtualMachine::constant4()
+ {
+ int v;
+
+ v = rom[pc-1].Parameter.int4;// | (rom[pc-1].Parameter<<8) | (rom[pc-1].Parameter<<16) | (rom[pc-1].Parameter<<24);
+ return v;
+ }
+
+ int VirtualMachine::constant1()
+ {
+ int v;
+
+ v = rom[pc-1].Parameter.uint1;
+ return v;
+ }
+
+ void VirtualMachine::emit1(int v)
+ {
+ buf[compiledOfs] = v;
+ compiledOfs++;
+
+ LastCommand = LAST_COMMAND_NONE;
+ }
+
+ void VirtualMachine::emit4(int v)
+ {
+ emit1(v & 255);
+ emit1((v >> 8) & 255);
+ emit1((v >> 16) & 255);
+ emit1((v >> 24) & 255);
+ }
+
+ void VirtualMachine::emitInstruction(const char *string)
+ {
+ int c1, c2;
+ int v;
+
+ while (true)
+ {
+ c1 = string[0];
+ c2 = string[1];
+
+ v = (hex( c1 ) << 4) | hex(c2);
+ emit1( v );
+
+ if (!string[2])
+ {
+ break;
+ }
+ string += 3;
+ }
+ }
+
+ void VirtualMachine::emitCommand(int command_)
+ {
+ ELastCommand command = (ELastCommand)command_;
+ switch(command)
+ {
+ case LAST_COMMAND_MOV_EDI_EAX:
+ emitInstruction( "89 07" ); // mov dword ptr [edi], eax
+ break;
+ case LAST_COMMAND_SUB_DI_4:
+ emitInstruction( "83 EF 04" ); // sub edi, 4
+ break;
+ case LAST_COMMAND_SUB_DI_8:
+ emitInstruction( "83 EF 08" ); // sub edi, 8
+ break;
+ default:
+ break;
+ }
+ LastCommand = command;
+ }
+
+ void VirtualMachine::emitAddEDI4()
+ {
+ if (LastCommand == LAST_COMMAND_SUB_DI_4 && jused[instruction-1] == 0)
+ { // sub di,4
+ compiledOfs -= 3;
+ instructionPointers[ instruction-1 ] = compiledOfs;
+ return;
+ }
+ if (LastCommand == LAST_COMMAND_SUB_DI_8 && jused[instruction-1] == 0)
+ { // sub di,8
+ compiledOfs -= 3;
+ instructionPointers[ instruction-1 ] = compiledOfs;
+ emitInstruction( "83 EF 04" ); // sub edi,4
+ return;
+ }
+ emitInstruction( "83 C7 04" ); // add edi,4
+ }
+
+ void VirtualMachine::emitMovEAXEDI()
+ {
+ if (LastCommand == LAST_COMMAND_MOV_EDI_EAX)
+ { // mov [edi], eax
+ compiledOfs -= 2;
+ instructionPointers[ instruction-1 ] = compiledOfs;
+ return;
+ }
+ if (pop1 == OP(DIVI) || pop1 == OP(DIVU) || pop1 == OP(MULI) || pop1 == OP(MULU) || pop1 == OP(STORE4) || pop1 == OP(STORE2) || pop1 == OP(STORE1) )
+ {
+ return;
+ }
+ if (pop1 == OP(CONST) && buf[compiledOfs-6] == 0xC7 && buf[compiledOfs-5] == 0x07)
+ { // mov edi, 0x123456
+ compiledOfs -= 6;
+ instructionPointers[ instruction-1 ] = compiledOfs;
+ emitInstruction( "B8" ); // mov eax, 0x12345678
+ emit4( lastConst );
+ return;
+ }
+ emitInstruction( "8B 07" ); // mov eax, dword ptr [edi]
+ }
+
+ bool VirtualMachine::emitMovEBXEDI(int andit)
+ {
+ if (LastCommand == LAST_COMMAND_MOV_EDI_EAX)
+ { // mov [edi], eax
+ compiledOfs -= 2;
+ instructionPointers[ instruction-1 ] = compiledOfs;
+ emitInstruction( "8B D8"); // mov bx, eax
+ return false;
+ }
+ if (pop1 == OP(DIVI) || pop1 == OP(DIVU) || pop1 == OP(MULI) || pop1 == OP(MULU) || pop1 == OP(STORE4) || pop1 == OP(STORE2) || pop1 == OP(STORE1) )
+ {
+ emitInstruction( "8B D8"); // mov bx, eax
+ return false;
+ }
+ if (pop1 == OP(CONST) && buf[compiledOfs-6] == 0xC7 && buf[compiledOfs-5] == 0x07 )
+ { // mov edi, 0x123456
+ compiledOfs -= 6;
+ instructionPointers[ instruction-1 ] = compiledOfs;
+ emitInstruction( "BB" ); // mov ebx, 0x12345678
+ if (andit) {
+ emit4( lastConst & andit );
+ } else {
+ emit4( lastConst );
+ }
+ return true;
+ }
+
+ emitInstruction( "8B 1F" ); // mov ebx, dword ptr [edi]
+ return false;
+ }
+
+ int VirtualMachine::hex(int c)
+ {
+ if (c >= 'a' && c <= 'f')
+ return 10 + c - 'a';
+ if (c >= 'A' && c <= 'F')
+ return 10 + c - 'A';
+ if (c >= '0' && c <= '9')
+ return c - '0';
+
+ throw JITException("hex: bad character");
+
+ return 0;
+ }
+
+ #undef OP
+} \ No newline at end of file