diff options
Diffstat (limited to 'src')
| -rwxr-xr-x | src/dynarec/arm64/dynarec_arm64_00.c | 21 | ||||
| -rwxr-xr-x | src/dynarec/arm64/dynarec_arm64_helper.c | 29 | ||||
| -rwxr-xr-x | src/emu/x64emu.c | 14 | ||||
| -rwxr-xr-x | src/emu/x64run.c | 242 | ||||
| -rw-r--r-- | src/emu/x64run64.c | 85 | ||||
| -rw-r--r-- | src/emu/x64run66.c | 14 | ||||
| -rw-r--r-- | src/emu/x64run67.c | 5 | ||||
| -rw-r--r-- | src/emu/x64run670f.c | 7 | ||||
| -rwxr-xr-x | src/emu/x64run_private.c | 35 | ||||
| -rwxr-xr-x | src/emu/x64run_private.h | 21 | ||||
| -rwxr-xr-x | src/emu/x64tls.c | 82 | ||||
| -rwxr-xr-x | src/emu/x86syscall.c | 2 | ||||
| -rwxr-xr-x | src/include/regs.h | 2 | ||||
| -rwxr-xr-x | src/include/x64emu.h | 2 | ||||
| -rwxr-xr-x | src/include/x64tls.h | 3 | ||||
| -rwxr-xr-x | src/libtools/signals.c | 8 |
16 files changed, 382 insertions, 190 deletions
diff --git a/src/dynarec/arm64/dynarec_arm64_00.c b/src/dynarec/arm64/dynarec_arm64_00.c index 2d621ef6..11888786 100755 --- a/src/dynarec/arm64/dynarec_arm64_00.c +++ b/src/dynarec/arm64/dynarec_arm64_00.c @@ -1048,12 +1048,13 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin case 0x8C: INST_NAME("MOV Ed, Seg"); nextop=F8; + u8 = (nextop&0x38)>>3; + LDRw_U12(x3, xEmu, offsetof(x64emu_t, segs[u8])); if((nextop&0xC0)==0xC0) { // reg <= seg - LDRH_U12(xRAX+(nextop&7)+(rex.b<<3), xEmu, offsetof(x64emu_t, segs[(nextop&0x38)>>3])); + UXTHw(xRAX+(nextop&7)+(rex.b<<3), x1); } else { // mem <= seg - addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0); - LDRH_U12(x3, xEmu, offsetof(x64emu_t, segs[(nextop&0x38)>>3])); - STH(x3, ed, fixedaddress); + addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0); + STH(x3, wback, fixedaddress); SMWRITE2(); } break; @@ -1076,16 +1077,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin case 0x8E: INST_NAME("MOV Seg,Ew"); nextop = F8; + u8 = (nextop&0x38)>>3; if((nextop&0xC0)==0xC0) { ed = xRAX+(nextop&7)+(rex.b<<3); } else { SMREAD(); - addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 1, rex, NULL, 0, 0); - LDH(x1, ed, fixedaddress); + addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0); + LDH(x1, wback, fixedaddress); ed = x1; } - STRw_U12(ed, xEmu, offsetof(x64emu_t, segs[(nextop&0x38)>>3])); - STRw_U12(wZR, xEmu, offsetof(x64emu_t, segs_serial[(nextop&0x38)>>3])); + STRw_U12(ed, xEmu, offsetof(x64emu_t, segs[u8])); + STRw_U12(wZR, xEmu, offsetof(x64emu_t, segs_serial[u8])); break; case 0x8F: INST_NAME("POP Ed"); @@ -1811,9 +1813,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin } break; case 0xCD: - INST_NAME("INT n"); u8 = F8; if(box64_wine && u8==0x2D) { + INST_NAME("INT 2D"); // lets do nothing MESSAGE(LOG_INFO, "INT 2D Windows anti-debug hack\n"); } else if (u8==0x80) { @@ -1833,6 +1835,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin LOAD_XEMU_REM(); jump_to_epilog(dyn, 0, xRIP, ninst); } else { + INST_NAME("INT n"); SETFLAGS(X_ALL, SF_SET); // Hack to set flags in "don't care" state GETIP(ip); STORE_XEMU_CALL(xRIP); diff --git a/src/dynarec/arm64/dynarec_arm64_helper.c b/src/dynarec/arm64/dynarec_arm64_helper.c index e141655a..f2dc26d8 100755 --- a/src/dynarec/arm64/dynarec_arm64_helper.c +++ b/src/dynarec/arm64/dynarec_arm64_helper.c @@ -541,23 +541,34 @@ void iret_to_epilog(dynarec_arm_t* dyn, int ninst, int is64bits) MESSAGE(LOG_DUMP, "IRet to epilog\n"); // POP IP NOTEST(x2); - POP1(xRIP); - // POP CS - POP1(x2); + if(is64bits) { + POP1(xRIP); + POP1(x2); + POP1(xFlags); + } else { + LDRw_S9_postindex(xRIP, xRSP, 4); + LDRw_S9_postindex(x2, xRSP, 4); + LDRw_S9_postindex(xFlags, xRSP, 4); + } + // x2 is CS STRH_U12(x2, xEmu, offsetof(x64emu_t, segs[_CS])); - STRx_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_CS])); - STRx_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_SS])); - // POP EFLAGS - POP1(xFlags); + STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_CS])); + // clean EFLAGS MOV32w(x1, 0x3F7FD7); ANDx_REG(xFlags, xFlags, x1); ORRx_mask(xFlags, xFlags, 1, 0b111111, 0); SET_DFNONE(x1); // POP RSP - POP1(x3); + if(is64bits) { + POP1(x3); //rsp + POP1(x2); //ss + } else { + LDRw_S9_postindex(x3, xRSP, 4); + LDRw_S9_postindex(x2, xRSP, 4); + } // POP SS - POP1(x2); STRH_U12(x2, xEmu, offsetof(x64emu_t, segs[_SS])); + STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_SS])); // set new RSP MOVx_REG(xRSP, x3); // Ret.... diff --git a/src/emu/x64emu.c b/src/emu/x64emu.c index 3962f5b9..9de4cb18 100755 --- a/src/emu/x64emu.c +++ b/src/emu/x64emu.c @@ -401,6 +401,7 @@ const char* DumpCPURegs(x64emu_t* emu, uintptr_t ip, int is32bits) static const char* regname[] = {"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI", " R8", " R9", "R10", "R11", "R12", "R13", "R14", "R15"}; static const char* regname32[]={"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"}; + static const char* segname[] = {"ES", "CS", "SS", "DS", "FS", "GS"}; char tmp[160]; buff[0] = '\0'; #ifdef HAVE_TRACE @@ -439,6 +440,13 @@ const char* DumpCPURegs(x64emu_t* emu, uintptr_t ip, int is32bits) } strcat(buff, "\n"); } + for (int i=0; i<6; ++i) { + sprintf(tmp, "%s=0x%04x", segname[i], emu->segs[i]); + strcat(buff, tmp); + if(i!=_GS) + strcat(buff, " "); + } + strcat(buff, "\n"); if(is32bits) for (int i=_AX; i<=_RDI; ++i) { #ifdef HAVE_TRACE @@ -527,13 +535,13 @@ void StopEmu(x64emu_t* emu, const char* reason, int is32bits) #endif } -void UnimpOpcode(x64emu_t* emu) +void UnimpOpcode(x64emu_t* emu, int is32bits) { R_RIP = emu->old_ip; int tid = syscall(SYS_gettid); - printf_log(LOG_NONE, "%04d|%p: Unimplemented Opcode (%02X %02X %02X %02X) %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", - tid, (void*)emu->old_ip, + printf_log(LOG_NONE, "%04d|%p: Unimplemented %sOpcode (%02X %02X %02X %02X) %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + tid, (void*)emu->old_ip, is32bits?"32bits ":"", Peek(emu, -4), Peek(emu, -3), Peek(emu, -2), Peek(emu, -1), Peek(emu, 0), Peek(emu, 1), Peek(emu, 2), Peek(emu, 3), Peek(emu, 4), Peek(emu, 5), Peek(emu, 6), Peek(emu, 7), diff --git a/src/emu/x64run.c b/src/emu/x64run.c index 6d66ad1e..09d28836 100755 --- a/src/emu/x64run.c +++ b/src/emu/x64run.c @@ -49,15 +49,10 @@ int Run(x64emu_t *emu, int step) int step = 0; #endif uintptr_t addr = R_RIP; - rex_t rex; + rex_t rex = {0}; int rep; // 0 none, 1=F2 prefix, 2=F3 prefix int unimp = 0; int is32bits = (emu->segs[_CS]==0x23); - if(is32bits) { - printf_log(LOG_INFO, "Error, 32bits execution not yet supported\n"); - emu->quit = 1; - return 0; - } if(emu->quit) return 0; @@ -68,7 +63,7 @@ int Run(x64emu_t *emu, int step) return 0; } //ref opcode: http://ref.x64asm.net/geek32.html#xA1 - printf_log(LOG_DEBUG, "Run X86 (%p), RIP=%p, Stack=%p is32bits=%D\n", emu, (void*)addr, (void*)R_RSP, is32bits); + printf_log(LOG_DEBUG, "Run X86 (%p), RIP=%p, Stack=%p is32bits=%d\n", emu, (void*)addr, (void*)R_RSP, is32bits); x64emurun: #ifndef TEST_INTERPRETER @@ -81,7 +76,7 @@ x64emurun: if(my_context->dec && ( (trace_end == 0) || ((addr >= trace_start) && (addr < trace_end))) ) - PrintTrace(emu, addr, 0, is32bits); + PrintTrace(emu, addr, 0); #endif emu->old_ip = addr; @@ -95,6 +90,7 @@ x64emurun: while((opcode==0x3E) || (opcode==0x26)) //Branch Taken Hint ignored opcode = F8; rex.rex = 0; + rex.is32bits = is32bits; if(!is32bits) while(opcode>=0x40 && opcode<=0x4f) { rex.rex = opcode; @@ -244,13 +240,39 @@ x64emurun: else cmp32(emu, R_EAX, F32); break; - + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: /* INC Reg (32bits only)*/ + tmp8u = opcode&7; + emu->regs[tmp8u].dword[0] = inc32(emu, emu->regs[tmp8u].dword[0]); + break; + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: /* DEC Reg (32bits only)*/ + tmp8u = opcode&7; + emu->regs[tmp8u].dword[0] = dec32(emu, emu->regs[tmp8u].dword[0]); + break; case 0x54: /* PUSH ESP */ if(rex.b) Push(emu, R_R12); else { - tmp64u = R_RSP; - Push(emu, tmp64u); + if(rex.is32bits) { + tmp32u = R_ESP; + Push32(emu, tmp32u); + } else { + tmp64u = R_RSP; + Push(emu, tmp64u); + } } break; case 0x50: @@ -261,7 +283,10 @@ x64emurun: case 0x56: case 0x57: /* PUSH Reg */ tmp8u = (opcode&7)+(rex.b<<3); - Push(emu, emu->regs[tmp8u].q[0]); + if(rex.is32bits) + Push32(emu, emu->regs[tmp8u].dword[0]); + else + Push(emu, emu->regs[tmp8u].q[0]); break; case 0x58: case 0x59: @@ -272,7 +297,7 @@ x64emurun: case 0x5E: case 0x5F: /* POP Reg */ tmp8u = (opcode&7)+(rex.b<<3); - emu->regs[tmp8u].q[0] = Pop(emu); + emu->regs[tmp8u].q[0] = is32bits?Pop32(emu):Pop(emu); break; case 0x63: /* MOVSXD Gd,Ed */ @@ -300,6 +325,7 @@ x64emurun: R_RIP = addr; goto fini; } + is32bits = (emu->segs[_CS]==0x23); #endif break; case 0x65: /* GS: prefix */ @@ -315,6 +341,7 @@ x64emurun: R_RIP = addr; goto fini; } + is32bits = (emu->segs[_CS]==0x23); #endif break; case 0x66: /* 16bits prefix */ @@ -348,7 +375,10 @@ x64emurun: #endif break; case 0x68: /* Push Id */ - Push(emu, F32S64); + if(rex.is32bits) + Push32(emu, F32); + else + Push(emu, F32S64); break; case 0x69: /* IMUL Gd,Ed,Id */ nextop = F8; @@ -361,8 +391,13 @@ x64emurun: GD->q[0] = imul32(emu, ED->dword[0], tmp64u); break; case 0x6A: /* Push Ib */ - tmp64s = F8S; - Push(emu, (uint64_t)tmp64s); + if(rex.is32bits) { + tmp32s = F8S; + Push32(emu, (uint32_t)tmp32s); + } else { + tmp64s = F8S; + Push(emu, (uint64_t)tmp64s); + } break; case 0x6B: /* IMUL Gd,Ed,Ib */ nextop = F8; @@ -589,17 +624,30 @@ x64emurun: else GD->q[0] = tmp64u&0xffffffff; break; - + case 0x8E: /* MOV Seg, Ew */ + nextop = F8; + GETED(0); + emu->segs[((nextop&0x38)>>3)] = ED->word[0]; + emu->segs_serial[((nextop&0x38)>>3)] = 0; + break; case 0x8F: /* POP Ed */ nextop = F8; if(MODREG) { emu->regs[(nextop&7)+(rex.b<<3)].q[0] = Pop(emu); } else { - tmp64u = Pop(emu); // this order allows handling POP [ESP] and variant - GETED(0); - R_ESP -= sizeof(void*); // to prevent issue with SEGFAULT - ED->q[0] = tmp64u; - R_ESP += sizeof(void*); + if(rex.is32bits) { + tmp32u = Pop32(emu); // this order allows handling POP [ESP] and variant + GETED(0); + R_ESP -= 4; // to prevent issue with SEGFAULT + ED->dword[0] = tmp32u; + R_ESP += 4; + } else { + tmp64u = Pop(emu); // this order allows handling POP [ESP] and variant + GETED(0); + R_RSP -= sizeof(void*); // to prevent issue with SEGFAULT + ED->q[0] = tmp64u; + R_RSP += sizeof(void*); + } } break; case 0x90: /* NOP or XCHG R8, RAX*/ @@ -643,7 +691,10 @@ x64emurun: break; case 0x9C: /* PUSHF */ CHECK_FLAGS(emu); - Push(emu, emu->eflags.x64); + if(rex.is32bits) + Push32(emu, emu->eflags.x64); + else + Push(emu, emu->eflags.x64); break; case 0x9D: /* POPF */ emu->eflags.x64 = ((Pop(emu) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1 @@ -673,22 +724,36 @@ x64emurun: R_AH = (uint8_t)emu->eflags.x64; break; case 0xA0: /* MOV AL,Ob */ - R_AL = *(uint8_t*)F64; + if(rex.is32bits) + R_AL = *(uint8_t*)(uintptr_t)F32; + else + R_AL = *(uint8_t*)F64; break; case 0xA1: /* MOV EAX,Od */ - if(rex.w) - R_RAX = *(uint64_t*)F64; - else - R_RAX = *(uint32_t*)F64; + if(rex.is32bits) + R_EAX = *(int32_t*)(uintptr_t)F32; + else { + if(rex.w) + R_RAX = *(uint64_t*)F64; + else + R_RAX = *(uint32_t*)F64; + } break; case 0xA2: /* MOV Ob,AL */ - *(uint8_t*)F64 = R_AL; + if(rex.is32bits) + *(uint8_t*)(uintptr_t)F32 = R_AL; + else + *(uint8_t*)F64 = R_AL; break; case 0xA3: /* MOV Od,EAX */ - if(rex.w) - *(uint64_t*)F64 = R_RAX; - else - *(uint32_t*)F64 = R_EAX; + if(rex.is32bits) + *(uint32_t*)(uintptr_t)F32 = R_EAX; + else { + if(rex.w) + *(uint64_t*)F64 = R_RAX; + else + *(uint32_t*)F64 = R_EAX; + } break; case 0xA4: /* MOVSB */ tmp8s = ACCESS_FLAG(F_DF)?-1:+1; @@ -1107,12 +1172,12 @@ x64emurun: break; case 0xC2: /* RETN Iw */ tmp16u = F16; - addr = Pop(emu); + addr = rex.is32bits?Pop32(emu):Pop(emu); R_RSP += tmp16u; STEP2 break; case 0xC3: /* RET */ - addr = Pop(emu); + addr = rex.is32bits?Pop32(emu):Pop(emu); STEP2 break; @@ -1135,21 +1200,34 @@ x64emurun: case 0xC8: /* ENTER Iw,Ib */ tmp16u = F16; tmp8u = (F8) & 0x1f; - tmp64u = R_RBP; - Push(emu, R_RBP); - R_RBP = R_RSP; - if (tmp8u) { - for (tmp8u2 = 1; tmp8u2 < tmp8u; tmp8u2++) { - tmp64u -= sizeof(void*); - Push(emu, *((uintptr_t*)tmp64u)); + if(rex.is32bits) { + tmp64u = R_EBP; + Push32(emu, R_EBP); + R_EBP = R_ESP; + if (tmp8u) { + for (tmp8u2 = 1; tmp8u2 < tmp8u; tmp8u2++) { + tmp64u -= 4; + Push32(emu, *((uint32_t*)tmp64u)); + } + Push32(emu, R_EBP); } + } else { + tmp64u = R_RBP; Push(emu, R_RBP); + R_RBP = R_RSP; + if (tmp8u) { + for (tmp8u2 = 1; tmp8u2 < tmp8u; tmp8u2++) { + tmp64u -= sizeof(void*); + Push(emu, *((uintptr_t*)tmp64u)); + } + Push(emu, R_RBP); + } } R_RSP -= tmp16u; break; case 0xC9: /* LEAVE */ R_RSP = R_RBP; - R_RBP = Pop(emu); + R_RBP = rex.is32bits?Pop32(emu):Pop(emu); break; case 0xCC: /* INT 3 */ @@ -1179,19 +1257,19 @@ x64emurun: } break; - case 0xCF: /* IRET */ - addr = Pop(emu); - emu->segs[_CS] = Pop(emu)&0xffff; + addr = rex.is32bits?Pop32(emu):Pop(emu); + emu->segs[_CS] = (rex.is32bits?Pop32(emu):Pop(emu))&0xffff; emu->segs_serial[_CS] = 0; - emu->eflags.x64 = ((Pop(emu) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1 - tmp64u = Pop(emu); //RSP - emu->segs[_SS] = Pop(emu)&0xffff; + emu->eflags.x64 = (((rex.is32bits?Pop32(emu):Pop(emu)) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1 + tmp64u = rex.is32bits?Pop32(emu):Pop(emu); //RSP + emu->segs[_SS] = (rex.is32bits?Pop32(emu):Pop(emu))&0xffff; emu->segs_serial[_SS] = 0; - R_RSP= tmp64u; + R_RSP = tmp64u; RESET_FLAGS(emu); R_RIP = addr; - goto fini; // exit, to recompute CS if needed + STEP; + is32bits = (emu->segs[_CS]==0x23); break; case 0xD0: /* GRP2 Eb,1 */ case 0xD2: /* GRP2 Eb,CL */ @@ -1415,7 +1493,10 @@ x64emurun: break; case 0xE8: /* CALL Id */ tmp32s = F32S; // call is relative - Push(emu, addr); + if(rex.is32bits) + Push32(emu, addr); + else + Push(emu, addr); addr += tmp32s; STEP2 break; @@ -1635,8 +1716,13 @@ x64emurun: break; case 2: /* CALL NEAR Ed */ GETE8(0); - tmp64u = (uintptr_t)getAlternate((void*)ED->q[0]); - Push(emu, addr); + if(rex.is32bits) { + tmp64u = (uintptr_t)ED->dword[0]; + Push32(emu, addr); + } else { + tmp64u = (uintptr_t)getAlternate((void*)ED->q[0]); + Push(emu, addr); + } addr = tmp64u; STEP2 break; @@ -1648,16 +1734,27 @@ x64emurun: emu->error |= ERR_ILLEGAL; goto fini; } else { - Push(emu, R_CS); - Push(emu, addr); - R_RIP = addr = (uintptr_t)getAlternate((void*)ED->q[0]); // check CS? - R_CS = (ED+1)->word[0]; - goto fini; // exit loop to recompute new CS... + if(rex.is32bits || !rex.w) { + Push32(emu, R_CS); + Push32(emu, addr); + addr = (uintptr_t)getAlternate((void*)(uintptr_t)ED->dword[0]); + R_CS = ED->word[2]; + } else { + Push(emu, R_CS); + Push(emu, addr); + addr = (uintptr_t)getAlternate((void*)ED->q[0]); + R_CS = (ED+1)->word[0]; + } + STEP2; + is32bits = (emu->segs[_CS]==0x23); } break; case 4: /* JMP NEAR Ed */ GETE8(0); - addr = (uintptr_t)getAlternate((void*)ED->q[0]); + if(rex.is32bits) + addr = (uintptr_t)ED->dword[0]; + else + addr = (uintptr_t)getAlternate((void*)ED->q[0]); STEP2 break; case 5: /* JMP FAR Ed */ @@ -1668,15 +1765,26 @@ x64emurun: emu->error |= ERR_ILLEGAL; goto fini; } else { - R_RIP = (uintptr_t)getAlternate((void*)ED->q[0]); //check CS? - R_CS = (ED+1)->word[0]; - goto fini; // exit loop to recompute CS... + if(rex.is32bits || !rex.w) { + addr = (uintptr_t)getAlternate((void*)(uintptr_t)ED->dword[0]); //check CS? + R_CS = ED->word[2]; + } else { + addr = (uintptr_t)getAlternate((void*)ED->q[0]); //check CS? + R_CS = (ED+1)->word[0]; + } + STEP2; + is32bits = (emu->segs[_CS]==0x23); } break; case 6: /* Push Ed */ _GETED(0); - tmp64u = ED->q[0]; // rex.w ignored - Push(emu, tmp64u); // avoid potential issue with push [esp+...] + if(rex.is32bits) { + tmp32u = ED->dword[0]; // rex.w ignored + Push32(emu, tmp32u); // avoid potential issue with push [esp+...] + } else { + tmp64u = ED->q[0]; // rex.w ignored + Push(emu, tmp64u); // avoid potential issue with push [esp+...] + } break; default: printf_log(LOG_NONE, "Illegal Opcode %p: %02X %02X %02X %02X %02X %02X\n",(void*)R_RIP, opcode, nextop, PK(2), PK(3), PK(4), PK(5)); @@ -1694,12 +1802,12 @@ x64emurun: fini: -if(emu->segs[_CS]!=0x33) printf_log(LOG_NONE, "Warning, CS is not default value: 0x%x\n", emu->segs[_CS]); +if(emu->segs[_CS]!=0x33 && emu->segs[_CS]!=0x23) printf_log(LOG_NONE, "Warning, CS is not default value: 0x%x\n", emu->segs[_CS]); #ifndef TEST_INTERPRETER printf_log(LOG_DEBUG, "End of X86 run (%p), RIP=%p, Stack=%p, unimp=%d, emu->fork=%d, emu->uc_link=%p, emu->quit=%d\n", emu, (void*)R_RIP, (void*)R_RSP, unimp, emu->fork, emu->uc_link, emu->quit); if(unimp) { emu->quit = 1; - UnimpOpcode(emu); + UnimpOpcode(emu, is32bits); } // fork handling if(emu->fork) { diff --git a/src/emu/x64run64.c b/src/emu/x64run64.c index a2d5cc74..b1fb52b7 100644 --- a/src/emu/x64run64.c +++ b/src/emu/x64run64.c @@ -47,10 +47,11 @@ uintptr_t Run64(x64emu_t *emu, rex_t rex, int seg, uintptr_t addr) opcode = F8; // REX prefix before the F0 are ignored rex.rex = 0; - while(opcode>=0x40 && opcode<=0x4f) { - rex.rex = opcode; - opcode = F8; - } + if(!rex.is32bits) + while(opcode>=0x40 && opcode<=0x4f) { + rex.rex = opcode; + opcode = F8; + } rep = 0; while((opcode==0xF2) || (opcode==0xF3)) { rep = opcode-0xF1; @@ -412,11 +413,29 @@ uintptr_t Run64(x64emu_t *emu, rex_t rex, int seg, uintptr_t addr) break; case 0xA1: /* MOV EAX,FS:Od */ - tmp64u = F64; - if(rex.w) - R_RAX = *(uint64_t*)(tlsdata+tmp64u); - else - R_RAX = *(uint32_t*)(tlsdata+tmp64u); + if(rex.is32bits) { + tmp64u = F32; + R_EAX = *(uint32_t*)(tlsdata+tmp64u); + } else { + tmp64u = F64; + if(rex.w) + R_RAX = *(uint64_t*)(tlsdata+tmp64u); + else + R_RAX = *(uint32_t*)(tlsdata+tmp64u); + } + break; + + case 0xA3: /* MOV FS:Od,EAX */ + if(rex.is32bits) { + tmp64u = F32; + *(uint32_t*)(uintptr_t)(tlsdata+tmp64u) = R_EAX; + } else { + tmp64u = F64; + if(rex.w) + *(uint64_t*)(tlsdata+tmp64u) = R_RAX; + else + *(uint32_t*)(tlsdata+tmp64u) = R_EAX; + } break; case 0xC6: /* MOV FS:Eb, Ib */ @@ -574,8 +593,13 @@ uintptr_t Run64(x64emu_t *emu, rex_t rex, int seg, uintptr_t addr) } break; case 2: /* CALL NEAR Ed */ - tmp64u = (uintptr_t)getAlternate((void*)ED->q[0]); - Push(emu, addr); + if(rex.is32bits) { + tmp64u = (uintptr_t)getAlternate((void*)(uintptr_t)ED->dword[0]); + Push32(emu, addr); + } else { + tmp64u = (uintptr_t)getAlternate((void*)ED->q[0]); + Push(emu, addr); + } addr = tmp64u; break; case 3: /* CALL FAR Ed */ @@ -585,15 +609,25 @@ uintptr_t Run64(x64emu_t *emu, rex_t rex, int seg, uintptr_t addr) emu->error |= ERR_ILLEGAL; return 0; } else { - Push16(emu, R_CS); - Push(emu, addr); - R_RIP = addr = ED->dword[0]; - R_CS = (ED+1)->word[0]; + if(rex.is32bits || !rex.w) { + Push32(emu, R_CS); + Push32(emu, addr); + R_RIP = addr = ED->dword[0]; + R_CS = ED->word[2]; + } else { + Push(emu, R_CS); + Push(emu, addr); + R_RIP = addr = ED->q[0]; + R_CS = (ED+1)->word[0]; + } return 0; // exit loop to recompute new CS... } break; case 4: /* JMP NEAR Ed */ - addr = (uintptr_t)getAlternate((void*)ED->q[0]); + if(rex.is32bits) + addr = (uintptr_t)getAlternate((void*)(uintptr_t)ED->dword[0]); + else + addr = (uintptr_t)getAlternate((void*)ED->q[0]); break; case 5: /* JMP FAR Ed */ if(nextop>0xc0) { @@ -602,14 +636,23 @@ uintptr_t Run64(x64emu_t *emu, rex_t rex, int seg, uintptr_t addr) emu->error |= ERR_ILLEGAL; return 0; } else { - R_RIP = addr = ED->q[0]; - R_CS = (ED+1)->word[0]; - return 0; // exit loop to recompute CS... + if(rex.is32bits || !rex.w) { + R_RIP = addr = ED->dword[0]; + R_CS = ED->word[2]; + } else { + R_RIP = addr = ED->q[0]; + R_CS = (ED+1)->word[0]; + } } break; case 6: /* Push Ed */ - tmp64u = ED->q[0]; // rex.w ignored - Push(emu, tmp64u); // avoid potential issue with push [esp+...] + if(rex.is32bits) { + tmp32u = ED->dword[0]; // rex.w ignored + Push32(emu, tmp32u); // avoid potential issue with push [esp+...] + } else { + tmp64u = ED->q[0]; // rex.w ignored + Push(emu, tmp64u); // avoid potential issue with push [esp+...] + } break; default: printf_log(LOG_NONE, "Illegal Opcode %p: %02X %02X %02X %02X %02X %02X\n",(void*)R_RIP, opcode, nextop, PK(2), PK(3), PK(4), PK(5)); diff --git a/src/emu/x64run66.c b/src/emu/x64run66.c index c2d53742..3698911f 100644 --- a/src/emu/x64run66.c +++ b/src/emu/x64run66.c @@ -647,7 +647,10 @@ uintptr_t Run66(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr) case 0xE8: /* CALL Id */ tmp32s = F32S; // call is relative - Push(emu, addr); + if(rex.is32bits) + Push32(emu, addr); + else + Push(emu, addr); addr += tmp32s; break; @@ -735,8 +738,13 @@ uintptr_t Run66(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr) EW->word[0] = dec16(emu, EW->word[0]); break; case 2: /* CALL NEAR Ed */ - tmp64u = (uintptr_t)getAlternate((void*)ED->q[0]); - Push(emu, addr); + if(rex.is32bits) { + tmp64u = (uintptr_t)getAlternate((void*)(uintptr_t)ED->dword[0]); + Push32(emu, addr); + } else { + tmp64u = (uintptr_t)getAlternate((void*)ED->q[0]); + Push(emu, addr); + } addr = tmp64u; break; /*case 6: diff --git a/src/emu/x64run67.c b/src/emu/x64run67.c index 63fca1ab..7a03342f 100644 --- a/src/emu/x64run67.c +++ b/src/emu/x64run67.c @@ -348,7 +348,10 @@ uintptr_t Run67(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr) case 0xE8: /* CALL Id */ tmp32s = F32S; // call is relative - Push(emu, addr); + if(rex.is32bits) + Push32(emu, addr); + else + Push(emu, addr); addr += tmp32s; break; diff --git a/src/emu/x64run670f.c b/src/emu/x64run670f.c index 589e5181..4e459e71 100644 --- a/src/emu/x64run670f.c +++ b/src/emu/x64run670f.c @@ -116,6 +116,13 @@ uintptr_t Run670F(x64emu_t *emu, rex_t rex, int rep, uintptr_t addr) } break; + case 0xB7: /* MOVZX Gd,Ew */ + nextop = F8; + GETEW32(0); + GETGD; + GD->q[0] = EW->word[0]; + break; + default: return 0; } diff --git a/src/emu/x64run_private.c b/src/emu/x64run_private.c index 57ff7c44..c8aa8794 100755 --- a/src/emu/x64run_private.c +++ b/src/emu/x64run_private.c @@ -1030,8 +1030,9 @@ extern uint64_t start_cnt; #define PK32(a) (*(int32_t*)((uint8_t*)(ip+a))) #define PK64(a) (*(int64_t*)((uint8_t*)(ip+a))) -void PrintTrace(x64emu_t* emu, uintptr_t ip, int dynarec, int is32bits) +void PrintTrace(x64emu_t* emu, uintptr_t ip, int dynarec) { + int is32bits = (emu->segs[_CS]==0x23); if(start_cnt) --start_cnt; if(!start_cnt && my_context->dec && ( (trace_end == 0) @@ -1136,8 +1137,36 @@ static uint64_t F64(uintptr_t* addr) { return ret; } +reg64_t* GetECommon_32(x64emu_t* emu, uintptr_t* addr, rex_t rex, uint8_t m, uintptr_t base) +{ + if (m<=7) { + if(m==0x4) { + uint8_t sib = F8(addr); + base += ((sib&0x7)==5)?((uint64_t)(int64_t)F32S(addr)):(emu->regs[(sib&0x7)+(rex.b<<3)].dword[0]); // base + base += (emu->sbiidx[((sib>>3)&7)+(rex.x<<3)]->sdword[0] << (sib>>6)); + return (reg64_t*)base; + } else if (m==0x5) { //disp32 + base += F32S(addr); + return (reg64_t*)(base); + } + return (reg64_t*)(uintptr_t)(base + emu->regs[m+(rex.b<<3)].dword[0]); + } else { + if((m&7)==4) { + uint8_t sib = F8(addr); + base += emu->regs[(sib&0x7)+(rex.b<<3)].dword[0]; // base + base += (emu->sbiidx[((sib>>3)&7)+(rex.x<<3)]->sdword[0] << (sib>>6)); + } else { + base += emu->regs[(m&0x7)+(rex.b<<3)].dword[0]; + } + base+=(m&0x80)?F32S(addr):F8S(addr); + return (reg64_t*)base; + } +} + reg64_t* GetECommon(x64emu_t* emu, uintptr_t* addr, rex_t rex, uint8_t m, uint8_t delta) { + if(rex.is32bits) + return GetECommon_32(emu, addr, rex, m, 0); if (m<=7) { if(m==0x4) { uint8_t sib = F8(addr); @@ -1165,6 +1194,8 @@ reg64_t* GetECommon(x64emu_t* emu, uintptr_t* addr, rex_t rex, uint8_t m, uint8_ reg64_t* GetECommonO(x64emu_t* emu, uintptr_t* addr, rex_t rex, uint8_t m, uint8_t delta, uintptr_t base) { + if(rex.is32bits) + return GetECommon_32(emu, addr, rex, m, base); if (m<=7) { if(m==0x4) { uint8_t sib = F8(addr); @@ -1191,6 +1222,8 @@ reg64_t* GetECommonO(x64emu_t* emu, uintptr_t* addr, rex_t rex, uint8_t m, uint8 reg64_t* GetECommon32O(x64emu_t* emu, uintptr_t* addr, rex_t rex, uint8_t m, uint8_t delta, uintptr_t base) { + if(rex.is32bits) + printf_log(LOG_INFO, "Warning, calling GetECommon32O with is32bits at %p\n", *addr); if (m<=7) { if(m==0x4) { uint8_t sib = F8(addr); diff --git a/src/emu/x64run_private.h b/src/emu/x64run_private.h index accf3a6e..93f6c096 100755 --- a/src/emu/x64run_private.h +++ b/src/emu/x64run_private.h @@ -7,15 +7,18 @@ #include "box64context.h" typedef struct x64emu_s x64emu_t; -typedef union rex_s { - uint8_t rex; - struct { - unsigned int b:1; - unsigned int x:1; - unsigned int r:1; - unsigned int w:1; - unsigned int s:4; +typedef struct rex_s { + union { + uint8_t rex; + struct { + unsigned int b:1; + unsigned int x:1; + unsigned int r:1; + unsigned int w:1; + unsigned int s:4; + }; }; + int is32bits; } rex_t; static inline uint8_t Peek(x64emu_t *emu, int offset){return *(uint8_t*)(R_RIP + offset);} @@ -158,7 +161,7 @@ uintptr_t GetSegmentBaseEmu(x64emu_t* emu, int seg); const char* GetNativeName(void* p); #ifdef HAVE_TRACE -void PrintTrace(x64emu_t* emu, uintptr_t ip, int dynarec, int is32bits); +void PrintTrace(x64emu_t* emu, uintptr_t ip, int dynarec); #endif #endif //__X86RUN_PRIVATE_H_ diff --git a/src/emu/x64tls.c b/src/emu/x64tls.c index af7c4aa0..12a6836d 100755 --- a/src/emu/x64tls.c +++ b/src/emu/x64tls.c @@ -15,7 +15,7 @@ typedef struct thread_area_s { int entry_number; - uintptr_t base_addr; + uint64_t base_addr; unsigned int limit; unsigned int seg_32bit:1; unsigned int contents:2; @@ -23,6 +23,7 @@ typedef struct thread_area_s unsigned int limit_in_pages:1; unsigned int seg_not_present:1; unsigned int useable:1; + unsigned int lm:1; } thread_area_t; typedef struct thread_area_32_s { @@ -37,64 +38,11 @@ typedef struct thread_area_32_s unsigned int useable:1; } thread_area_32_t; -uint32_t my_set_thread_area(thread_area_t* td) -{ - printf_log(/*LOG_DEBUG*/LOG_NONE, "set_thread_area(%p[%d/base=%p/limit=%u/32bits:%u/%u/%u...])\n", td, td->entry_number, (void*)td->base_addr, td->limit_in_pages, td->seg_32bit, td->contents, td->read_exec_only); - - int isempty = 0; - // first, check if the "user_desc", here td, is "empty" - if(td->read_exec_only==1 && td->seg_not_present==1) - if( !td->base_addr - && !td->limit - && !td->seg_32bit - && !td->contents - && !td->limit_in_pages - && !td->useable) - isempty = 1; - int idx = td->entry_number; - if(idx==-1) { - // find a free one - for (int i=9; i<15 && idx==-1; ++i) - if(!my_context->segtls[i].present) - idx=i; - if(idx==-1) { - errno = ESRCH; - return (uint32_t)-1; - } - td->entry_number = idx; - } - if(isempty && (td->entry_number<9 || td->entry_number>15)) { - errno = EINVAL; - return (uint32_t)-1; - } - if(isempty) { - memset(&my_context->segtls[td->entry_number], 0, sizeof(base_segment_t)); - return 0; - } - if((idx<9 || idx>15)) { - errno = EINVAL; - return (uint32_t)-1; - } - - my_context->segtls[idx].base = td->base_addr; - my_context->segtls[idx].limit = td->limit; - my_context->segtls[idx].present = 1; - my_context->segtls[idx].is32bits = 0; - if(!my_context->segtls[idx].key_init) { - pthread_key_create(&my_context->segtls[idx].key, NULL); - my_context->segtls[idx].key_init = 1; - } - - pthread_setspecific(my_context->segtls[idx].key, (void*)my_context->segtls[idx].base); - - ResetSegmentsCache(thread_get_emu()); - - return 0; -} +int GetTID(); -uint32_t my_set_thread_area_32(thread_area_32_t* td) +uint32_t my_set_thread_area_32(x64emu_t* emu, thread_area_32_t* td) { - printf_log(LOG_DEBUG, "set_thread_area(%p[%d/base=%p/limit=%u/32bits:%u/%u/%u...])\n", td, td->entry_number, (void*)(uintptr_t)td->base_addr, td->limit_in_pages, td->seg_32bit, td->contents, td->read_exec_only); + printf_log(LOG_DEBUG, "%04d| set_thread_area_32(%p[%d/base=%p/limit=%u/32bits:%u/%u/%u...])\n", GetTID(), td, td->entry_number, (void*)(uintptr_t)td->base_addr, td->limit_in_pages, td->seg_32bit, td->contents, td->read_exec_only); int isempty = 0; // first, check if the "user_desc", here td, is "empty" @@ -142,14 +90,14 @@ uint32_t my_set_thread_area_32(thread_area_32_t* td) pthread_setspecific(my_context->segtls[idx].key, (void*)my_context->segtls[idx].base); - ResetSegmentsCache(thread_get_emu()); + ResetSegmentsCache(emu); return 0; } uint32_t my_modify_ldt(x64emu_t* emu, int op, thread_area_t* td, int size) { - printf_log(/*LOG_DEBUG*/LOG_INFO, "modify_ldt(0x%x, %p[0x%x/base=%p/limit=%u/32bits:%u/%u/%u...], %d)\n", op, td, td->entry_number, (void*)td->base_addr, td->limit_in_pages, td->seg_32bit, td->contents, td->read_exec_only, size); + printf_log(LOG_DEBUG, "%04d| modify_ldt(0x%x, %p[0x%x/base=%p/limit=%u/32bits:%u/%u/%u...], %d)\n", GetTID(), op, td, td->entry_number, (void*)td->base_addr, td->limit_in_pages, td->seg_32bit, td->contents, td->read_exec_only, size); if(!td) { errno = EFAULT; return (uint32_t)-1; @@ -181,7 +129,7 @@ uint32_t my_modify_ldt(x64emu_t* emu, int op, thread_area_t* td, int size) return 0; } -int GetTID(); +static void* GetSeg43Base(); int my_arch_prctl(x64emu_t *emu, int code, void* addr) { printf_log(LOG_DEBUG, "%04d| arch_prctl(0x%x, %p) (RSP=%p, FS=0x%x, GS=0x%x)\n", GetTID(), code, addr,(void*)R_RSP, emu->segs[_FS], emu->segs[_GS]); @@ -202,7 +150,21 @@ int my_arch_prctl(x64emu_t *emu, int code, void* addr) case ARCH_SET_FS: case ARCH_SET_GS: seg=(code==ARCH_SET_FS)?_FS:_GS; + int idx = -1; + // search if it's a TLS base + // Is this search only occurs when seg==0? + for (int i=9; i<15 && idx==-1; ++i) + if(my_context->segtls[i].present && my_context->segtls[i].base==(uintptr_t)addr) + idx=i; + if(idx==-1 && GetSeg43Base()==addr) + idx = 0x43>>3; + // found... + if(idx!=-1) { + printf_log(LOG_DEBUG, "Changing segment selector from 0x%x to 0x%x\n", emu->segs[seg], (idx<<3) +3); + emu->segs[seg]=(idx<<3) +3; + } if(emu->segs[seg]==0) { + printf_log(LOG_DEBUG, "Warning, set seg, but it's 0!\n"); errno = EINVAL; return -1; } diff --git a/src/emu/x86syscall.c b/src/emu/x86syscall.c index c1f7bce2..b41b0066 100755 --- a/src/emu/x86syscall.c +++ b/src/emu/x86syscall.c @@ -271,7 +271,7 @@ void EXPORT x86Syscall(x64emu_t *emu) R_EAX = (uint32_t)-errno; break;*/ case 243: // set_thread_area - R_EAX = my_set_thread_area_32((thread_area_32_t*)(uintptr_t)R_EBX); + R_EAX = my_set_thread_area_32(emu, (thread_area_32_t*)(uintptr_t)R_EBX); if(R_EAX==0xffffffff && errno>0) R_EAX = (uint32_t)-errno; break; diff --git a/src/include/regs.h b/src/include/regs.h index 7a4ced73..a80b393e 100755 --- a/src/include/regs.h +++ b/src/include/regs.h @@ -17,7 +17,7 @@ enum { #define _DI _RDI enum { - _CS, _DS, _SS, _ES, _FS, _GS + _ES, _CS, _SS, _DS, _FS, _GS }; diff --git a/src/include/x64emu.h b/src/include/x64emu.h index dd324add..e9ad201c 100755 --- a/src/include/x64emu.h +++ b/src/include/x64emu.h @@ -49,7 +49,7 @@ void AddCleanup(x64emu_t *emu, void *p, void* dso_handle); void AddCleanup1Arg(x64emu_t *emu, void *p, void* a, void* dso_handle); void CallCleanup(x64emu_t *emu, void* p); void CallAllCleanup(x64emu_t *emu); -void UnimpOpcode(x64emu_t* emu); +void UnimpOpcode(x64emu_t* emu, int is32bits); uint64_t ReadTSC(x64emu_t* emu); diff --git a/src/include/x64tls.h b/src/include/x64tls.h index b99e3bc0..66f0d9eb 100755 --- a/src/include/x64tls.h +++ b/src/include/x64tls.h @@ -4,8 +4,7 @@ typedef struct thread_area_s thread_area_t; typedef struct thread_area_32_s thread_area_32_t; -uint32_t my_set_thread_area(thread_area_t* td); -uint32_t my_set_thread_area_32(thread_area_32_t* td); +uint32_t my_set_thread_area_32(x64emu_t* emu, thread_area_32_t* td); uint32_t my_modify_ldt(x64emu_t* emu, int op, thread_area_t* td, int size); tlsdatasize_t* getTLSData(box64context_t *context); diff --git a/src/libtools/signals.c b/src/libtools/signals.c index 76fd50eb..c38cacbb 100755 --- a/src/libtools/signals.c +++ b/src/libtools/signals.c @@ -1242,7 +1242,7 @@ exit(-1); } if(log_minimum<=box64_log) { static const char* reg_name[] = {"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI", " R8", " R9","R10","R11", "R12","R13","R14","R15"}; - static const char* seg_name[] = {"CS", "DS", "SS", "ES", "GS", "FS"}; + static const char* seg_name[] = {"ES", "CS", "SS", "DS", "GS", "FS"}; int shown_regs = 0; #ifdef DYNAREC uint32_t hash = 0; @@ -1293,11 +1293,15 @@ exit(-1); #else printf_log(log_minimum, "%04d|%s @%p (%s) (x64pc=%p/%s:\"%s\", rsp=%p), for accessing %p (code=%d)", GetTID(), signame, pc, name, (void*)x64pc, elfname?elfname:"???", x64name?x64name:"???", rsp, addr, info->si_code); #endif - if(!shown_regs) + if(!shown_regs) { for (int i=0; i<16; ++i) { if(!(i%4)) printf_log(log_minimum, "\n"); printf_log(log_minimum, "%s:0x%016llx ", reg_name[i], emu->regs[i].q[0]); } + printf_log(log_minimum, "\n"); + for (int i=0; i<6; ++i) + printf_log(log_minimum, "%s:0x%04x ", seg_name[i], emu->segs[i]); + } if(sig==SIGILL) printf_log(log_minimum, " opcode=%02X %02X %02X %02X %02X %02X %02X %02X (%02X %02X %02X %02X %02X)\n", ((uint8_t*)pc)[0], ((uint8_t*)pc)[1], ((uint8_t*)pc)[2], ((uint8_t*)pc)[3], ((uint8_t*)pc)[4], ((uint8_t*)pc)[5], ((uint8_t*)pc)[6], ((uint8_t*)pc)[7], ((uint8_t*)x64pc)[0], ((uint8_t*)x64pc)[1], ((uint8_t*)x64pc)[2], ((uint8_t*)x64pc)[3], ((uint8_t*)x64pc)[4]); else if(sig==SIGBUS) |