diff options
| author | Yang Liu <liuyang22@iscas.ac.cn> | 2024-12-26 01:52:32 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-12-25 18:52:32 +0100 |
| commit | 21a21b04e6b678cbdd88172c0d162e82f2190c9f (patch) | |
| tree | 2ef432c3ab03e8a7bc44d5562a26fe030f6c98dc /src | |
| parent | 87e19076ad6836cac80ea945a9f973279d91a5b9 (diff) | |
| download | box64-21a21b04e6b678cbdd88172c0d162e82f2190c9f.tar.gz box64-21a21b04e6b678cbdd88172c0d162e82f2190c9f.zip | |
[LA64_DYNAREC] Added IRET opcode (#2210)
Diffstat (limited to 'src')
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_00.c | 8 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_helper.c | 43 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_helper.h | 2 |
3 files changed, 53 insertions, 0 deletions
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c index 8a863667..a5a8f459 100644 --- a/src/dynarec/la64/dynarec_la64_00.c +++ b/src/dynarec/la64/dynarec_la64_00.c @@ -1908,6 +1908,14 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni } } break; + case 0xCF: + INST_NAME("IRET"); + SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION); // Not a hack, EFLAGS are restored + BARRIER(BARRIER_FLOAT); + iret_to_epilog(dyn, ninst, rex.w); + *need_epilog = 0; + *ok = 0; + break; case 0xD0: case 0xD2: // TODO: Jump if CL is 0 nextop = F8; diff --git a/src/dynarec/la64/dynarec_la64_helper.c b/src/dynarec/la64/dynarec_la64_helper.c index e752ac96..48e5fc10 100644 --- a/src/dynarec/la64/dynarec_la64_helper.c +++ b/src/dynarec/la64/dynarec_la64_helper.c @@ -658,6 +658,49 @@ void retn_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex, int n) CLEARIP(); } +void iret_to_epilog(dynarec_la64_t* dyn, int ninst, int is64bits) +{ + // #warning TODO: is64bits + MAYUSE(ninst); + MESSAGE(LOG_DUMP, "IRet to epilog\n"); + NOTEST(x2); + if (is64bits) { + POP1(xRIP); + POP1(x2); + POP1(xFlags); + } else { + POP1_32(xRIP); + POP1_32(x2); + POP1_32(xFlags); + } + + ST_H(x2, xEmu, offsetof(x64emu_t, segs[_CS])); + ST_W(xZR, xEmu, offsetof(x64emu_t, segs_serial[_CS])); + // clean EFLAGS + MOV32w(x1, 0x3F7FD7); + AND(xFlags, xFlags, x1); + ORI(xFlags, xFlags, 0x2); + SET_DFNONE(); + // POP RSP + if (is64bits) { + POP1(x3); // rsp + POP1(x2); // ss + } else { + POP1_32(x3); // rsp + POP1_32(x2); // ss + } + // POP SS + ST_H(x2, xEmu, offsetof(x64emu_t, segs[_SS])); + ST_W(xZR, xEmu, offsetof(x64emu_t, segs_serial[_SS])); + // set new RSP + MV(xRSP, x3); + // Ret.... + MOV64x(x2, (uintptr_t)la64_epilog); // epilog on purpose, CS might have changed! + SMEND(); + BR(x2); + CLEARIP(); +} + void call_c(dynarec_la64_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int savereg) { MAYUSE(fnc); diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h index 15f9bb15..7eaaac30 100644 --- a/src/dynarec/la64/dynarec_la64_helper.h +++ b/src/dynarec/la64/dynarec_la64_helper.h @@ -838,6 +838,7 @@ void* la64_next(x64emu_t* emu, uintptr_t addr); #define jump_to_next STEPNAME(jump_to_next) #define ret_to_epilog STEPNAME(ret_to_epilog) #define retn_to_epilog STEPNAME(retn_to_epilog) +#define iret_to_epilog STEPNAME(iret_to_epilog) #define call_c STEPNAME(call_c) #define grab_segdata STEPNAME(grab_segdata) #define emit_cmp16 STEPNAME(emit_cmp16) @@ -946,6 +947,7 @@ void jump_to_epilog_fast(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst); void jump_to_next(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst, int is32bits); void ret_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex); void retn_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex, int n); +void iret_to_epilog(dynarec_la64_t* dyn, int ninst, int is64bits); void call_c(dynarec_la64_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int save_reg); void grab_segdata(dynarec_la64_t* dyn, uintptr_t addr, int ninst, int reg, int segment); void emit_cmp8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5, int s6); |