diff options
| author | xctan <xctan@cirno.icu> | 2024-04-28 21:27:10 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-28 15:27:10 +0200 |
| commit | 41ae74757e3b5249852551539976d507bbeeb3b6 (patch) | |
| tree | 1067ea767c96e28400e57ece2a55d1872c4d3f53 /src | |
| parent | 2304738336d72d0a3df1c6652cb2785751747b9a (diff) | |
| download | box64-41ae74757e3b5249852551539976d507bbeeb3b6.tar.gz box64-41ae74757e3b5249852551539976d507bbeeb3b6.zip | |
[RV64_DYNAREC] Fixed DIV and IDIV for zero divisor (#1476)
* [RV64_DYNAREC] Fixed DIV Ed and IDIV Ed for zero divisor * [RV64_DYNAREC] Fixed DIV Ew and IDIV Ew for zero divisor * [LA64_DYNAREC] Added todos for zero divisor
Diffstat (limited to 'src')
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_00.c | 2 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_00_3.c | 96 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_66.c | 20 |
3 files changed, 105 insertions, 13 deletions
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c index 38a7abdd..64e8ba5f 100644 --- a/src/dynarec/la64/dynarec_la64_00.c +++ b/src/dynarec/la64/dynarec_la64_00.c @@ -1723,6 +1723,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni case 6: INST_NAME("DIV Ed"); SETFLAGS(X_ALL, SF_SET); + // TODO: handle zero divisor if (!rex.w) { SET_DFNONE(); GETED(0); @@ -1765,6 +1766,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni INST_NAME("IDIV Ed"); SKIPTEST(x1); SETFLAGS(X_ALL, SF_SET); + // TODO: handle zero divisor if (!rex.w) { SET_DFNONE() GETSED(0); diff --git a/src/dynarec/rv64/dynarec_rv64_00_3.c b/src/dynarec/rv64/dynarec_rv64_00_3.c index 93bf1690..015c2df9 100644 --- a/src/dynarec/rv64/dynarec_rv64_00_3.c +++ b/src/dynarec/rv64/dynarec_rv64_00_3.c @@ -1125,17 +1125,39 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int if(!rex.w) { SET_DFNONE(); GETED(0); - SLLI(x3, xRDX, 32); - AND(x2, xRAX, xMASK); - OR(x3, x3, x2); - if(MODREG) { - AND(x4, ed, xMASK); - ed = x4; + if(ninst && (nextop==0xF0) + && dyn->insts[ninst-1].x64.addr + && *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0xB8 + && *(uint32_t*)(dyn->insts[ninst-1].x64.addr+1)==0) { + // hack for some protection that check a divide by zero actualy trigger a divide by zero exception + MESSAGE(LOG_INFO, "Divide by 0 hack\n"); + GETIP(ip); + STORE_XEMU_CALL(x3); + CALL(native_div0, -1); + LOAD_XEMU_CALL(); + } else { + if(box64_dynarec_div0) { + BNE_MARK3(ed, xZR); + GETIP_(ip); + STORE_XEMU_CALL(x3); + CALL(native_div0, -1); + CLEARIP(); + LOAD_XEMU_CALL(); + jump_to_epilog(dyn, 0, xRIP, ninst); + MARK3; + } + SLLI(x3, xRDX, 32); + AND(x2, xRAX, xMASK); + OR(x3, x3, x2); + if(MODREG) { + AND(x4, ed, xMASK); + ed = x4; + } + DIVU(x2, x3, ed); + REMU(xRDX, x3, ed); + AND(xRAX, x2, xMASK); + ZEROUP(xRDX); } - DIVU(x2, x3, ed); - REMU(xRDX, x3, ed); - AND(xRAX, x2, xMASK); - ZEROUP(xRDX); } else { if(ninst && dyn->insts[ninst-1].x64.addr @@ -1143,11 +1165,31 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int && *(uint8_t*)(dyn->insts[ninst-1].x64.addr+1)==0xD2) { SET_DFNONE(); GETED(0); + if(box64_dynarec_div0) { + BNE_MARK3(ed, xZR); + GETIP_(ip); + STORE_XEMU_CALL(x3); + CALL(native_div0, -1); + CLEARIP(); + LOAD_XEMU_CALL(); + jump_to_epilog(dyn, 0, xRIP, ninst); + MARK3; + } DIVU(x2, xRAX, ed); REMU(xRDX, xRAX, ed); MV(xRAX, x2); } else { GETEDH(x1, 0); // get edd changed addr, so cannot be called 2 times for same op... + if(box64_dynarec_div0) { + BNE_MARK3(ed, xZR); + GETIP_(ip); + STORE_XEMU_CALL(x3); + CALL(native_div0, -1); + CLEARIP(); + LOAD_XEMU_CALL(); + jump_to_epilog(dyn, 0, xRIP, ninst); + MARK3; + } BEQ_MARK(xRDX, xZR); if(ed!=x1) {MV(x1, ed);} CALL(div64, -1); @@ -1164,9 +1206,19 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int INST_NAME("IDIV Ed"); SKIPTEST(x1); SETFLAGS(X_ALL, SF_SET); + SET_DFNONE() if(!rex.w) { - SET_DFNONE() GETSED(0); + if(box64_dynarec_div0) { + BNE_MARK3(ed, xZR); + GETIP_(ip); + STORE_XEMU_CALL(x3); + CALL(native_div0, -1); + CLEARIP(); + LOAD_XEMU_CALL(); + jump_to_epilog(dyn, 0, xRIP, ninst); + MARK3; + } SLLI(x3, xRDX, 32); AND(x2, xRAX, xMASK); OR(x3, x3, x2); @@ -1179,13 +1231,32 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int && dyn->insts[ninst-1].x64.addr && *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0x48 && *(uint8_t*)(dyn->insts[ninst-1].x64.addr+1)==0x99) { - SET_DFNONE() GETED(0); + if(box64_dynarec_div0) { + BNE_MARK3(ed, xZR); + GETIP_(ip); + STORE_XEMU_CALL(x3); + CALL(native_div0, -1); + CLEARIP(); + LOAD_XEMU_CALL(); + jump_to_epilog(dyn, 0, xRIP, ninst); + MARK3; + } DIV(x2, xRAX, ed); REM(xRDX, xRAX, ed); MV(xRAX, x2); } else { GETEDH(x1, 0); // get edd changed addr, so cannot be called 2 times for same op... + if(box64_dynarec_div0) { + BNE_MARK3(ed, xZR); + GETIP_(ip); + STORE_XEMU_CALL(x3); + CALL(native_div0, -1); + CLEARIP(); + LOAD_XEMU_CALL(); + jump_to_epilog(dyn, 0, xRIP, ninst); + MARK3; + } //Need to see if RDX==0 and RAX not signed // or RDX==-1 and RAX signed BNE_MARK2(xRDX, xZR); @@ -1202,7 +1273,6 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int DIV(x2, xRAX, ed); REM(xRDX, xRAX, ed); MV(xRAX, x2); - SET_DFNONE() } } break; diff --git a/src/dynarec/rv64/dynarec_rv64_66.c b/src/dynarec/rv64/dynarec_rv64_66.c index f9538fbf..c5ace2f5 100644 --- a/src/dynarec/rv64/dynarec_rv64_66.c +++ b/src/dynarec/rv64/dynarec_rv64_66.c @@ -1215,6 +1215,16 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni SLLI(x3, xRDX, 48); SRLI(x3, x3, 32); OR(x2, x2, x3); + if(box64_dynarec_div0) { + BNE_MARK3(ed, xZR); + GETIP_(ip); + STORE_XEMU_CALL(x6); + CALL(native_div0, -1); + CLEARIP(); + LOAD_XEMU_CALL(); + jump_to_epilog(dyn, 0, xRIP, ninst); + MARK3; + } DIVUW(x3, x2, ed); REMUW(x4, x2, ed); MOV64x(x5, ~0xffff); @@ -1231,6 +1241,16 @@ uintptr_t dynarec64_66(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int ni NOTEST(x1); SETFLAGS(X_ALL, SF_SET); GETSEW(x1, 0); + if(box64_dynarec_div0) { + BNE_MARK3(ed, xZR); + GETIP_(ip); + STORE_XEMU_CALL(x6); + CALL(native_div0, -1); + CLEARIP(); + LOAD_XEMU_CALL(); + jump_to_epilog(dyn, 0, xRIP, ninst); + MARK3; + } ZEXTH(x2, xRAX); SLLI(x3, xRDX, 48); SRLI(x3, x3, 32); |