#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include "debug.h" #include "box64context.h" #include "dynarec.h" #include "emu/x64emu_private.h" #include "tools/bridge_private.h" #include "x64run.h" #include "x64emu.h" #include "box64stack.h" #include "callback.h" #include "emu/x64run_private.h" #include "emu/x87emu_private.h" #include "x64trace.h" #include "signals.h" #include "dynarec_arm64.h" #include "dynarec_arm64_private.h" #include "dynarec_arm64_functions.h" void arm_fstp(x64emu_t* emu, void* p) { if(ST0.q!=STld(0).ref) D2LD(&ST0.d, p); else memcpy(p, &STld(0).ld, 10); } void arm_print_armreg(x64emu_t* emu, uintptr_t reg, uintptr_t n) { dynarec_log(LOG_DEBUG, "R%ld=0x%lx (%ld)\n", n, reg, reg); } void arm_f2xm1(x64emu_t* emu) { ST0.d = exp2(ST0.d) - 1.0; } void arm_fyl2x(x64emu_t* emu) { ST(1).d = log2(ST0.d)*ST(1).d; } void arm_ftan(x64emu_t* emu) { ST0.d = tan(ST0.d); } void arm_fpatan(x64emu_t* emu) { ST1.d = atan2(ST1.d, ST0.d); } void arm_fxtract(x64emu_t* emu) { int32_t tmp32s = (ST1.q&0x7ff0000000000000LL)>>52; tmp32s -= 1023; ST1.d /= exp2(tmp32s); ST0.d = tmp32s; } void arm_fprem(x64emu_t* emu) { int32_t tmp32s = ST0.d / ST1.d; ST0.d -= ST1.d * tmp32s; emu->sw.f.F87_C2 = 0; emu->sw.f.F87_C0 = (tmp32s&1); emu->sw.f.F87_C3 = ((tmp32s>>1)&1); emu->sw.f.F87_C1 = ((tmp32s>>2)&1); } void arm_fyl2xp1(x64emu_t* emu) { ST(1).d = log2(ST0.d + 1.0)*ST(1).d; } void arm_fsincos(x64emu_t* emu) { sincos(ST1.d, &ST1.d, &ST0.d); } void arm_frndint(x64emu_t* emu) { ST0.d = fpu_round(emu, ST0.d); } void arm_fscale(x64emu_t* emu) { ST0.d *= exp2(trunc(ST1.d)); } void arm_fsin(x64emu_t* emu) { ST0.d = sin(ST0.d); } void arm_fcos(x64emu_t* emu) { ST0.d = cos(ST0.d); } void arm_fbld(x64emu_t* emu, uint8_t* ed) { fpu_fbld(emu, ed); } void arm_fild64(x64emu_t* emu, int64_t* ed) { int64_t tmp; memcpy(&tmp, ed, sizeof(tmp)); ST0.d = tmp; STll(0).ll = tmp; STll(0).ref = ST0.q; } void arm_fbstp(x64emu_t* emu, uint8_t* ed) { fpu_fbst(emu, ed); } void arm_fistp64(x64emu_t* emu, int64_t* ed) { // used of memcpy to avoid aligments issues if(STll(0).ref==ST(0).q) { memcpy(ed, &STll(0).ll, sizeof(int64_t)); } else { int64_t tmp; if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, (double)(int64_t)0x8000000000000000LL) || !isfinite(ST0.d)) tmp = 0x8000000000000000LL; else tmp = fpu_round(emu, ST0.d); memcpy(ed, &tmp, sizeof(tmp)); } } void arm_fistt64(x64emu_t* emu, int64_t* ed) { // used of memcpy to avoid aligments issues int64_t tmp = ST0.d; memcpy(ed, &tmp, sizeof(tmp)); } void arm_fld(x64emu_t* emu, uint8_t* ed) { memcpy(&STld(0).ld, ed, 10); LD2D(&STld(0), &ST(0).d); STld(0).ref = ST0.q; } void arm_ud(x64emu_t* emu) { emit_signal(emu, SIGILL, (void*)R_RIP, 0); } void arm_fsave(x64emu_t* emu, uint8_t* ed) { fpu_savenv(emu, (char*)ed, 0); uint8_t* p = ed; p += 28; for (int i=0; i<8; ++i) { LD2D(p, &ST(i).d); p+=10; } } void arm_frstor(x64emu_t* emu, uint8_t* ed) { fpu_loadenv(emu, (char*)ed, 0); uint8_t* p = ed; p += 28; for (int i=0; i<8; ++i) { D2LD(&ST(i).d, p); p+=10; } } void arm_fprem1(x64emu_t* emu) { // simplified version int32_t tmp32s = round(ST0.d / ST1.d); ST0.d -= ST1.d*tmp32s; emu->sw.f.F87_C2 = 0; emu->sw.f.F87_C0 = (tmp32s&1); emu->sw.f.F87_C3 = ((tmp32s>>1)&1); emu->sw.f.F87_C1 = ((tmp32s>>2)&1); } #define XMM0 0 #define XMM8 16 #define X870 8 #define EMM0 8 #define SCRATCH0 24 // Get a FPU scratch reg int fpu_get_scratch(dynarec_arm_t* dyn) { return SCRATCH0 + dyn->fpu_scratch++; // return an Sx } // Reset scratch regs counter void fpu_reset_scratch(dynarec_arm_t* dyn) { dyn->fpu_scratch = 0; } // Get a x87 double reg int fpu_get_reg_x87(dynarec_arm_t* dyn) { int i=X870; while (dyn->fpuused[i]) ++i; dyn->fpuused[i] = 1; return i; // return a Dx } // Free a FPU double reg void fpu_free_reg(dynarec_arm_t* dyn, int reg) { // TODO: check upper limit? dyn->fpuused[reg] = 0; } // Get an MMX double reg int fpu_get_reg_emm(dynarec_arm_t* dyn, int emm) { dyn->fpuused[EMM0 + emm] = 1; return EMM0 + emm; } // Get an XMM quad reg int fpu_get_reg_xmm(dynarec_arm_t* dyn, int xmm) { if(xmm>7) { dyn->fpuused[XMM8 + xmm - 8] = 1; return XMM8 + xmm - 8; } else { dyn->fpuused[XMM0 + xmm] = 1; return XMM0 + xmm; } } // Reset fpu regs counter void fpu_reset_reg(dynarec_arm_t* dyn) { dyn->fpu_reg = 0; for (int i=0; i<32; ++i) dyn->fpuused[i]=0; } #define F8 *(uint8_t*)(addr++) #define F32 *(uint32_t*)(addr+=4, addr-4) #define F32S64 (uint64_t)(int64_t)*(int32_t*)(addr+=4, addr-4) // Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity, int delta) { uint32_t tested = (1<>3)&7; if((sib&0x7)==5) { uint64_t tmp = F32S64; if (sib_reg!=4) { // if XXXXXX+reg<>6)>=parity)?1:0; } else { // just a constant... return (tmp&tested)?0:1; } } else { if(sib_reg==4 && parity<3) return 0; // simple [reg] // don't try [reg1 + reg2<>6)>=parity)?1:0; } } else if((nextop&7)==5) { uint64_t tmp = F32S64; tmp+=addr+delta; return (tmp&tested)?0:1; } else { return 0; } } else { return 0; //Form [reg1 + reg2<CC==0xCC && b->S=='S' && b->C=='C' && b->w!=(wrapper_t)0 && b->f!=(uintptr_t)PltResolver) { // found ! if(retn) *retn = (b->C3==0xC2)?b->N:0; if(calladdress) *calladdress = addr+1; return 1; } return 0; #undef PK32 #undef PK }