about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorYang Liu <liuyang22@iscas.ac.cn>2024-10-06 18:19:55 +0800
committerGitHub <noreply@github.com>2024-10-06 12:19:55 +0200
commit172df2cd0cade8c591bbff7a7e288bc867c01c9e (patch)
treee5b7892ee496f45b8e3f7ad97ad9d457d008c9d9
parentb395cd7ccc0a3b98b82306a35a2d96a9d42c5d7d (diff)
downloadbox64-172df2cd0cade8c591bbff7a7e288bc867c01c9e.tar.gz
box64-172df2cd0cade8c591bbff7a7e288bc867c01c9e.zip
[DYNAREC] Tweaking indirect jumps for CALL/RET to use the return address stack (#1907)
-rw-r--r--src/dynarec/arm64/arm64_emitter.h1
-rw-r--r--src/dynarec/arm64/dynarec_arm64_helper.c18
-rw-r--r--src/dynarec/la64/dynarec_la64_helper.c14
-rw-r--r--src/dynarec/rv64/dynarec_rv64_helper.c20
-rw-r--r--src/dynarec/rv64/rv64_emitter.h4
5 files changed, 31 insertions, 26 deletions
diff --git a/src/dynarec/arm64/arm64_emitter.h b/src/dynarec/arm64/arm64_emitter.h
index bab9222c..4dc681e7 100644
--- a/src/dynarec/arm64/arm64_emitter.h
+++ b/src/dynarec/arm64/arm64_emitter.h
@@ -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))
diff --git a/src/dynarec/arm64/dynarec_arm64_helper.c b/src/dynarec/arm64/dynarec_arm64_helper.c
index 5e2ed69d..f4497b61 100644
--- a/src/dynarec/arm64/dynarec_arm64_helper.c
+++ b/src/dynarec/arm64/dynarec_arm64_helper.c
@@ -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)
@@ -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);
     }
@@ -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();
 }
 
@@ -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);
     }
@@ -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();
 }
 
diff --git a/src/dynarec/la64/dynarec_la64_helper.c b/src/dynarec/la64/dynarec_la64_helper.c
index 1d23f10a..b33445f3 100644
--- a/src/dynarec/la64/dynarec_la64_helper.c
+++ b/src/dynarec/la64/dynarec_la64_helper.c
@@ -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)
@@ -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);
     }
@@ -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();
 }
 
@@ -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);
     }
@@ -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();
 }
 
diff --git a/src/dynarec/rv64/dynarec_rv64_helper.c b/src/dynarec/rv64/dynarec_rv64_helper.c
index 408312dd..7c572092 100644
--- a/src/dynarec/rv64/dynarec_rv64_helper.c
+++ b/src/dynarec/rv64/dynarec_rv64_helper.c
@@ -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)
@@ -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);
@@ -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();
 }
 
@@ -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);
@@ -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();
 }
 
@@ -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);
     }
@@ -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);
diff --git a/src/dynarec/rv64/rv64_emitter.h b/src/dynarec/rv64/rv64_emitter.h
index 7076a467..342bf818 100644
--- a/src/dynarec/rv64/rv64_emitter.h
+++ b/src/dynarec/rv64/rv64_emitter.h
@@ -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))