From 04a0859f79945cc9c43a0b1a38e2a39664d127af Mon Sep 17 00:00:00 2001 From: TomW Date: Sun, 19 Jul 2015 16:59:58 +0100 Subject: [PATCH] Effective address calculations now implemented by recompiled code in x86-64 recompiler. --- src/386_dynarec_ops.c | 123 ------------- src/codegen_x86-64.c | 389 +++++++++++++++++++++++++++++++----------- 2 files changed, 288 insertions(+), 224 deletions(-) diff --git a/src/386_dynarec_ops.c b/src/386_dynarec_ops.c index 853a736..12de113 100644 --- a/src/386_dynarec_ops.c +++ b/src/386_dynarec_ops.c @@ -16,72 +16,11 @@ extern uint16_t *mod1add[2][8]; extern uint32_t *mod1seg[8]; -/*Copy-and-pasted from 386_dynarec.c, is not in a header file because it will - eventually be different for the dynarec ops*/ -#ifdef __amd64__ static inline void fetch_ea_32_long(uint32_t rmdat) { eal_r = eal_w = NULL; easeg = ea_seg->base; ea_rseg = ea_seg->seg; - if (rm == 4) - { - uint8_t sib = rmdat >> 8; - - switch (mod) - { - case 0: - eaaddr = regs[sib & 7].l; - pc++; - break; - case 1: - pc++; - eaaddr = ((uint32_t)(int8_t)getbyte()) + regs[sib & 7].l; -// pc++; - break; - case 2: - eaaddr = (fastreadl(cs + pc + 1)) + regs[sib & 7].l; - pc += 5; - break; - } - /*SIB byte present*/ - if ((sib & 7) == 5 && !mod) - eaaddr = getlong(); - else if ((sib & 6) == 4 && !ssegs) - { - easeg = ss; - ea_rseg = SS; - ea_seg = &_ss; - } - if (((sib >> 3) & 7) != 4) - eaaddr += regs[(sib >> 3) & 7].l << (sib >> 6); - } - else - { - eaaddr = regs[rm].l; - if (mod) - { - if (rm == 5 && !ssegs) - { - easeg = ss; - ea_rseg = SS; - ea_seg = &_ss; - } - if (mod == 1) - { - eaaddr += ((uint32_t)(int8_t)(rmdat >> 8)); - pc++; - } - else - { - eaaddr += getlong(); - } - } - else if (rm == 5) - { - eaaddr = getlong(); - } - } if (easeg != 0xFFFFFFFF && ((easeg + eaaddr) & 0xFFF) <= 0xFFC) { uint32_t addr = easeg + eaaddr; @@ -97,33 +36,6 @@ static inline void fetch_ea_16_long(uint32_t rmdat) eal_r = eal_w = NULL; easeg = ea_seg->base; ea_rseg = ea_seg->seg; - if (!mod && rm == 6) - { - eaaddr = getword(); - } - else - { - switch (mod) - { - case 0: - eaaddr = 0; - break; - case 1: - eaaddr = (uint16_t)(int8_t)(rmdat >> 8); pc++; - break; - case 2: - eaaddr = getword(); - break; - } - eaaddr += (*mod1add[0][rm]) + (*mod1add[1][rm]); - if (mod1seg[rm] == &ss && !ssegs) - { - easeg = ss; - ea_rseg = SS; - ea_seg = &_ss; - } - eaaddr &= 0xFFFF; - } if (easeg != 0xFFFFFFFF && ((easeg + eaaddr) & 0xFFF) <= 0xFFC) { uint32_t addr = easeg + eaaddr; @@ -134,44 +46,9 @@ static inline void fetch_ea_16_long(uint32_t rmdat) } } -#define fetch_ea_16(rmdat) pc++; mod=(rmdat >> 6) & 3; reg=(rmdat >> 3) & 7; rm = rmdat & 7; if (mod != 3) { fetch_ea_16_long(rmdat); if (abrt) return 1; } -#define fetch_ea_32(rmdat) pc++; mod=(rmdat >> 6) & 3; reg=(rmdat >> 3) & 7; rm = rmdat & 7; if (mod != 3) { fetch_ea_32_long(rmdat); } if (abrt) return 1 - -#else /*__amd64__*/ - -static inline void fetch_ea_32_long(uint32_t rmdat) -{ - eal_r = eal_w = NULL; - easeg = ea_seg->base; - ea_rseg = ea_seg->seg; - if (easeg != 0xFFFFFFFF && ((easeg + eaaddr) & 0xFFF) <= 0xFFC) - { - if ( readlookup2[(easeg + eaaddr) >> 12] != -1) - eal_r = (uint32_t *)(readlookup2[(easeg + eaaddr) >> 12] + easeg + eaaddr); - if (writelookup2[(easeg + eaaddr) >> 12] != -1) - eal_w = (uint32_t *)(writelookup2[(easeg + eaaddr) >> 12] + easeg + eaaddr); - } -} - -static inline void fetch_ea_16_long(uint32_t rmdat) -{ - eal_r = eal_w = NULL; - easeg = ea_seg->base; - ea_rseg = ea_seg->seg; - if (easeg != 0xFFFFFFFF && ((easeg + eaaddr) & 0xFFF) <= 0xFFC) - { - if ( readlookup2[(easeg + eaaddr) >> 12] != -1) - eal_r = (uint32_t *)(readlookup2[(easeg + eaaddr) >> 12] + easeg + eaaddr); - if (writelookup2[(easeg + eaaddr) >> 12] != -1) - eal_w = (uint32_t *)(writelookup2[(easeg + eaaddr) >> 12] + easeg + eaaddr); - } -} - #define fetch_ea_16(rmdat) pc++; if (mod != 3) fetch_ea_16_long(rmdat); #define fetch_ea_32(rmdat) pc++; if (mod != 3) fetch_ea_32_long(rmdat); -#endif /*__amd64__*/ - #define OP_TABLE(name) dynarec_ops_ ## name diff --git a/src/codegen_x86-64.c b/src/codegen_x86-64.c index dd1abba..e5e33d9 100644 --- a/src/codegen_x86-64.c +++ b/src/codegen_x86-64.c @@ -14,7 +14,7 @@ #include "codegen.h" #include "codegen_ops.h" -//#include "codegen_ops_x86.h" +#include "codegen_ops_x86-64.h" #ifdef __linux__ #include @@ -297,16 +297,34 @@ void codegen_block_init(uint32_t phys_addr) addbyte(0xf6); #endif call(block, (uintptr_t)x86gpf); + while (block_pos < BLOCK_EXIT_OFFSET) + addbyte(0x90); /*NOP*/ block_pos = BLOCK_EXIT_OFFSET; /*Exit code*/ addbyte(0x48); /*ADDL $32,%rsp*/ addbyte(0x83); addbyte(0xC4); addbyte(0x20); + addbyte(0x41); /*POP R15*/ + addbyte(0x5f); + addbyte(0x41); /*POP R14*/ + addbyte(0x5e); + addbyte(0x41); /*POP R13*/ + addbyte(0x5d); + addbyte(0x41); /*POP R12*/ + addbyte(0x5c); addbyte(0x5d); /*POP RBP*/ addbyte(0xC3); /*RET*/ cpu_block_end = 0; block_pos = 0; /*Entry code*/ addbyte(0x55); /*PUSH RBP*/ + addbyte(0x41); /*PUSH R12*/ + addbyte(0x54); + addbyte(0x41); /*PUSH R13*/ + addbyte(0x55); + addbyte(0x41); /*PUSH R14*/ + addbyte(0x56); + addbyte(0x41); /*PUSH R15*/ + addbyte(0x57); addbyte(0x48); /*SUBL $32,%rsp*/ addbyte(0x83); addbyte(0xEC); @@ -482,6 +500,14 @@ void codegen_block_end() addbyte(0x83); addbyte(0xC4); addbyte(0x20); + addbyte(0x41); /*POP R15*/ + addbyte(0x5f); + addbyte(0x41); /*POP R14*/ + addbyte(0x5e); + addbyte(0x41); /*POP R13*/ + addbyte(0x5d); + addbyte(0x41); /*POP R12*/ + addbyte(0x5c); addbyte(0x5d); /*POP RBP*/ addbyte(0xC3); /*RET*/ @@ -595,54 +621,125 @@ void codegen_debug() pclog("At %04x(%08x):%04x %04x(%08x):%04x es=%08x EAX=%08x BX=%04x ECX=%08x BP=%04x EDX=%08x EDI=%08x\n", CS, cs, pc, SS, ss, ESP, es,EAX, BX,ECX,BP, EDX,EDI); } } -#if 0 + static x86seg *codegen_generate_ea_16_long(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) { if (!mod && rm == 6) { addbyte(0xC7); /*MOVL $0,(ssegs)*/ - addbyte(0x05); + addbyte(0x04); + addbyte(0x25); addlong((uint32_t)&eaaddr); addlong((fetchdat >> 8) & 0xffff); (*op_pc) += 2; } else { + int base_reg, index_reg; + + switch (rm) + { + case 0: case 1: case 7: + base_reg = LOAD_REG_W(REG_BX); + break; + case 2: case 3: case 6: + base_reg = LOAD_REG_W(REG_BP); + break; + case 4: + base_reg = LOAD_REG_W(REG_SI); + break; + case 5: + base_reg = LOAD_REG_W(REG_DI); + break; + } + if (!(rm & 4)) + { + if (rm & 1) + index_reg = LOAD_REG_W(REG_DI); + else + index_reg = LOAD_REG_W(REG_SI); + } + base_reg &= 7; + index_reg &= 7; + switch (mod) { case 0: - addbyte(0xa1); /*MOVL *mod1add[0][rm], %eax*/ - addlong((uint32_t)mod1add[0][rm]); - addbyte(0x03); /*ADDL *mod1add[1][rm], %eax*/ - addbyte(0x05); - addlong((uint32_t)mod1add[1][rm]); + if (rm & 4) + { + addbyte(0x41); /*MOVZX EAX, base_reg*/ + addbyte(0x0f); + addbyte(0xb7); + addbyte(0xc0 | base_reg); + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg*/ + addbyte(0x43); + addbyte(0x8d); + if (base_reg == 5) + { + addbyte(0x44); + addbyte(base_reg | (index_reg << 3)); + addbyte(0); + } + else + { + addbyte(0x04); + addbyte(base_reg | (index_reg << 3)); + } + } break; case 1: - addbyte(0xb8); /*MOVL ,%eax*/ - addlong((uint32_t)(int8_t)(rmdat >> 8));// pc++; - addbyte(0x03); /*ADDL *mod1add[0][rm], %eax*/ - addbyte(0x05); - addlong((uint32_t)mod1add[0][rm]); - addbyte(0x03); /*ADDL *mod1add[1][rm], %eax*/ - addbyte(0x05); - addlong((uint32_t)mod1add[1][rm]); + if (rm & 4) + { + addbyte(0x67); /*LEA EAX, base_reg+imm8*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x40 | base_reg); + addbyte((fetchdat >> 8) & 0xff); + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg+imm8*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x44); + addbyte(base_reg | (index_reg << 3)); + addbyte((fetchdat >> 8) & 0xff); + } (*op_pc)++; break; case 2: - addbyte(0xb8); /*MOVL ,%eax*/ - addlong((fetchdat >> 8) & 0xffff);// pc++; - addbyte(0x03); /*ADDL *mod1add[0][rm], %eax*/ - addbyte(0x05); - addlong((uint32_t)mod1add[0][rm]); - addbyte(0x03); /*ADDL *mod1add[1][rm], %eax*/ - addbyte(0x05); - addlong((uint32_t)mod1add[1][rm]); + if (rm & 4) + { + addbyte(0x67); /*LEA EAX, base_reg+imm8*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x80 | base_reg); + addlong((fetchdat >> 8) & 0xffff); + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg+imm16*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x84); + addbyte(base_reg | (index_reg << 3)); + addlong((fetchdat >> 8) & 0xffff); + } (*op_pc) += 2; break; + } - addbyte(0x25); /*ANDL $0xffff, %eax*/ - addlong(0xffff); - addbyte(0xa3); + if (mod || !(rm & 4)) + { + addbyte(0x25); /*ANDL $0xffff, %eax*/ + addlong(0xffff); + } + addbyte(0x89); /*MOV eaaddr, EAX*/ + addbyte(0x04); + addbyte(0x25); addlong((uint32_t)&eaaddr); if (mod1seg[rm] == &ss && !op_ssegs) @@ -650,7 +747,7 @@ static x86seg *codegen_generate_ea_16_long(x86seg *op_ea_seg, uint32_t fetchdat, } return op_ea_seg; } - +//#if 0 static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, int stack_offset) { uint32_t new_eaaddr; @@ -658,42 +755,135 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, if (rm == 4) { uint8_t sib = fetchdat >> 8; + int base_reg = -1, index_reg = -1; + (*op_pc)++; - - switch (mod) + + if (mod || (sib & 7) != 5) + base_reg = LOAD_REG_L(sib & 7) & 7; + + if (((sib >> 3) & 7) != 4) + index_reg = LOAD_REG_L((sib >> 3) & 7) & 7; + + if (index_reg == -1) { - case 0: - if ((sib & 7) == 5) + switch (mod) { + case 0: + if ((sib & 7) == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOV EAX, imm32*/ + addlong(new_eaaddr); + (*op_pc) += 4; + } + else + { + addbyte(0x44); /*MOV EAX, base_reg*/ + addbyte(0x89); + addbyte(0xc0 | (base_reg << 3)); + } + break; + case 1: + addbyte(0x67); /*LEA EAX, imm8+base_reg*/ + addbyte(0x41); + addbyte(0x8d); + if (base_reg == 4) + { + addbyte(0x44); + addbyte(0x24); + } + else + { + addbyte(0x40 | base_reg); + } + addbyte((fetchdat >> 16) & 0xff); + (*op_pc)++; + break; + case 2: new_eaaddr = fastreadl(cs + (*op_pc) + 1); - addbyte(0xb8); /*MOVL ,%eax*/ - addlong(new_eaaddr);// pc++; + addbyte(0x67); /*LEA EAX, imm32+base_reg*/ + addbyte(0x41); + addbyte(0x8d); + if (base_reg == 4) + { + addbyte(0x84); + addbyte(0x24); + } + else + { + addbyte(0x80 | base_reg); + } + addlong(new_eaaddr); (*op_pc) += 4; + break; } - else + } + else + { + switch (mod) { - addbyte(0xa1); /*MOVL regs[sib&7].l, %eax*/ - addlong((uint32_t)®s[sib & 7].l); + case 0: + if ((sib & 7) == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + if (sib >> 6) + { + addbyte(0x67); /*LEA EAX, imm32+index_reg*scale*/ + addbyte(0x42); + addbyte(0x8d); + addbyte(0x04); + addbyte(0x05 | (sib & 0xc0) | (index_reg << 3)); + addlong(new_eaaddr); + } + else + { + addbyte(0x67); /*LEA EAX, imm32+index_reg*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x80 | index_reg); + addlong(new_eaaddr); + } + (*op_pc) += 4; + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg*scale*/ + addbyte(0x43); + addbyte(0x8d); + if (base_reg == 5) + { + addbyte(0x44); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + addbyte(0); + } + else + { + addbyte(0x04); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + } + } + break; + case 1: + addbyte(0x67); /*LEA EAX, imm8+base_reg+index_reg*scale*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x44); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + addbyte((fetchdat >> 16) & 0xff); + (*op_pc)++; + break; + case 2: + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x67); /*LEA EAX, imm32+base_reg+index_reg*scale*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x84); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + addlong(new_eaaddr); + (*op_pc) += 4; + break; } - break; - case 1: - new_eaaddr = (uint32_t)(int8_t)((fetchdat >> 16) & 0xff); - addbyte(0xb8); /*MOVL new_eaaddr, %eax*/ - addlong(new_eaaddr); - addbyte(0x03); /*ADDL regs[sib&7].l, %eax*/ - addbyte(0x05); - addlong((uint32_t)®s[sib & 7].l); - (*op_pc)++; - break; - case 2: - new_eaaddr = fastreadl(cs + (*op_pc) + 1); - addbyte(0xb8); /*MOVL new_eaaddr, %eax*/ - addlong(new_eaaddr); - addbyte(0x03); /*ADDL regs[sib&7].l, %eax*/ - addbyte(0x05); - addlong((uint32_t)®s[sib & 7].l); - (*op_pc) += 4; - break; } if (stack_offset && (sib & 7) == 4 && (mod || (sib & 7) != 5)) /*ESP*/ { @@ -702,74 +892,68 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, } if (((sib & 7) == 4 || (mod && (sib & 7) == 5)) && !op_ssegs) op_ea_seg = &_ss; - if (((sib >> 3) & 7) != 4) - { - switch (sib >> 6) - { - case 0: - addbyte(0x03); /*ADDL regs[sib&7].l, %eax*/ - addbyte(0x05); - addlong((uint32_t)®s[(sib >> 3) & 7].l); - break; - case 1: - addbyte(0x8B); addbyte(0x1D); addlong((uint32_t)®s[(sib >> 3) & 7].l); /*MOVL armregs[RD],%ebx*/ - addbyte(0x01); addbyte(0xD8); /*ADDL %ebx,%eax*/ - addbyte(0x01); addbyte(0xD8); /*ADDL %ebx,%eax*/ - break; - case 2: - addbyte(0x8B); addbyte(0x1D); addlong((uint32_t)®s[(sib >> 3) & 7].l); /*MOVL armregs[RD],%ebx*/ - addbyte(0xC1); addbyte(0xE3); addbyte(2); /*SHL $2,%ebx*/ - addbyte(0x01); addbyte(0xD8); /*ADDL %ebx,%eax*/ - break; - case 3: - addbyte(0x8B); addbyte(0x1D); addlong((uint32_t)®s[(sib >> 3) & 7].l); /*MOVL armregs[RD],%ebx*/ - addbyte(0xC1); addbyte(0xE3); addbyte(3); /*SHL $2,%ebx*/ - addbyte(0x01); addbyte(0xD8); /*ADDL %ebx,%eax*/ - break; - } - } - addbyte(0xa3); + + addbyte(0x89); /*MOV eaaddr, EAX*/ + addbyte(0x04); + addbyte(0x25); addlong((uint32_t)&eaaddr); } else { + int base_reg; + if (!mod && rm == 5) { new_eaaddr = fastreadl(cs + (*op_pc) + 1); addbyte(0xC7); /*MOVL $new_eaaddr,(eaaddr)*/ - addbyte(0x05); + addbyte(0x04); + addbyte(0x25); addlong((uint32_t)&eaaddr); addlong(new_eaaddr); (*op_pc) += 4; return op_ea_seg; } - addbyte(0xa1); /*MOVL regs[rm].l, %eax*/ - addlong((uint32_t)®s[rm].l); - eaaddr = regs[rm].l; + base_reg = LOAD_REG_L(rm) & 7; if (mod) { if (rm == 5 && !op_ssegs) op_ea_seg = &_ss; if (mod == 1) { - addbyte(0x05); - addlong((uint32_t)(int8_t)(fetchdat >> 8)); + addbyte(0x67); /*LEA EAX, base_reg+imm8*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x40 | base_reg); + addbyte((fetchdat >> 8) & 0xff); (*op_pc)++; } else { new_eaaddr = fastreadl(cs + (*op_pc) + 1); - addbyte(0x05); - addlong(new_eaaddr); + addbyte(0x67); /*LEA EAX, base_reg+imm32*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x80 | base_reg); + addlong(new_eaaddr); (*op_pc) += 4; } + addbyte(0x89); /*MOV eaaddr, EAX*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&eaaddr); + } + else + { + addbyte(0x44); /*MOV eaaddr, base_reg*/ + addbyte(0x89); + addbyte(4 | (base_reg << 3)); + addbyte(0x25); + addlong((uint32_t)&eaaddr); } - addbyte(0xa3); - addlong((uint32_t)&eaaddr); } return op_ea_seg; } -#endif +//#endif void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_pc, uint32_t old_pc) { codeblock_t *block = &codeblock[block_current]; @@ -1002,10 +1186,10 @@ generate_call: addlong((uint32_t)&ssegs); addlong(op_ssegs); } -#if 0 - if (!test_modrm || +//#if 0 + if ((!test_modrm || (op_table == x86_dynarec_opcodes && opcode_modrm[opcode]) || - (op_table == x86_dynarec_opcodes_0f && opcode_0f_modrm[opcode])) + (op_table == x86_dynarec_opcodes_0f && opcode_0f_modrm[opcode]))/* && !(op_32 & 0x200)*/) { int stack_offset = 0; @@ -1017,15 +1201,18 @@ generate_call: rm = fetchdat & 7; addbyte(0xC7); /*MOVL $mod,(mod)*/ - addbyte(0x05); + addbyte(0x04); + addbyte(0x25); addlong((uint32_t)&mod); addlong(mod); addbyte(0xC7); /*MOVL $reg,(reg)*/ - addbyte(0x05); + addbyte(0x04); + addbyte(0x25); addlong((uint32_t)®); addlong(reg); addbyte(0xC7); /*MOVL $rm,(rm)*/ - addbyte(0x05); + addbyte(0x04); + addbyte(0x25); addlong((uint32_t)&rm); addlong(rm); @@ -1036,7 +1223,7 @@ generate_call: op_ea_seg = codegen_generate_ea_32_long(op_ea_seg, fetchdat, op_ssegs, &op_pc, stack_offset); op_pc -= pc_off; } -#endif +//#endif // if (op_ea_seg != last_ea_seg) // { // last_ea_seg = op_ea_seg;