Skip to content

Commit

Permalink
[DYNAREC] Tweaking indirect jumps for CALL/RET to use the return addr…
Browse files Browse the repository at this point in the history
…ess stack (#1907)
  • Loading branch information
ksco authored Oct 6, 2024
1 parent b395cd7 commit 172df2c
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 26 deletions.
1 change: 1 addition & 0 deletions src/dynarec/arm64/arm64_emitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,7 @@ int convert_bitmask(uint64_t bitmask);
#define BR_gen(Z, op, A, M, Rn, Rm) (0b1101011<<25 | (Z)<<24 | (op)<<21 | 0b11111<<16 | (A)<<11 | (M)<<10 | (Rn)<<5 | (Rm))
#define BR(Rn) EMIT(BR_gen(0, 0b00, 0, 0, Rn, 0))
#define BLR(Rn) EMIT(BR_gen(0, 0b01, 0, 0, Rn, 0))
#define RET(Rn) EMIT(BR_gen(0, 0b10, 0, 0, Rn, 0))

#define CB_gen(sf, op, imm19, Rt) ((sf)<<31 | 0b011010<<25 | (op)<<24 | (imm19)<<5 | (Rt))
#define CBNZx(Rt, imm19) EMIT(CB_gen(1, 1, ((imm19)>>2)&0x7FFFF, Rt))
Expand Down
18 changes: 11 additions & 7 deletions src/dynarec/arm64/dynarec_arm64_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,11 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32
#ifdef HAVE_TRACE
//MOVx(x3, 15); no access to PC reg
#endif
BLR(x2); // save LR...
if (dyn->insts[ninst].x64.has_callret) {
BLR(x2); // save LR...
} else {
BR(x2);
}
}

void ret_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex)
Expand All @@ -622,10 +626,10 @@ void ret_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex)
SMEND();
if(box64_dynarec_callret) {
// pop the actual return address for ARM stack
LDPx_S7_postindex(x2, x6, xSP, 16);
LDPx_S7_postindex(xLR, x6, xSP, 16);
SUBx_REG(x6, x6, xRIP); // is it the right address?
CBNZx(x6, 2*4);
BLR(x2);
RET(xLR);
// not the correct return address, regular jump, but purge the stack first, it's unsync now...
SUBx_U12(xSP, xSavedSP, 16);
}
Expand All @@ -646,7 +650,7 @@ void ret_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex)
LDRx_REG_LSL3(x2, x2, x3);
UBFXx(x3, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
LDRx_REG_LSL3(x2, x2, x3);
BLR(x2); // save LR
BR(x2);
CLEARIP();
}

Expand All @@ -665,10 +669,10 @@ void retn_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex, int n)
SMEND();
if(box64_dynarec_callret) {
// pop the actual return address for ARM stack
LDPx_S7_postindex(x2, x6, xSP, 16);
LDPx_S7_postindex(xLR, x6, xSP, 16);
SUBx_REG(x6, x6, xRIP); // is it the right address?
CBNZx(x6, 2*4);
BLR(x2);
RET(xLR);
// not the correct return address, regular jump
SUBx_U12(xSP, xSavedSP, 16);
}
Expand All @@ -689,7 +693,7 @@ void retn_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex, int n)
LDRx_REG_LSL3(x2, x2, x3);
UBFXx(x3, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
LDRx_REG_LSL3(x2, x2, x3);
BLR(x2); // save LR
BR(x2);
CLEARIP();
}

Expand Down
14 changes: 7 additions & 7 deletions src/dynarec/la64/dynarec_la64_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ void jump_to_next(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst, int is3
// MOVx(x3, 15); no access to PC reg
#endif
SMEND();
JIRL(xRA, x2, 0x0); // save LR...
JIRL((dyn->insts[ninst].x64.has_callret ? xRA : xZR), x2, 0x0); // save LR...
}

void ret_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex)
Expand All @@ -584,11 +584,11 @@ void ret_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex)
SMEND();
if (box64_dynarec_callret) {
// pop the actual return address from RV64 stack
LD_D(x2, xSP, 0); // native addr
LD_D(xRA, xSP, 0); // native addr
LD_D(x6, xSP, 8); // x86 addr
ADDI_D(xSP, xSP, 16); // pop
BNE(x6, xRIP, 2 * 4); // is it the right address?
BR(x2);
BR(xRA);
// not the correct return address, regular jump, but purge the stack first, it's unsync now...
ADDI_D(xSP, xSavedSP, -16);
}
Expand All @@ -609,7 +609,7 @@ void ret_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex)
BSTRPICK_D(x2, xRIP, JMPTABL_START0 + JMPTABL_SHIFT0 - 1, JMPTABL_START0);
ALSL_D(x3, x2, x3, 3);
LD_D(x2, x3, 0);
BR(x2); // save LR
BR(x2);
CLEARIP();
}

Expand All @@ -629,11 +629,11 @@ void retn_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex, int n)
SMEND();
if (box64_dynarec_callret) {
// pop the actual return address from RV64 stack
LD_D(x2, xSP, 0); // native addr
LD_D(xRA, xSP, 0); // native addr
LD_D(x6, xSP, 8); // x86 addr
ADDI_D(xSP, xSP, 16); // pop
BNE(x6, xRIP, 2 * 4); // is it the right address?
BR(x2);
BR(xRA);
// not the correct return address, regular jump, but purge the stack first, it's unsync now...
ADDI_D(xSP, xSavedSP, -16);
}
Expand All @@ -654,7 +654,7 @@ void retn_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex, int n)
BSTRPICK_D(x2, xRIP, JMPTABL_START0 + JMPTABL_SHIFT0 - 1, JMPTABL_START0);
ALSL_D(x3, x2, x3, 3);
LD_D(x2, x3, 0);
BR(x2); // save LR
BR(x2);
CLEARIP();
}

Expand Down
20 changes: 10 additions & 10 deletions src/dynarec/rv64/dynarec_rv64_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,7 @@ void jump_to_next(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst, int is3
//MOVx(x3, 15); no access to PC reg
#endif
SMEND();
JALR(x2); // save LR...
JALR((dyn->insts[ninst].x64.has_callret ? xRA : xZR), x2);
}

void ret_to_epilog(dynarec_rv64_t* dyn, int ninst, rex_t rex)
Expand All @@ -592,11 +592,11 @@ void ret_to_epilog(dynarec_rv64_t* dyn, int ninst, rex_t rex)
SMEND();
if (box64_dynarec_callret) {
// pop the actual return address from RV64 stack
LD(x2, xSP, 0); // native addr
LD(xRA, xSP, 0); // native addr
LD(x6, xSP, 8); // x86 addr
ADDI(xSP, xSP, 16); // pop
BNE(x6, xRIP, 2*4); // is it the right address?
JALR(x2);
BR(xRA);
// not the correct return address, regular jump, but purge the stack first, it's unsync now...
LD(xSP, xEmu, offsetof(x64emu_t, xSPSave));
ADDI(xSP, xSP, -16);
Expand Down Expand Up @@ -631,7 +631,7 @@ void ret_to_epilog(dynarec_rv64_t* dyn, int ninst, rex_t rex)
}
if(rv64_zba) SH3ADD(x3, x2, x3); else {SLLI(x2, x2, 3); ADD(x3, x3, x2);}
LD(x2, x3, 0);
JALR(x2); // save LR
BR(x2);
CLEARIP();
}

Expand All @@ -650,11 +650,11 @@ void retn_to_epilog(dynarec_rv64_t* dyn, int ninst, rex_t rex, int n)
SMEND();
if (box64_dynarec_callret) {
// pop the actual return address from RV64 stack
LD(x2, xSP, 0); // native addr
LD(xRA, xSP, 0); // native addr
LD(x6, xSP, 8); // x86 addr
ADDI(xSP, xSP, 16); // pop
BNE(x6, xRIP, 2*4); // is it the right address?
JALR(x2);
BR(xRA);
// not the correct return address, regular jump, but purge the stack first, it's unsync now...
LD(xSP, xEmu, offsetof(x64emu_t, xSPSave));
ADDI(xSP, xSP, -16);
Expand Down Expand Up @@ -688,7 +688,7 @@ void retn_to_epilog(dynarec_rv64_t* dyn, int ninst, rex_t rex, int n)
}
if(rv64_zba) SH3ADD(x3, x2, x3); else {SLLI(x2, x2, 3); ADD(x3, x3, x2);}
LD(x2, x3, 0);
JALR(x2); // save LR
BR(x2);
CLEARIP();
}

Expand Down Expand Up @@ -760,7 +760,7 @@ void call_c(dynarec_rv64_t* dyn, int ninst, void* fnc, int reg, int ret, int sav
SD(xRIP, xEmu, offsetof(x64emu_t, ip));
}
TABLE64(reg, (uintptr_t)fnc);
JALR(reg);
JALR(xRA, reg);
if(ret>=0) {
MV(ret, xEmu);
}
Expand Down Expand Up @@ -833,8 +833,8 @@ void call_n(dynarec_rv64_t* dyn, int ninst, void* fnc, int w)
MV(A4, xR8);
MV(A5, xR9);
// native call
TABLE64(16, (uintptr_t)fnc); // using x16 as scratch regs for call address
JALR(16);
TABLE64(xRAX, (uintptr_t)fnc); // using xRAX as scratch regs for call address
JALR(xRA, xRAX);
// put return value in x64 regs
if(w>0) {
MV(xRAX, A0);
Expand Down
4 changes: 2 additions & 2 deletions src/dynarec/rv64/rv64_emitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,9 @@ f28–31 ft8–11 FP temporaries Caller
// Unconditionnal branch to r+i12, no return address set
#define BR_I12(r, imm12) EMIT(JALR_gen(xZR, r, (imm12) & 0b111111111111))
// Unconditionnal branch to r, return address set to xRA
#define JALR(r) EMIT(JALR_gen(xRA, r, 0))
#define JALR(rd, rs) EMIT(JALR_gen(rd, rs, 0))
// Unconditionnal branch to r+i12, return address set to xRA
#define JALR_I12(r, imm12) EMIT(JALR_gen(xRA, r, (imm12) & 0b111111111111))
#define JALR_I12(rd, rs, imm12) EMIT(JALR_gen(rd, rs, (imm12) & 0b111111111111))

// rd = rs1 + imm12
#define ADDI(rd, rs1, imm12) EMIT(I_type((imm12) & 0b111111111111, rs1, 0b000, rd, 0b0010011))
Expand Down

0 comments on commit 172df2c

Please sign in to comment.