- Fix SEGV in while loop getop() after t = b = 0

- Fix iss8, iss16 and iss32 which would not correctly detect 32-bit signed integer range
- Add support for "addb", "subb" etc. assembler mnemonic
- Change opStack protection for x86_64 VM: No overflow checks necessary anymore as offset register is 1 byte long only
This commit is contained in:
Thilo Schulz 2011-05-16 17:55:07 +00:00
parent 558ed62771
commit 5aa3da2f84
2 changed files with 189 additions and 196 deletions

View file

@ -71,13 +71,13 @@ static void VM_Destroy_Compiled(vm_t* self);
+- r8 +- r8
eax scratch eax scratch
ebx scratch bl opStack offset
ecx scratch (required for shifts) ecx scratch (required for shifts)
edx scratch (required for divisions) edx scratch (required for divisions)
rsi opStack offset rsi scratch
rdi program frame pointer (programStack) rdi program frame pointer (programStack)
r8 pointer data (vm->dataBase) r8 pointer data (vm->dataBase)
r9 opStack data base (opStack) r9 opStack data base (vm->opStack + OPSTACK_SIZE / 2)
r10 start of generated code r10 start of generated code
*/ */
@ -248,33 +248,19 @@ void emit(const char* fmt, ...)
emit("movq $%"PRIu64", %%rax", (intptr_t) memviolation); \ emit("movq $%"PRIu64", %%rax", (intptr_t) memviolation); \
emit("callq *%%rax"); \ emit("callq *%%rax"); \
emit("rc_ok_i_%08x:", instruction) emit("rc_ok_i_%08x:", instruction)
#define OPSTACKCHECK() \
emit("movl %%esi, %%ecx"); \
emit("andl $0x%x, %%ecx", OPSTACK_MASK & ~0x03); \
emit("cmpl %%esi, %%ecx"); \
emit("jz oc_ok_i_%08x", instruction); \
emit("movq $%"PRIu64", %%rax", (intptr_t) opstackviolation); \
emit("callq *%%rax"); \
emit("oc_ok_i_%08x:", instruction)
#elif 1 #elif 1
// check is too expensive, so just confine memory access // check is too expensive, so just confine memory access
#define RANGECHECK(reg, bytes) \ #define RANGECHECK(reg, bytes) \
emit("andl $0x%x, %%" #reg, vm->dataMask &~(bytes-1)) emit("andl $0x%x, %%" #reg, vm->dataMask &~(bytes-1))
#define OPSTACKCHECK() \
emit("andl $0x%x, %%esi", OPSTACK_MASK & ~0x03)
#else #else
#define RANGECHECK(reg, bytes) #define RANGECHECK(reg, bytes)
#endif #endif
#define STACK_PUSH(bytes) \ #define STACK_PUSH(bytes) \
emit("addl $0x%x, %%esi", bytes); \ emit("addb $0x%x, %%bl", bytes); \
OPSTACKCHECK()
#define STACK_POP(bytes) \ #define STACK_POP(bytes) \
emit("subl $0x%x, %%esi", bytes); \ emit("subb $0x%x, %%bl", bytes); \
OPSTACKCHECK()
#define CHECK_INSTR_REG(reg) \ #define CHECK_INSTR_REG(reg) \
emit("cmpl $%u, %%"#reg, header->instructionCount); \ emit("cmpl $%u, %%"#reg, header->instructionCount); \
@ -285,8 +271,8 @@ void emit(const char* fmt, ...)
#define PREPARE_JMP(reg) \ #define PREPARE_JMP(reg) \
CHECK_INSTR_REG(reg); \ CHECK_INSTR_REG(reg); \
emit("movq $%"PRIu64", %%rbx", (intptr_t)vm->instructionPointers); \ emit("movq $%"PRIu64", %%rsi", (intptr_t)vm->instructionPointers); \
emit("movl (%%rbx, %%rax, 4), %%eax"); \ emit("movl (%%rsi, %%rax, 4), %%eax"); \
emit("addq %%r10, %%rax") emit("addq %%r10, %%rax")
#define CHECK_INSTR(nr) \ #define CHECK_INSTR(nr) \
@ -309,7 +295,7 @@ void emit(const char* fmt, ...)
got_const = 0; \ got_const = 0; \
vm->instructionPointers[instruction-1] = assembler_get_code_size(); \ vm->instructionPointers[instruction-1] = assembler_get_code_size(); \
STACK_PUSH(4); \ STACK_PUSH(4); \
emit("movl $%d, 0(%%r9, %%rsi, 1)", const_value); \ emit("movl $%d, (%%r9, %%rbx, 1)", const_value); \
} }
#else #else
#define MAYBE_EMIT_CONST() #define MAYBE_EMIT_CONST()
@ -319,8 +305,8 @@ void emit(const char* fmt, ...)
#define IJ(op) \ #define IJ(op) \
MAYBE_EMIT_CONST(); \ MAYBE_EMIT_CONST(); \
STACK_POP(8); \ STACK_POP(8); \
emit("movl 4(%%r9, %%rsi, 1), %%eax"); \ emit("movl 4(%%r9, %%rbx, 1), %%eax"); \
emit("cmpl 8(%%r9, %%rsi, 1), %%eax"); \ emit("cmpl 8(%%r9, %%rbx, 1), %%eax"); \
emit(op " i_%08x", instruction+1); \ emit(op " i_%08x", instruction+1); \
JMPIARG(); \ JMPIARG(); \
neednilabel = 1 neednilabel = 1
@ -329,8 +315,8 @@ void emit(const char* fmt, ...)
#define FJ(bits, op) \ #define FJ(bits, op) \
MAYBE_EMIT_CONST(); \ MAYBE_EMIT_CONST(); \
STACK_POP(8); \ STACK_POP(8); \
emit("flds 4(%%r9, %%rsi, 1)");\ emit("flds 4(%%r9, %%rbx, 1)");\
emit("fcomps 8(%%r9, %%rsi, 1)");\ emit("fcomps 8(%%r9, %%rbx, 1)");\
emit("fnstsw %%ax");\ emit("fnstsw %%ax");\
emit("testb $" #bits ", %%ah");\ emit("testb $" #bits ", %%ah");\
emit(op " i_%08x", instruction+1);\ emit(op " i_%08x", instruction+1);\
@ -342,8 +328,8 @@ void emit(const char* fmt, ...)
#define XJ(op) \ #define XJ(op) \
MAYBE_EMIT_CONST(); \ MAYBE_EMIT_CONST(); \
STACK_POP(8); \ STACK_POP(8); \
emit("movss 4(%%r9, %%rsi, 1), %%xmm0");\ emit("movss 4(%%r9, %%rbx, 1), %%xmm0");\
emit("ucomiss 8(%%r9, %%rsi, 1), %%xmm0");\ emit("ucomiss 8(%%r9, %%rbx, 1), %%xmm0");\
emit("jp i_%08x", instruction+1);\ emit("jp i_%08x", instruction+1);\
emit(op " i_%08x", instruction+1);\ emit(op " i_%08x", instruction+1);\
JMPIARG(); \ JMPIARG(); \
@ -352,35 +338,35 @@ void emit(const char* fmt, ...)
#define SIMPLE(op) \ #define SIMPLE(op) \
MAYBE_EMIT_CONST(); \ MAYBE_EMIT_CONST(); \
emit("movl 0(%%r9, %%rsi, 1), %%eax"); \ emit("movl (%%r9, %%rbx, 1), %%eax"); \
STACK_POP(4); \ STACK_POP(4); \
emit(op " %%eax, 0(%%r9, %%rsi, 1)") emit(op " %%eax, (%%r9, %%rbx, 1)")
#ifdef USE_X87 #ifdef USE_X87
#define FSIMPLE(op) \ #define FSIMPLE(op) \
MAYBE_EMIT_CONST(); \ MAYBE_EMIT_CONST(); \
STACK_POP(4); \ STACK_POP(4); \
emit("flds 0(%%r9, %%rsi, 1)"); \ emit("flds (%%r9, %%rbx, 1)"); \
emit(op " 4(%%r9, %%rsi, 1)"); \ emit(op " 4(%%r9, %%rbx, 1)"); \
emit("fstps 0(%%r9, %%rsi, 1)") emit("fstps (%%r9, %%rbx, 1)")
#define XSIMPLE(op) #define XSIMPLE(op)
#else #else
#define FSIMPLE(op) #define FSIMPLE(op)
#define XSIMPLE(op) \ #define XSIMPLE(op) \
MAYBE_EMIT_CONST(); \ MAYBE_EMIT_CONST(); \
STACK_POP(4); \ STACK_POP(4); \
emit("movss 0(%%r9, %%rsi, 1), %%xmm0"); \ emit("movss (%%r9, %%rbx, 1), %%xmm0"); \
emit(op " 4(%%r9, %%rsi, 1), %%xmm0"); \ emit(op " 4(%%r9, %%rbx, 1), %%xmm0"); \
emit("movss %%xmm0, 0(%%r9, %%rsi, 1)") emit("movss %%xmm0, (%%r9, %%rbx, 1)")
#endif #endif
#define SHIFT(op) \ #define SHIFT(op) \
MAYBE_EMIT_CONST(); \ MAYBE_EMIT_CONST(); \
STACK_POP(4); \ STACK_POP(4); \
emit("movl 4(%%r9, %%rsi, 1), %%ecx"); \ emit("movl 4(%%r9, %%rbx, 1), %%ecx"); \
emit("movl 0(%%r9, %%rsi, 1), %%eax"); \ emit("movl (%%r9, %%rbx, 1), %%eax"); \
emit(op " %%cl, %%eax"); \ emit(op " %%cl, %%eax"); \
emit("movl %%eax, 0(%%r9, %%rsi, 1)") emit("movl %%eax, (%%r9, %%rbx, 1)")
#ifdef DEBUG_VM #ifdef DEBUG_VM
#define NOTIMPL(x) \ #define NOTIMPL(x) \
@ -562,7 +548,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
break; break;
case OP_CALL: case OP_CALL:
RANGECHECK(edi, 4); RANGECHECK(edi, 4);
emit("movl $%d, 0(%%r8, %%rdi, 1)", instruction+1); // save next instruction emit("movl $%d, (%%r8, %%rdi, 1)", instruction+1); // save next instruction
if(got_const) if(got_const)
{ {
@ -578,7 +564,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
else else
{ {
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
emit("movl 0(%%r9, %%rsi, 1), %%eax"); // get instr from stack emit("movl (%%r9, %%rbx, 1), %%eax"); // get instr from stack
STACK_POP(4); STACK_POP(4);
emit("orl %%eax, %%eax"); emit("orl %%eax, %%eax");
@ -592,16 +578,15 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
} }
// emit("fnsave 4(%%r9, %%rsi, 1)"); // emit("fnsave 4(%%r9, %%rsi, 1)");
emit("push %%rsi");
emit("push %%rdi"); emit("push %%rdi");
emit("push %%r8"); emit("push %%r8");
emit("push %%r9"); emit("push %%r9");
emit("push %%r10"); emit("push %%r10");
emit("movq %%rsp, %%rbx"); // we need to align the stack pointer emit("movq %%rsp, %%rsi"); // we need to align the stack pointer
emit("subq $8, %%rbx"); // | emit("subq $8, %%rsi"); // |
emit("andq $127, %%rbx"); // | emit("andq $127, %%rsi"); // |
emit("subq %%rbx, %%rsp"); // <-+ emit("subq %%rsi, %%rsp"); // <-+
emit("push %%rbx"); emit("push %%rsi");
if(got_const) { if(got_const) {
got_const = 0; got_const = 0;
emit("movq $%u, %%rsi", -1-const_value); // second argument in rsi emit("movq $%u, %%rsi", -1-const_value); // second argument in rsi
@ -612,16 +597,15 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
} }
emit("movq $%"PRIu64", %%rax", (intptr_t) callAsmCall); emit("movq $%"PRIu64", %%rax", (intptr_t) callAsmCall);
emit("callq *%%rax"); emit("callq *%%rax");
emit("pop %%rbx"); emit("pop %%rsi");
emit("addq %%rbx, %%rsp"); emit("addq %%rsi, %%rsp");
emit("pop %%r10"); emit("pop %%r10");
emit("pop %%r9"); emit("pop %%r9");
emit("pop %%r8"); emit("pop %%r8");
emit("pop %%rdi"); emit("pop %%rdi");
emit("pop %%rsi");
// emit("frstor 4(%%r9, %%rsi, 1)"); // emit("frstor 4(%%r9, %%rsi, 1)");
STACK_PUSH(4); STACK_PUSH(4);
emit("movl %%eax, (%%r9, %%rsi, 1)"); // store return value emit("movl %%eax, (%%r9, %%rbx, 1)"); // store return value
neednilabel = 1; neednilabel = 1;
break; break;
case OP_PUSH: case OP_PUSH:
@ -639,15 +623,15 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
const_value = iarg; const_value = iarg;
#else #else
STACK_PUSH(4); STACK_PUSH(4);
emit("movl $%d, 0(%%r9, %%rsi, 1)", iarg); emit("movl $%d, (%%r9, %%rbx, 1)", iarg);
#endif #endif
break; break;
case OP_LOCAL: case OP_LOCAL:
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
emit("movl %%edi, %%ebx"); emit("movl %%edi, %%esi");
emit("addl $%d,%%ebx", iarg); emit("addl $%d,%%esi", iarg);
STACK_PUSH(4); STACK_PUSH(4);
emit("movl %%ebx, 0(%%r9, %%rsi, 1)"); emit("movl %%esi, (%%r9, %%rbx, 1)");
break; break;
case OP_JUMP: case OP_JUMP:
if(got_const) { if(got_const) {
@ -655,7 +639,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
got_const = 0; got_const = 0;
JMPIARG(); JMPIARG();
} else { } else {
emit("movl 0(%%r9, %%rsi, 1), %%eax"); // get instr from stack emit("movl (%%r9, %%rbx, 1), %%eax"); // get instr from stack
STACK_POP(4); STACK_POP(4);
PREPARE_JMP(eax); PREPARE_JMP(eax);
@ -701,8 +685,8 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
#ifndef USE_X87 #ifndef USE_X87
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
STACK_POP(8); STACK_POP(8);
emit("movss 4(%%r9, %%rsi, 1), %%xmm0"); emit("movss 4(%%r9, %%rbx, 1), %%xmm0");
emit("ucomiss 8(%%r9, %%rsi, 1), %%xmm0"); emit("ucomiss 8(%%r9, %%rbx, 1), %%xmm0");
emit("jp dojump_i_%08x", instruction); emit("jp dojump_i_%08x", instruction);
emit("jz i_%08x", instruction+1); emit("jz i_%08x", instruction+1);
emit("dojump_i_%08x:", instruction); emit("dojump_i_%08x:", instruction);
@ -728,105 +712,103 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
break; break;
case OP_LOAD1: case OP_LOAD1:
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
emit("movl 0(%%r9, %%rsi, 1), %%eax"); // get value from stack emit("movl (%%r9, %%rbx, 1), %%eax"); // get value from stack
RANGECHECK(eax, 1); RANGECHECK(eax, 1);
emit("movb 0(%%r8, %%rax, 1), %%al"); // deref into eax emit("movb (%%r8, %%rax, 1), %%al"); // deref into eax
emit("andq $255, %%rax"); emit("andq $255, %%rax");
emit("movl %%eax, 0(%%r9, %%rsi, 1)"); // store on stack emit("movl %%eax, (%%r9, %%rbx, 1)"); // store on stack
break; break;
case OP_LOAD2: case OP_LOAD2:
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
emit("movl 0(%%r9, %%rsi, 1), %%eax"); // get value from stack emit("movl (%%r9, %%rbx, 1), %%eax"); // get value from stack
RANGECHECK(eax, 2); RANGECHECK(eax, 2);
emit("movw 0(%%r8, %%rax, 1), %%ax"); // deref into eax emit("movw (%%r8, %%rax, 1), %%ax"); // deref into eax
emit("movl %%eax, 0(%%r9, %%rsi, 1)"); // store on stack emit("movl %%eax, (%%r9, %%rbx, 1)"); // store on stack
break; break;
case OP_LOAD4: case OP_LOAD4:
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
emit("movl 0(%%r9, %%rsi, 1), %%eax"); // get value from stack emit("movl (%%r9, %%rbx, 1), %%eax"); // get value from stack
RANGECHECK(eax, 4); // not a pointer!? RANGECHECK(eax, 4); // not a pointer!?
emit("movl 0(%%r8, %%rax, 1), %%eax"); // deref into eax emit("movl (%%r8, %%rax, 1), %%eax"); // deref into eax
emit("movl %%eax, 0(%%r9, %%rsi, 1)"); // store on stack emit("movl %%eax, (%%r9, %%rbx, 1)"); // store on stack
break; break;
case OP_STORE1: case OP_STORE1:
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
emit("movl 0(%%r9, %%rsi, 1), %%eax"); // get value from stack emit("movl (%%r9, %%rbx, 1), %%eax"); // get value from stack
STACK_POP(8); STACK_POP(8);
emit("andq $255, %%rax"); emit("andq $255, %%rax");
emit("movl 4(%%r9, %%rsi, 1), %%ebx"); // get pointer from stack emit("movl 4(%%r9, %%rbx, 1), %%esi"); // get pointer from stack
RANGECHECK(ebx, 1); RANGECHECK(esi, 1);
emit("movb %%al, 0(%%r8, %%rbx, 1)"); // store in memory emit("movb %%al, (%%r8, %%rsi, 1)"); // store in memory
break; break;
case OP_STORE2: case OP_STORE2:
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
emit("movl 0(%%r9, %%rsi, 1), %%eax"); // get value from stack emit("movl (%%r9, %%rbx, 1), %%eax"); // get value from stack
STACK_POP(8); STACK_POP(8);
emit("movl 4(%%r9, %%rsi, 1), %%ebx"); // get pointer from stack emit("movl 4(%%r9, %%rbx, 1), %%esi"); // get pointer from stack
RANGECHECK(ebx, 2); RANGECHECK(esi, 2);
emit("movw %%ax, 0(%%r8, %%rbx, 1)"); // store in memory emit("movw %%ax, (%%r8, %%rsi, 1)"); // store in memory
break; break;
case OP_STORE4: case OP_STORE4:
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
emit("movl 0(%%r9, %%rsi, 1), %%eax"); // get value from stack emit("movl (%%r9, %%rbx, 1), %%eax"); // get value from stack
STACK_POP(8); STACK_POP(8);
emit("movl 4(%%r9, %%rsi, 1), %%ebx"); // get pointer from stack emit("movl 4(%%r9, %%rbx, 1), %%esi"); // get pointer from stack
RANGECHECK(ebx, 4); RANGECHECK(esi, 4);
emit("movl %%eax, 0(%%r8, %%rbx, 1)"); // store in memory emit("movl %%eax, (%%r8, %%rsi, 1)"); // store in memory
break; break;
case OP_ARG: case OP_ARG:
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
emit("movl 0(%%r9, %%rsi, 1), %%eax"); // get value from stack emit("movl (%%r9, %%rbx, 1), %%eax"); // get value from stack
STACK_POP(4); STACK_POP(4);
emit("movl $0x%hx, %%ebx", barg); emit("movl $0x%hx, %%esi", barg);
emit("addl %%edi, %%ebx"); emit("addl %%edi, %%esi");
RANGECHECK(ebx, 4); RANGECHECK(esi, 4);
emit("movl %%eax, 0(%%r8,%%rbx, 1)"); // store in args space emit("movl %%eax, (%%r8,%%rsi, 1)"); // store in args space
break; break;
case OP_BLOCK_COPY: case OP_BLOCK_COPY:
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
STACK_POP(8); STACK_POP(8);
emit("push %%rsi");
emit("push %%rdi"); emit("push %%rdi");
emit("push %%r8"); emit("push %%r8");
emit("push %%r9"); emit("push %%r9");
emit("push %%r10"); emit("push %%r10");
emit("movq %%rsp, %%rbx"); // we need to align the stack pointer emit("movq %%rsp, %%rsi"); // we need to align the stack pointer
emit("subq $8, %%rbx"); // | emit("subq $8, %%rsi"); // |
emit("andq $127, %%rbx"); // | emit("andq $127, %%rsi"); // |
emit("subq %%rbx, %%rsp"); // <-+ emit("subq %%rsi, %%rsp"); // <-+
emit("push %%rbx"); emit("push %%rsi");
emit("movl 4(%%r9, %%rsi, 1), %%edi"); // 1st argument dest emit("movl 4(%%r9, %%rbx, 1), %%edi"); // 1st argument dest
emit("movl 8(%%r9, %%rsi, 1), %%esi"); // 2nd argument src emit("movl 8(%%r9, %%rbx, 1), %%rsi"); // 2nd argument src
emit("movl $%d, %%edx", iarg); // 3rd argument count emit("movl $%d, %%edx", iarg); // 3rd argument count
emit("movq $%"PRIu64", %%rax", (intptr_t) block_copy_vm); emit("movq $%"PRIu64", %%rax", (intptr_t) block_copy_vm);
emit("callq *%%rax"); emit("callq *%%rax");
emit("pop %%rbx"); emit("pop %%rsi");
emit("addq %%rbx, %%rsp"); emit("addq %%rsi, %%rsp");
emit("pop %%r10"); emit("pop %%r10");
emit("pop %%r9"); emit("pop %%r9");
emit("pop %%r8"); emit("pop %%r8");
emit("pop %%rdi"); emit("pop %%rdi");
emit("pop %%rsi");
break; break;
case OP_SEX8: case OP_SEX8:
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
emit("movw 0(%%r9, %%rsi, 1), %%ax"); emit("movw (%%r9, %%rbx, 1), %%ax");
emit("andq $255, %%rax"); emit("andq $255, %%rax");
emit("cbw"); emit("cbw");
emit("cwde"); emit("cwde");
emit("movl %%eax, 0(%%r9, %%rsi, 1)"); emit("movl %%eax, (%%r9, %%rbx, 1)");
break; break;
case OP_SEX16: case OP_SEX16:
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
emit("movw 0(%%r9, %%rsi, 1), %%ax"); emit("movw (%%r9, %%rbx, 1), %%ax");
emit("cwde"); emit("cwde");
emit("movl %%eax, 0(%%r9, %%rsi, 1)"); emit("movl %%eax, (%%r9, %%rbx, 1)");
break; break;
case OP_NEGI: case OP_NEGI:
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
emit("negl 0(%%r9, %%rsi, 1)"); emit("negl (%%r9, %%rbx, 1)");
break; break;
case OP_ADD: case OP_ADD:
SIMPLE("addl"); SIMPLE("addl");
@ -837,49 +819,49 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
case OP_DIVI: case OP_DIVI:
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
STACK_POP(4); STACK_POP(4);
emit("movl 0(%%r9, %%rsi, 1), %%eax"); emit("movl (%%r9, %%rbx, 1), %%eax");
emit("cdq"); emit("cdq");
emit("idivl 4(%%r9, %%rsi, 1)"); emit("idivl 4(%%r9, %%rbx, 1)");
emit("movl %%eax, 0(%%r9, %%rsi, 1)"); emit("movl %%eax, (%%r9, %%rbx, 1)");
break; break;
case OP_DIVU: case OP_DIVU:
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
STACK_POP(4); STACK_POP(4);
emit("movl 0(%%r9, %%rsi, 1), %%eax"); emit("movl (%%r9, %%rbx, 1), %%eax");
emit("xorq %%rdx, %%rdx"); emit("xorq %%rdx, %%rdx");
emit("divl 4(%%r9, %%rsi, 1)"); emit("divl 4(%%r9, %%rbx, 1)");
emit("movl %%eax, 0(%%r9, %%rsi, 1)"); emit("movl %%eax, (%%r9, %%rbx, 1)");
break; break;
case OP_MODI: case OP_MODI:
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
STACK_POP(4); STACK_POP(4);
emit("movl 0(%%r9, %%rsi, 1), %%eax"); emit("movl (%%r9, %%rbx, 1), %%eax");
emit("xorl %%edx, %%edx"); emit("xorl %%edx, %%edx");
emit("cdq"); emit("cdq");
emit("idivl 4(%%r9, %%rsi, 1)"); emit("idivl 4(%%r9, %%rbx, 1)");
emit("movl %%edx, 0(%%r9, %%rsi, 1)"); emit("movl %%edx, (%%r9, %%rbx, 1)");
break; break;
case OP_MODU: case OP_MODU:
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
STACK_POP(4); STACK_POP(4);
emit("movl 0(%%r9, %%rsi, 1), %%eax"); emit("movl (%%r9, %%rbx, 1), %%eax");
emit("xorl %%edx, %%edx"); emit("xorl %%edx, %%edx");
emit("divl 4(%%r9, %%rsi, 1)"); emit("divl 4(%%r9, %%rbx, 1)");
emit("movl %%edx, 0(%%r9, %%rsi, 1)"); emit("movl %%edx, (%%r9, %%rbx, 1)");
break; break;
case OP_MULI: case OP_MULI:
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
STACK_POP(4); STACK_POP(4);
emit("movl 0(%%r9, %%rsi, 1), %%eax"); emit("movl (%%r9, %%rbx, 1), %%eax");
emit("imull 4(%%r9, %%rsi, 1)"); emit("imull 4(%%r9, %%rbx, 1)");
emit("movl %%eax, 0(%%r9, %%rsi, 1)"); emit("movl %%eax, (%%r9, %%rbx, 1)");
break; break;
case OP_MULU: case OP_MULU:
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
STACK_POP(4); STACK_POP(4);
emit("movl 0(%%r9, %%rsi, 1), %%eax"); emit("movl (%%r9, %%rbx, 1), %%eax");
emit("mull 4(%%r9, %%rsi, 1)"); emit("mull 4(%%r9, %%rbx, 1)");
emit("movl %%eax, 0(%%r9, %%rsi, 1)"); emit("movl %%eax, (%%r9, %%rbx, 1)");
break; break;
case OP_BAND: case OP_BAND:
SIMPLE("andl"); SIMPLE("andl");
@ -892,7 +874,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
break; break;
case OP_BCOM: case OP_BCOM:
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
emit("notl 0(%%r9, %%rsi, 1)"); emit("notl (%%r9, %%rbx, 1)");
break; break;
case OP_LSH: case OP_LSH:
SHIFT("shl"); SHIFT("shl");
@ -906,12 +888,12 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
case OP_NEGF: case OP_NEGF:
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
#ifdef USE_X87 #ifdef USE_X87
emit("flds 0(%%r9, %%rsi, 1)"); emit("flds (%%r9, %%rbx, 1)");
emit("fchs"); emit("fchs");
emit("fstps 0(%%r9, %%rsi, 1)"); emit("fstps (%%r9, %%rbx, 1)");
#else #else
emit("movl $0x80000000, %%eax"); emit("movl $0x80000000, %%eax");
emit("xorl %%eax, 0(%%r9, %%rsi, 1)"); emit("xorl %%eax, (%%r9, %%rbx, 1)");
#endif #endif
break; break;
case OP_ADDF: case OP_ADDF:
@ -933,27 +915,27 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
case OP_CVIF: case OP_CVIF:
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
#ifdef USE_X87 #ifdef USE_X87
emit("filds 0(%%r9, %%rsi, 1)"); emit("filds (%%r9, %%rbx, 1)");
emit("fstps 0(%%r9, %%rsi, 1)"); emit("fstps (%%r9, %%rbx, 1)");
#else #else
emit("movl 0(%%r9, %%rsi, 1), %%eax"); emit("movl (%%r9, %%rbx, 1), %%eax");
emit("cvtsi2ss %%eax, %%xmm0"); emit("cvtsi2ss %%eax, %%xmm0");
emit("movss %%xmm0, 0(%%r9, %%rsi, 1)"); emit("movss %%xmm0, (%%r9, %%rbx, 1)");
#endif #endif
break; break;
case OP_CVFI: case OP_CVFI:
MAYBE_EMIT_CONST(); MAYBE_EMIT_CONST();
#ifdef USE_X87 #ifdef USE_X87
emit("flds 0(%%r9, %%rsi, 1)"); emit("flds (%%r9, %%rbx, 1)");
emit("fnstcw 4(%%r9, %%rsi, 1)"); emit("fnstcw 4(%%r9, %%rbx, 1)");
emit("movw $0x0F7F, 8(%%r9, %%rsi, 1)"); // round toward zero emit("movw $0x0F7F, 8(%%r9, %%rbx, 1)"); // round toward zero
emit("fldcw 8(%%r9, %%rsi, 1)"); emit("fldcw 8(%%r9, %%rbx, 1)");
emit("fistpl 0(%%r9, %%rsi, 1)"); emit("fistpl (%%r9, %%rbx, 1)");
emit("fldcw 4(%%r9, %%rsi, 1)"); emit("fldcw 4(%%r9, %%rbx, 1)");
#else #else
emit("movss 0(%%r9, %%rsi, 1), %%xmm0"); emit("movss (%%r9, %%rbx, 1), %%xmm0");
emit("cvttss2si %%xmm0, %%eax"); emit("cvttss2si %%xmm0, %%eax");
emit("movl %%eax, 0(%%r9, %%rsi, 1)"); emit("movl %%eax, (%%r9, %%rbx, 1)");
#endif #endif
break; break;
default: default:
@ -1051,10 +1033,10 @@ int VM_CallCompiled( vm_t *vm, int *args ) {
int programCounter; int programCounter;
int programStack; int programStack;
int stackOnEntry; int stackOnEntry;
int opStackRet; long opStackRet;
byte *image; byte *image;
void *entryPoint; void *entryPoint;
void *opStack; int *opStack;
int stack[OPSTACK_SIZE + 3] = { 0xDEADBEEF }; int stack[OPSTACK_SIZE + 3] = { 0xDEADBEEF };
currentVM = vm; currentVM = vm;
@ -1098,7 +1080,7 @@ int VM_CallCompiled( vm_t *vm, int *args ) {
opStack = PADP(stack, 4); opStack = PADP(stack, 4);
__asm__ __volatile__ ( __asm__ __volatile__ (
" movl $0,%%esi \r\n" \ " movq $-0x80,%%rbx \r\n" \
" movl %5,%%edi \r\n" \ " movl %5,%%edi \r\n" \
" movq %4,%%r8 \r\n" \ " movq %4,%%r8 \r\n" \
" movq %3,%%r9 \r\n" \ " movq %3,%%r9 \r\n" \
@ -1107,14 +1089,13 @@ int VM_CallCompiled( vm_t *vm, int *args ) {
" callq *%%r10 \r\n" \ " callq *%%r10 \r\n" \
" addq $24, %%rsp \r\n" \ " addq $24, %%rsp \r\n" \
" movl %%edi, %0 \r\n" \ " movl %%edi, %0 \r\n" \
" movl %%esi, %1 \r\n" \ " movq %%rbx, %1 \r\n" \
: "=m" (programStack), "=m" (opStackRet) : "=g" (programStack), "=g" (opStackRet)
: "m" (entryPoint), "m" (opStack), "m" (vm->dataBase), "m" (programStack) : "g" (entryPoint), "g" (((intptr_t ) opStack) + OPSTACK_SIZE / 2), "g" (vm->dataBase), "g" (programStack)
: "%rsi", "%rdi", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r15", "%xmm0" : "%rsi", "%rdi", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r15", "%xmm0"
); );
if(opStackRet != -(OPSTACK_SIZE / 2) + 4 || *opStack != 0xDEADBEEF)
if(opStackRet != 4) Com_Error(ERR_DROP, "opStack corrupted in compiled code (offset %ld)", opStackRet);
Com_Error(ERR_DROP, "opStack corrupted in compiled code (offset %d)", opStackRet);
if ( programStack != stackOnEntry - 48 ) { if ( programStack != stackOnEntry - 48 ) {
Com_Error( ERR_DROP, "programStack corrupted in compiled code" ); Com_Error( ERR_DROP, "programStack corrupted in compiled code" );

View file

@ -158,6 +158,7 @@ typedef enum {
R_R15 = 0x0F | R_64, R_R15 = 0x0F | R_64,
R_AL = R_EAX | R_8, R_AL = R_EAX | R_8,
R_AX = R_EAX | R_16, R_AX = R_EAX | R_16,
R_BL = R_EBX | R_8,
R_CL = R_ECX | R_8, R_CL = R_ECX | R_8,
R_XMM0 = 0x00 | R_XMM, R_XMM0 = 0x00 | R_XMM,
R_MGP = 0x0F, // mask for general purpose registers R_MGP = 0x0F, // mask for general purpose registers
@ -213,6 +214,32 @@ typedef struct {
u8 rcode; // opcode for reg/mem u8 rcode; // opcode for reg/mem
} opparam_t; } opparam_t;
static opparam_t params_add = { subcode: 0, rmcode: 0x01, };
static opparam_t params_or = { subcode: 1, rmcode: 0x09, };
static opparam_t params_and = { subcode: 4, rmcode: 0x21, };
static opparam_t params_sub = { subcode: 5, rmcode: 0x29, };
static opparam_t params_xor = { subcode: 6, rmcode: 0x31, };
static opparam_t params_cmp = { subcode: 7, rmcode: 0x39, mrcode: 0x3b, };
static opparam_t params_dec = { subcode: 1, rcode: 0xff, rcode8: 0xfe, };
static opparam_t params_sar = { subcode: 7, rcode: 0xd3, rcode8: 0xd2, };
static opparam_t params_shl = { subcode: 4, rcode: 0xd3, rcode8: 0xd2, };
static opparam_t params_shr = { subcode: 5, rcode: 0xd3, rcode8: 0xd2, };
static opparam_t params_idiv = { subcode: 7, rcode: 0xf7, rcode8: 0xf6, };
static opparam_t params_div = { subcode: 6, rcode: 0xf7, rcode8: 0xf6, };
static opparam_t params_imul = { subcode: 5, rcode: 0xf7, rcode8: 0xf6, };
static opparam_t params_mul = { subcode: 4, rcode: 0xf7, rcode8: 0xf6, };
static opparam_t params_neg = { subcode: 3, rcode: 0xf7, rcode8: 0xf6, };
static opparam_t params_not = { subcode: 2, rcode: 0xf7, rcode8: 0xf6, };
static opparam_t params_cvtsi2ss = { xmmprefix: 0xf3, rmcode: 0x2a };
static opparam_t params_cvttss2si = { xmmprefix: 0xf3, rmcode: 0x2c };
static opparam_t params_addss = { xmmprefix: 0xf3, mrcode: 0x58 };
static opparam_t params_divss = { xmmprefix: 0xf3, mrcode: 0x5e };
static opparam_t params_movss = { xmmprefix: 0xf3, mrcode: 0x10, rmcode: 0x11 };
static opparam_t params_mulss = { xmmprefix: 0xf3, mrcode: 0x59 };
static opparam_t params_subss = { xmmprefix: 0xf3, mrcode: 0x5c };
static opparam_t params_ucomiss = { mrcode: 0x2e };
/* ************************* */ /* ************************* */
static unsigned hashkey(const char *string, unsigned len) { static unsigned hashkey(const char *string, unsigned len) {
@ -314,9 +341,9 @@ static const char* argtype2str(argtype_t t)
/* ************************* */ /* ************************* */
static inline int iss8(u64 v) static inline int iss8(int64_t v)
{ {
return (llabs(v) <= 0x80); //llabs instead of labs required for __WIN64 return (v >= -0x80 && v <= 0x7f);
} }
static inline int isu8(u64 v) static inline int isu8(u64 v)
@ -324,9 +351,9 @@ static inline int isu8(u64 v)
return (v <= 0xff); return (v <= 0xff);
} }
static inline int iss16(u64 v) static inline int iss16(int64_t v)
{ {
return (llabs(v) <= 0x8000); return (v >= -0x8000 && v <= 0x7fff);
} }
static inline int isu16(u64 v) static inline int isu16(u64 v)
@ -334,9 +361,9 @@ static inline int isu16(u64 v)
return (v <= 0xffff); return (v <= 0xffff);
} }
static inline int iss32(u64 v) static inline int iss32(int64_t v)
{ {
return (llabs(v) <= 0x80000000); return (v >= -0x80000000L && v <= 0x7fffffff);
} }
static inline int isu32(u64 v) static inline int isu32(u64 v)
@ -595,7 +622,7 @@ static void emit_mov(const char* mnemonic, arg_t arg1, arg_t arg2, void* data)
if(arg2.v.reg & R_8) if(arg2.v.reg & R_8)
{ {
if(!isu8(arg1.v.imm)) if(!iss8(arg1.v.imm))
crap("value too large for 8bit register"); crap("value too large for 8bit register");
op = 0xb0; op = 0xb0;
@ -711,19 +738,23 @@ static void emit_subaddand(const char* mnemonic, arg_t arg1, arg_t arg2, void* d
} }
compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2); compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2);
modrm |= params->subcode << 3; modrm |= params->subcode << 3;
if(rex) emit1(rex); if(rex) emit1(rex);
#if 0
if(isu8(arg1.v.imm)) if(arg2.v.reg & R_8)
{
emit1(0x80); // sub reg8/mem8, imm8
emit1(modrm);
emit1(arg1.v.imm & 0xFF);
}
else if(iss8(arg1.v.imm))
{ {
emit1(0x83); // sub reg/mem, imm8 emit1(0x83); // sub reg/mem, imm8
emit1(modrm); emit1(modrm);
emit1(arg1.v.imm&0xFF); emit1(arg1.v.imm & 0xFF);
} }
else else
#endif
{ {
emit1(0x81); // sub reg/mem, imm32 emit1(0x81); // sub reg/mem, imm32
emit1(modrm); emit1(modrm);
@ -893,42 +924,19 @@ static void emit_twobyte(const char* mnemonic, arg_t arg1, arg_t arg2, void* dat
CRAP_INVALID_ARGS; CRAP_INVALID_ARGS;
} }
static opparam_t params_add = { subcode: 0, rmcode: 0x01, };
static opparam_t params_or = { subcode: 1, rmcode: 0x09, };
static opparam_t params_and = { subcode: 4, rmcode: 0x21, };
static opparam_t params_sub = { subcode: 5, rmcode: 0x29, };
static opparam_t params_xor = { subcode: 6, rmcode: 0x31, };
static opparam_t params_cmp = { subcode: 7, rmcode: 0x39, mrcode: 0x3b, };
static opparam_t params_dec = { subcode: 1, rcode: 0xff, rcode8: 0xfe, };
static opparam_t params_sar = { subcode: 7, rcode: 0xd3, rcode8: 0xd2, };
static opparam_t params_shl = { subcode: 4, rcode: 0xd3, rcode8: 0xd2, };
static opparam_t params_shr = { subcode: 5, rcode: 0xd3, rcode8: 0xd2, };
static opparam_t params_idiv = { subcode: 7, rcode: 0xf7, rcode8: 0xf6, };
static opparam_t params_div = { subcode: 6, rcode: 0xf7, rcode8: 0xf6, };
static opparam_t params_imul = { subcode: 5, rcode: 0xf7, rcode8: 0xf6, };
static opparam_t params_mul = { subcode: 4, rcode: 0xf7, rcode8: 0xf6, };
static opparam_t params_neg = { subcode: 3, rcode: 0xf7, rcode8: 0xf6, };
static opparam_t params_not = { subcode: 2, rcode: 0xf7, rcode8: 0xf6, };
static opparam_t params_cvtsi2ss = { xmmprefix: 0xf3, rmcode: 0x2a };
static opparam_t params_cvttss2si = { xmmprefix: 0xf3, rmcode: 0x2c };
static opparam_t params_addss = { xmmprefix: 0xf3, mrcode: 0x58 };
static opparam_t params_divss = { xmmprefix: 0xf3, mrcode: 0x5e };
static opparam_t params_movss = { xmmprefix: 0xf3, mrcode: 0x10, rmcode: 0x11 };
static opparam_t params_mulss = { xmmprefix: 0xf3, mrcode: 0x59 };
static opparam_t params_subss = { xmmprefix: 0xf3, mrcode: 0x5c };
static opparam_t params_ucomiss = { mrcode: 0x2e };
static int ops_sorted = 0; static int ops_sorted = 0;
static op_t ops[] = { static op_t ops[] = {
{ "addb", emit_subaddand, &params_add },
{ "addl", emit_subaddand, &params_add }, { "addl", emit_subaddand, &params_add },
{ "addq", emit_subaddand, &params_add }, { "addq", emit_subaddand, &params_add },
{ "addss", emit_twobyte, &params_addss }, { "addss", emit_twobyte, &params_addss },
{ "andb", emit_subaddand, &params_and },
{ "andl", emit_subaddand, &params_and }, { "andl", emit_subaddand, &params_and },
{ "andq", emit_subaddand, &params_and }, { "andq", emit_subaddand, &params_and },
{ "callq", emit_call, NULL }, { "callq", emit_call, NULL },
{ "cbw", emit_opsingle16, (void*)0x98 }, { "cbw", emit_opsingle16, (void*)0x98 },
{ "cdq", emit_opsingle, (void*)0x99 }, { "cdq", emit_opsingle, (void*)0x99 },
{ "cmpb", emit_subaddand, &params_cmp },
{ "cmpl", emit_subaddand, &params_cmp }, { "cmpl", emit_subaddand, &params_cmp },
{ "cmpq", emit_subaddand, &params_cmp }, { "cmpq", emit_subaddand, &params_cmp },
{ "cvtsi2ss", emit_twobyte, &params_cvtsi2ss }, { "cvtsi2ss", emit_twobyte, &params_cvtsi2ss },
@ -974,18 +982,21 @@ static op_t ops[] = {
{ "nop", emit_opsingle, (void*)0x90 }, { "nop", emit_opsingle, (void*)0x90 },
{ "notl", emit_op_rm, &params_not }, { "notl", emit_op_rm, &params_not },
{ "notq", emit_op_rm, &params_not }, { "notq", emit_op_rm, &params_not },
{ "or", emit_subaddand, &params_or }, { "orb", emit_subaddand, &params_or },
{ "orl", emit_subaddand, &params_or }, { "orl", emit_subaddand, &params_or },
{ "orq", emit_subaddand, &params_or },
{ "pop", emit_opreg, (void*)0x58 }, { "pop", emit_opreg, (void*)0x58 },
{ "push", emit_opreg, (void*)0x50 }, { "push", emit_opreg, (void*)0x50 },
{ "ret", emit_opsingle, (void*)0xc3 }, { "ret", emit_opsingle, (void*)0xc3 },
{ "sarl", emit_op_rm_cl, &params_sar }, { "sarl", emit_op_rm_cl, &params_sar },
{ "shl", emit_op_rm_cl, &params_shl }, { "shl", emit_op_rm_cl, &params_shl },
{ "shrl", emit_op_rm_cl, &params_shr }, { "shrl", emit_op_rm_cl, &params_shr },
{ "subb", emit_subaddand, &params_sub },
{ "subl", emit_subaddand, &params_sub }, { "subl", emit_subaddand, &params_sub },
{ "subq", emit_subaddand, &params_sub }, { "subq", emit_subaddand, &params_sub },
{ "subss", emit_twobyte, &params_subss }, { "subss", emit_twobyte, &params_subss },
{ "ucomiss", emit_twobyte, &params_ucomiss }, { "ucomiss", emit_twobyte, &params_ucomiss },
{ "xorb", emit_subaddand, &params_xor },
{ "xorl", emit_subaddand, &params_xor }, { "xorl", emit_subaddand, &params_xor },
{ "xorq", emit_subaddand, &params_xor }, { "xorq", emit_subaddand, &params_xor },
{ NULL, NULL, NULL } { NULL, NULL, NULL }
@ -1010,27 +1021,24 @@ static op_t* getop(const char* n)
} }
#else #else
unsigned m, t, b; unsigned int m, t, b;
int r; int r;
t = ARRAY_LEN(ops)-1; t = ARRAY_LEN(ops)-1;
b = 0;
while(b <= t) r = m = -1;
{
m = ((t-b)>>1) + b; do
if((r = strcmp(ops[m].mnemonic, n)) == 0)
{
return &ops[m];
}
else if(r < 0)
{ {
if(r < 0)
b = m + 1; b = m + 1;
}
else else
{
t = m - 1; t = m - 1;
}
} m = ((t - b) >> 1) + b;
if((r = strcmp(ops[m].mnemonic, n)) == 0)
return &ops[m];
} while(b <= t && t);
#endif #endif
return NULL; return NULL;
@ -1047,6 +1055,10 @@ static reg_t parsereg(const char* str)
{ {
return R_AX; return R_AX;
} }
if(*s == 'b' && s[1] == 'l' && !s[2])
{
return R_BL;
}
if(*s == 'c' && s[1] == 'l' && !s[2]) if(*s == 'c' && s[1] == 'l' && !s[2])
{ {
return R_CL; return R_CL;