about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/arm64/dynarec_arm64_00.c23
-rw-r--r--src/dynarec/arm64/dynarec_arm64_64.c1
-rw-r--r--src/dynarec/arm64/dynarec_arm64_660f.c2
-rw-r--r--src/dynarec/arm64/dynarec_arm64_67.c1
-rw-r--r--src/dynarec/arm64/dynarec_arm64_avx_66_0f.c2
-rw-r--r--src/dynarec/arm64/dynarec_arm64_avx_66_0f38.c2
-rw-r--r--src/dynarec/arm64/dynarec_arm64_consts.c1
-rw-r--r--src/dynarec/arm64/dynarec_arm64_consts.h1
-rw-r--r--src/dynarec/arm64/dynarec_arm64_helper.c3
-rw-r--r--src/dynarec/arm64/dynarec_arm64_helper.h15
-rw-r--r--src/dynarec/arm64/dynarec_arm64_pass2.h15
-rw-r--r--src/dynarec/arm64/dynarec_arm64_pass3.h18
-rw-r--r--src/dynarec/arm64/dynarec_arm64_private.h4
-rw-r--r--src/dynarec/dynablock_private.h1
-rw-r--r--src/dynarec/dynacache_reloc.c162
-rw-r--r--src/dynarec/dynacache_reloc.h20
-rw-r--r--src/dynarec/dynarec_arch.h2
-rw-r--r--src/dynarec/dynarec_native.c21
-rw-r--r--src/dynarec/la64/dynarec_la64_private.h4
-rw-r--r--src/dynarec/rv64/dynarec_rv64_private.h4
-rw-r--r--src/include/env.h4
-rw-r--r--src/tools/env.c18
-rw-r--r--src/wrapped/generated/functions_list.txt1
23 files changed, 291 insertions, 34 deletions
diff --git a/src/dynarec/arm64/dynarec_arm64_00.c b/src/dynarec/arm64/dynarec_arm64_00.c
index 2947ee42..75d963af 100644
--- a/src/dynarec/arm64/dynarec_arm64_00.c
+++ b/src/dynarec/arm64/dynarec_arm64_00.c
@@ -2626,7 +2626,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                 INST_NAME("INT 3");
                 if(!BOX64ENV(ignoreint3)) {
                     // check if TRAP signal is handled
-                    TABLE64(x1, (uintptr_t)my_context);
+                    TABLE64C(x1, const_context);
                     MOV32w(x2, offsetof(box64context_t, signals[SIGTRAP]));
                     LDRx_REG(x3, x1, x2);
                     //LDRx_U12(x3, x1, offsetof(box64context_t, signals[SIGTRAP]));
@@ -4129,7 +4129,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                         // jumps out of current dynablock...
                         MARK;
                         j64 = getJumpTableAddress64(addr);
-                        TABLE64(x4, j64);
+                        if(dyn->need_reloc) AddRelocTable64RetEndBlock(dyn, ninst, addr, STEP);
+                        TABLE64_(x4, j64);
                         LDRx_U12(x4, x4, 0);
                         BR(x4);
                     }
@@ -4148,24 +4149,6 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                         LDH(x3, wback, rex.w?8:4);
                         LDH(x4, xEmu, offsetof(x64emu_t, segs[_CS]));
                         GETIP_(addr);
-                        /*
-                        if(BOX64DRENV(dynarec_callret)) {
-                            SET_HASCALLRET();
-                            // Push actual return address
-                            if(addr < (dyn->start+dyn->isize)) {
-                                // there is a next...
-                                j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;
-                                ADR_S20(x4, j64);
-                                MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
-                            } else {
-                                MESSAGE(LOG_NONE, "\tCALLRET set return to Jmptable(%p)\n", (void*)addr);
-                                j64 = getJumpTableAddress64(addr);
-                                TABLE64(x4, j64);
-                                LDRx_U12(x4, x4, 0);
-                            }
-                            STPx_S7_preindex(x4, xRIP, xSP, -16);
-                        }
-                        */
                         // not doing callret because call far will exit the dynablock anyway, to be sure to recompute CS segment
                         PUSH1z(x4);
                         PUSH1z(xRIP);
diff --git a/src/dynarec/arm64/dynarec_arm64_64.c b/src/dynarec/arm64/dynarec_arm64_64.c
index 73f0ee9a..de10a343 100644
--- a/src/dynarec/arm64/dynarec_arm64_64.c
+++ b/src/dynarec/arm64/dynarec_arm64_64.c
@@ -1647,6 +1647,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                         // jumps out of current dynablock...
                         MARK;
                         j64 = getJumpTableAddress64(addr);
+                        if(dyn->need_reloc) AddRelocTable64RetEndBlock(dyn, ninst, addr, STEP);
                         TABLE64(x4, j64);
                         LDRx_U12(x4, x4, 0);
                         BR(x4);
diff --git a/src/dynarec/arm64/dynarec_arm64_660f.c b/src/dynarec/arm64/dynarec_arm64_660f.c
index d1581b5d..3acd6dfe 100644
--- a/src/dynarec/arm64/dynarec_arm64_660f.c
+++ b/src/dynarec/arm64/dynarec_arm64_660f.c
@@ -3038,7 +3038,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
                 q1 = fpu_get_scratch(dyn, ninst);

                 GETEX(q0, 0, 0);

                 GETGD;

-                TABLE64(x2, 0x0706050403020100LL);

+                TABLE64_(x2, 0x0706050403020100LL);

                 VDUPQD(v0, x2);

                 VSHRQ_8(q1, q0, 7);

                 USHLQ_8(q1, q1, v0); // shift

diff --git a/src/dynarec/arm64/dynarec_arm64_67.c b/src/dynarec/arm64/dynarec_arm64_67.c
index b32433ad..f44cb687 100644
--- a/src/dynarec/arm64/dynarec_arm64_67.c
+++ b/src/dynarec/arm64/dynarec_arm64_67.c
@@ -1748,6 +1748,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                         // jumps out of current dynablock...

                         MARK;

                         j64 = getJumpTableAddress64(addr);

+                        if(dyn->need_reloc) AddRelocTable64RetEndBlock(dyn, ninst, addr, STEP);

                         TABLE64(x4, j64);

                         LDRx_U12(x4, x4, 0);

                         BR(x4);

diff --git a/src/dynarec/arm64/dynarec_arm64_avx_66_0f.c b/src/dynarec/arm64/dynarec_arm64_avx_66_0f.c
index b5e1d362..54b9cecc 100644
--- a/src/dynarec/arm64/dynarec_arm64_avx_66_0f.c
+++ b/src/dynarec/arm64/dynarec_arm64_avx_66_0f.c
@@ -1459,7 +1459,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
                 q1 = fpu_get_scratch(dyn, ninst);
                 GETEX_Y(q0, 0, 0);
                 GETGD;
-                TABLE64(x2, 0x0706050403020100LL);
+                TABLE64_(x2, 0x0706050403020100LL);
                 VDUPQD(v0, x2);
                 VSHRQ_8(q1, q0, 7);
                 USHLQ_8(q1, q1, v0); // shift
diff --git a/src/dynarec/arm64/dynarec_arm64_avx_66_0f38.c b/src/dynarec/arm64/dynarec_arm64_avx_66_0f38.c
index e65864bf..d83ac74c 100644
--- a/src/dynarec/arm64/dynarec_arm64_avx_66_0f38.c
+++ b/src/dynarec/arm64/dynarec_arm64_avx_66_0f38.c
@@ -1756,7 +1756,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
             INST_NAME("VFMSUBADD231PS/D Gx, Vx, Ex");
             nextop = F8;
             q0 = fpu_get_scratch(dyn, ninst);
-            TABLE64(x2, rex.w?const_2d_1_m1:const_4f_1_m1_1_m1);
+            TABLE64C(x2, rex.w?const_2d_1_m1:const_4f_1_m1_1_m1);
             VLDR128_U12(q0, x2, 0);
             for(int l=0; l<1+vex.l; ++l) {
                 if(!l) { GETGX_VXEX(v0, v2, v1, 0); if(v0==v2 || v0==v1) q1 = fpu_get_scratch(dyn, ninst); } else { GETGY_VYEY(v0, v2, v1); }
diff --git a/src/dynarec/arm64/dynarec_arm64_consts.c b/src/dynarec/arm64/dynarec_arm64_consts.c
index f412099f..ce59c954 100644
--- a/src/dynarec/arm64/dynarec_arm64_consts.c
+++ b/src/dynarec/arm64/dynarec_arm64_consts.c
@@ -126,6 +126,7 @@ uintptr_t getConst(arm64_consts_t which)
         case const_jmptbl32: return getJumpTable32();
         case const_jmptbl48: return getJumpTable48();
         case const_jmptbl64: return getJumpTable64();
+        case const_context: return (uintptr_t)my_context;
         case const_8b_m7_m6_m5_m4_m3_m2_m1_0: return (uintptr_t)&mask_shift8;
         case const_8b_7_6_5_4_3_2_1_0: return (uintptr_t)&mask_string8;
         case const_8b_15_14_13_12_11_10_9_8: return (uintptr_t)&mask_string16;
diff --git a/src/dynarec/arm64/dynarec_arm64_consts.h b/src/dynarec/arm64/dynarec_arm64_consts.h
index 2c14640b..71e2bdce 100644
--- a/src/dynarec/arm64/dynarec_arm64_consts.h
+++ b/src/dynarec/arm64/dynarec_arm64_consts.h
@@ -88,6 +88,7 @@ typedef enum arm64_consts_s {
     const_jmptbl32,
     const_jmptbl48,
     const_jmptbl64,
+    const_context,
     const_8b_m7_m6_m5_m4_m3_m2_m1_0,
     const_8b_7_6_5_4_3_2_1_0,
     const_8b_15_14_13_12_11_10_9_8,
diff --git a/src/dynarec/arm64/dynarec_arm64_helper.c b/src/dynarec/arm64/dynarec_arm64_helper.c
index 656ee7ad..d4817803 100644
--- a/src/dynarec/arm64/dynarec_arm64_helper.c
+++ b/src/dynarec/arm64/dynarec_arm64_helper.c
@@ -622,7 +622,8 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32
         NOTEST(x2);
         uintptr_t p = getJumpTableAddress64(ip);
         MAYUSE(p);
-        TABLE64(x3, p);
+        if(dyn->need_reloc) AddRelocTable64JmpTbl(dyn, ninst, ip, STEP);
+        TABLE64_(x3, p);
         GETIP_(ip);
         LDRx_U12(x2, x3, 0);
         dest = x2;
diff --git a/src/dynarec/arm64/dynarec_arm64_helper.h b/src/dynarec/arm64/dynarec_arm64_helper.h
index 50c1279a..8806777c 100644
--- a/src/dynarec/arm64/dynarec_arm64_helper.h
+++ b/src/dynarec/arm64/dynarec_arm64_helper.h
@@ -1208,6 +1208,9 @@
 #ifndef TABLE64
 #define TABLE64(A, V)
 #endif
+#ifndef TABLE64_
+#define TABLE64_(A, V)
+#endif
 #ifndef FTABLE64
 #define FTABLE64(A, V)
 #endif
@@ -1235,14 +1238,22 @@
         }                                               \
     } else {                                            \
         dyn->last_ip = (A);                             \
-        MOV64x(xRIP, dyn->last_ip);                     \
+        if(dyn->need_reloc) {                           \
+            TABLE64(xRIP, dyn->last_ip);                \
+        } else {                                        \
+            MOV64x(xRIP, dyn->last_ip);                 \
+        }                                               \
     }
 #define GETIP_(A)                                       \
     if(dyn->last_ip && ((A)-dyn->last_ip)<0x1000) {     \
         uint64_t _delta_ip = (A)-dyn->last_ip;          \
         if(_delta_ip) {ADDx_U12(xRIP, xRIP, _delta_ip);}\
     } else {                                            \
-        MOV64x(xRIP, (A));                              \
+        if(dyn->need_reloc) {                           \
+            TABLE64(xRIP, (A));                         \
+        } else {                                        \
+            MOV64x(xRIP, (A));                          \
+        }                                               \
     }
 #endif
 #define CLEARIP()   dyn->last_ip=0
diff --git a/src/dynarec/arm64/dynarec_arm64_pass2.h b/src/dynarec/arm64/dynarec_arm64_pass2.h
index 02f596a9..6bedf76a 100644
--- a/src/dynarec/arm64/dynarec_arm64_pass2.h
+++ b/src/dynarec/arm64/dynarec_arm64_pass2.h
@@ -15,8 +15,19 @@
         }
 #define INST_EPILOG dyn->insts[ninst].epilog = dyn->native_size; 
 #define INST_NAME(name) 
-#define TABLE64(A, V)   {Table64(dyn, (V), 2); EMIT(0);}
-#define TABLE64C(A, V)  {Table64(dyn, getConst(V), 2); EMIT(0);}
+#define TABLE64(A, V)   {                                                       \
+                if(dyn->need_reloc && !isTable64(dyn, (V)))                     \
+                        AddRelocTable64Addr(dyn, ninst, (V), 2);                \
+                Table64(dyn, (V), 2); EMIT(0);                                  \
+        }
+#define TABLE64_(A, V)   {                                                      \
+                Table64(dyn, (V), 2); EMIT(0);                                  \
+        }
+#define TABLE64C(A, V)  {                                                       \
+                if(dyn->need_reloc && !isTable64(dyn, getConst(V)))             \
+                        AddRelocTable64Const(dyn, ninst, (V), 2);               \
+                Table64(dyn, getConst(V), 2); EMIT(0);                          \
+        }
 #define FTABLE64(A, V)  {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q, 2); EMIT(0);}
 #define CALLRET_RET()   do {dyn->callrets[dyn->callret_size].type = 0; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0)
 #define CALLRET_LOOP()   do {dyn->callrets[dyn->callret_size].type = 1; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0)
\ No newline at end of file
diff --git a/src/dynarec/arm64/dynarec_arm64_pass3.h b/src/dynarec/arm64/dynarec_arm64_pass3.h
index 73f0babf..5930c410 100644
--- a/src/dynarec/arm64/dynarec_arm64_pass3.h
+++ b/src/dynarec/arm64/dynarec_arm64_pass3.h
@@ -24,8 +24,22 @@
     }
 #define INST_EPILOG
 #define INST_NAME(name) inst_name_pass3(dyn, ninst, name, rex)
-#define TABLE64(A, V)   {int val64offset = Table64(dyn, (V), 3); MESSAGE(LOG_DUMP, "  Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset);}
-#define TABLE64C(A, V)  {int val64offset = Table64(dyn, getConst(V), 3); MESSAGE(LOG_DUMP, "  Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset);}
+#define TABLE64(A, V)   {                                                                   \
+                if(dyn->need_reloc && !isTable64(dyn, (V)))                                 \
+                        AddRelocTable64Addr(dyn, ninst, (V), 3);                            \
+                int val64offset = Table64(dyn, (V), 3);                                     \
+                MESSAGE(LOG_DUMP, "  Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset); \
+            }
+#define TABLE64_(A, V)   {                                                                  \
+                int val64offset = Table64(dyn, (V), 3);                                     \
+                MESSAGE(LOG_DUMP, "  Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset); \
+            }
+#define TABLE64C(A, V)  {                                                                   \
+                if(dyn->need_reloc && !isTable64(dyn, getConst(V)))                         \
+                        AddRelocTable64Const(dyn, ninst, (V), 3);                           \
+                int val64offset = Table64(dyn, getConst(V), 3);                             \
+                MESSAGE(LOG_DUMP, "  Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset); \
+            }
 #define FTABLE64(A, V)  {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q, 3); MESSAGE(LOG_DUMP, "  FTable64: %g\n", v.d); VLDR64_literal(A, val64offset);}
 #define CALLRET_RET()   do {dyn->callrets[dyn->callret_size].type = 0; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0)
 #define CALLRET_LOOP()   do {dyn->callrets[dyn->callret_size].type = 1; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0)
diff --git a/src/dynarec/arm64/dynarec_arm64_private.h b/src/dynarec/arm64/dynarec_arm64_private.h
index ca249949..b3eeed49 100644
--- a/src/dynarec/arm64/dynarec_arm64_private.h
+++ b/src/dynarec/arm64/dynarec_arm64_private.h
@@ -180,6 +180,9 @@ typedef struct dynarec_arm_s {
     void*               gdbjit_block;
     uint32_t            need_x87check;  // needs x87 precision control check if non-null, or 0 if not
     uint32_t            need_dump;     // need to dump the block
+    int                 need_reloc; // does the dynablock need relocations
+    int                 reloc_size;
+    uint32_t*           relocs;
 } dynarec_arm_t;
 
 void add_next(dynarec_arm_t *dyn, uintptr_t addr);
@@ -190,6 +193,7 @@ int get_first_jump_addr(dynarec_arm_t *dyn, uintptr_t next);
 int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n);
 int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n);
 
+int isTable64(dynarec_arm_t *dyn, uint64_t val); // return 1 if val already in Table64
 int Table64(dynarec_arm_t *dyn, uint64_t val, int pass);  // add a value to table64 (if needed) and gives back the imm19 to use in LDR_literal
 
 void CreateJmpNext(void* addr, void* next);
diff --git a/src/dynarec/dynablock_private.h b/src/dynarec/dynablock_private.h
index 8220be0c..f78d457c 100644
--- a/src/dynarec/dynablock_private.h
+++ b/src/dynarec/dynablock_private.h
@@ -31,6 +31,7 @@ typedef struct dynablock_s {
     void*           arch;       // arch dependant per inst info (can be NULL)
     callret_t*      callrets;   // array of callret return, with NOP / UDF depending if the block is clean or dirty
     void*           jmpnext;    // a branch jmpnext code when block is marked
+    void*           relocs;     // relocations, when block is loaded
     #ifdef GDBJIT
     void*           gdbjit_block;
     #endif
diff --git a/src/dynarec/dynacache_reloc.c b/src/dynarec/dynacache_reloc.c
new file mode 100644
index 00000000..7692e007
--- /dev/null
+++ b/src/dynarec/dynacache_reloc.c
@@ -0,0 +1,162 @@
+#include <stdint.h>
+#include <string.h>
+
+#include "os.h"
+#include "dynarec_private.h"
+#include "emu/x64run_private.h"
+#include "dynarec_arch.h"
+#include "custommem.h"
+#include "debug.h"
+
+#define RELOC_TBL64C        1
+#define RELOC_TBL64ADDR     2
+#define RELOC_TBL64RETENDBL 3
+#define RELOC_CANCELBLOCK   4
+#define RELOC_TBL64TBLJMPH  5
+#define RELOC_TBL64TBLJMPL  5
+
+typedef union reloc_s {
+    uint8_t type;
+    struct {
+        uint8_t     type;
+        uint8_t     C;
+        uint16_t    idx;
+    } table64c;
+    struct {
+        uint8_t     type;
+        uint8_t     nothing;
+        uint16_t    idx;
+    } table64addr;
+    struct {
+        uint8_t     type;
+        uint8_t     delta;
+        uint16_t    idx;
+    } table64retendbl;
+    struct {
+        uint8_t     type;
+        uint8_t     deltah;
+        uint16_t    idx;
+    } table64jmptblh;
+    struct {
+        uint32_t    type:8;
+        uint32_t    deltal:24;
+    } table64jmptbll;
+    uint32_t x;
+} reloc_t;
+
+void AddRelocTable64Const(dynarec_native_t* dyn, int ninst, native_consts_t C, int pass)
+{
+    if(!dyn->need_reloc)
+        return;
+    if(pass<3)  {
+        dyn->reloc_size++;
+        return;
+    }
+    // generating the reloc
+    reloc_t reloc = {0};
+    reloc.table64c.type = RELOC_TBL64C;
+    reloc.table64c.C = C;
+    reloc.table64c.idx = dyn->table64size;
+    dyn->relocs[dyn->reloc_size++] = reloc.x;
+}
+
+void AddRelocTable64RetEndBlock(dynarec_native_t* dyn, int ninst, uintptr_t addr, int pass)
+{
+    if(!dyn->need_reloc)
+        return;
+    if(isTable64(dyn, getJumpTableAddress64(addr)))
+        return; // no need, already handled
+    // TODO: check iif addr is in current map
+    if(pass<3) {
+        dyn->reloc_size++;
+        return;
+    }
+    reloc_t reloc = {0};
+    intptr_t delta = addr-(dyn->start + dyn->isize);
+    if(delta>255 || delta<0) {
+        dynarec_log(LOG_INFO, "Warning Relocation Ret End Block not possible: delta=%lld, aborting block\n", delta);
+        dyn->abort = 1;
+    }
+    reloc.table64retendbl.type = RELOC_TBL64RETENDBL;
+    reloc.table64retendbl.delta = delta;
+    reloc.table64retendbl.idx = dyn->table64size;
+    dyn->relocs[dyn->reloc_size++] = reloc.x;
+}
+
+void AddRelocCancelBlock(dynarec_native_t* dyn, int ninst, int pass)
+{
+    if(!dyn->need_reloc)
+        return;
+    if(pass<3) {
+        dyn->reloc_size++;
+        return;
+    }
+    reloc_t reloc = {0};
+    reloc.type = RELOC_CANCELBLOCK;
+    dyn->relocs[dyn->reloc_size++] = reloc.x;
+}
+
+void AddRelocTable64Addr(dynarec_native_t* dyn, int ninst, uintptr_t addr, int pass)
+{
+    if(!dyn->need_reloc)
+        return;
+    if(isTable64(dyn, addr))
+        return; // no need, already handled
+    // check if addr is in the same mmap area
+    // else, use a cancel block instead
+    uintptr_t start;
+    int ok = 1;
+    if(!IsAddrFileMapped(dyn->start, NULL, &start))
+        ok = 0;
+    else {
+        uintptr_t end = start + SizeFileMapped(dyn->start);
+        if(addr<start || addr>=end)
+            ok = 0;
+        if(ok && ((addr-start)>=0x100000000LL))
+            ok = 0;
+    }
+    if(!ok) return AddRelocCancelBlock(dyn, ninst, pass);
+    if(pass<3) {
+        dyn->reloc_size+=2;
+        return;
+    }
+    reloc_t reloc = {0};
+    reloc.type = RELOC_TBL64ADDR;
+    reloc.table64addr.idx = dyn->table64size;
+}
+
+
+void AddRelocTable64JmpTbl(dynarec_native_t* dyn, int ninst, uintptr_t addr, int pass)
+{
+    if(!dyn->need_reloc)
+        return;
+    if(isTable64(dyn, getJumpTableAddress64(addr)))
+        return; // no need, already handled
+    // check if addr is in the same mmap area
+    // else, use a cancel block instead
+    uintptr_t start;
+    int ok = 1;
+    if(!IsAddrFileMapped(dyn->start, NULL, &start))
+        ok = 0;
+    else {
+        uintptr_t end = start + SizeFileMapped(dyn->start);
+        if(addr<start || addr>=end)
+            ok = 0;
+        if(ok && ((addr-start)>=0x100000000LL))
+            ok = 0;
+    }
+    if(!ok) return AddRelocCancelBlock(dyn, ninst, pass);
+    if(pass<3) {
+        dyn->reloc_size+=2;
+        return;
+    }
+    uintptr_t delta = addr - start;
+    reloc_t reloc = {0};
+    reloc.type = RELOC_TBL64TBLJMPH;
+    reloc.table64jmptblh.idx = dyn->table64size;
+    reloc.table64jmptblh.deltah = delta>>24;
+    dyn->relocs[dyn->reloc_size++] = reloc.x;
+    reloc.type = RELOC_TBL64TBLJMPL;
+    reloc.table64jmptbll.deltal = delta&0xffffff;
+    dyn->relocs[dyn->reloc_size++] = reloc.x;
+}
\ No newline at end of file
diff --git a/src/dynarec/dynacache_reloc.h b/src/dynarec/dynacache_reloc.h
new file mode 100644
index 00000000..fed00562
--- /dev/null
+++ b/src/dynarec/dynacache_reloc.h
@@ -0,0 +1,20 @@
+#ifndef __DYNACACHE_RELOC_H__
+#define __DYNACACHE_RELOC_H__
+
+#ifdef ARM64
+#include "dynarec/arm64/dynarec_arm64_consts.h"
+#define native_consts_t             arm64_consts_t
+#else
+typedef enum native_consts_s {
+    const_none,
+    const_last
+} native_consts_t;
+#endif
+
+void AddRelocTable64Const(dynarec_native_t* dyn, int ninst, native_consts_t C, int pass);
+void AddRelocTable64Addr(dynarec_native_t* dyn, int ninst, uintptr_t addr, int pass);
+void AddRelocTable64RetEndBlock(dynarec_native_t* dyn, int ninst, uintptr_t addr, int pass);
+void AddRelocTable64JmpTbl(dynarec_native_t* dyn, int ninst, uintptr_t addr, int pass);
+void AddRelocCancelBlock(dynarec_native_t* dyn, int ninst, int pass);
+
+#endif
\ No newline at end of file
diff --git a/src/dynarec/dynarec_arch.h b/src/dynarec/dynarec_arch.h
index 74d8a6f1..5424c447 100644
--- a/src/dynarec/dynarec_arch.h
+++ b/src/dynarec/dynarec_arch.h
@@ -103,4 +103,6 @@ extern uint32_t arm64_crc(void* p, uint32_t len);
 #error Unsupported platform

 #endif

 

+#include "dynacache_reloc.h"

+

 #endif //__DYNAREC_ARCH__H_

diff --git a/src/dynarec/dynarec_native.c b/src/dynarec/dynarec_native.c
index 65868435..6d777805 100644
--- a/src/dynarec/dynarec_native.c
+++ b/src/dynarec/dynarec_native.c
@@ -293,6 +293,15 @@ void addInst(instsize_t* insts, size_t* size, int x64_size, int native_size)
     }
 }
 
+int isTable64(dynarec_native_t *dyn, uint64_t val)
+{
+    // find the value if already present
+    int idx = -1;
+    for(int i=0; i<dyn->table64size && (idx==-1); ++i)
+        if(dyn->table64[i] == val)
+            idx = i;
+    return (idx!=-1);
+}
 // add a value to table64 (if needed) and gives back the imm19 to use in LDR_literal
 int Table64(dynarec_native_t *dyn, uint64_t val, int pass)
 {
@@ -636,6 +645,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
     helper.end = addr + SizeFileMapped(addr);
     if(helper.end == helper.start)  // that means there is no mmap with a file associated to the memory
         helper.end = (uintptr_t)~0LL;
+    helper.need_reloc = IsAddrNeedReloc(addr);
     // pass 0, addresses, x64 jump addresses, overall size of the block
     uintptr_t end = native_pass0(&helper, addr, alternate, is32bits, inst_max);
     if(helper.abort) {
@@ -771,6 +781,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
     helper.next_sz = helper.next_cap = 0;
     helper.next = NULL;
     helper.table64size = 0;
+    helper.reloc_size = 0;
     // pass 1, float optimizations, first pass for flags
     native_pass1(&helper, addr, alternate, is32bits, inst_max);
     if(helper.abort) {
@@ -784,6 +795,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
     }
     POSTUPDATE_SPECIFICS(&helper);
     helper.table64size = 0;
+    helper.reloc_size = 0;
     // pass 2, instruction size
     helper.callrets = static_callrets;
     native_pass2(&helper, addr, alternate, is32bits, inst_max);
@@ -812,9 +824,10 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
     insts_rsize = (insts_rsize+7)&~7;   // round the size...
     size_t arch_size = ARCH_SIZE(&helper);
     size_t callret_size = helper.callret_size*sizeof(callret_t);
+    size_t reloc_size = helper.reloc_size*sizeof(uint32_t);
     // ok, now allocate mapped memory, with executable flag on
-    size_t sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + insts_rsize + arch_size + callret_size + sizeof(dynablock_t);
-    //           dynablock_t*     block (arm insts)            table64               jmpnext code       instsize     arch         callrets          dynablock
+    size_t sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + insts_rsize + arch_size + callret_size + sizeof(dynablock_t) + reloc_size;
+    //           dynablock_t*     block (arm insts)            table64               jmpnext code       instsize     arch         callrets          dynablock           relocs
     void* actual_p = (void*)AllocDynarecMap(addr, sz);
     void* p = (void*)(((uintptr_t)actual_p) + sizeof(void*));
     void* tablestart = p + native_size;
@@ -830,10 +843,13 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
     helper.block = p;
     dynablock_t* block = (dynablock_t*)(callrets+callret_size);
     memset(block, 0, sizeof(dynablock_t));
+    void* relocs = helper.need_reloc?(block+1):NULL;
     // fill the block
     block->x64_addr = (void*)addr;
     block->isize = 0;
     block->actual_block = actual_p;
+    helper.relocs = relocs;
+    block->relocs = relocs;
     helper.native_start = (uintptr_t)p;
     helper.tablestart = (uintptr_t)tablestart;
     helper.jmp_next = (uintptr_t)next+sizeof(void*);
@@ -861,6 +877,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
     helper.native_size = 0;
     helper.table64size = 0; // reset table64 (but not the cap)
     helper.insts_size = 0;  // reset
+    helper.reloc_size = 0;
     native_pass3(&helper, addr, alternate, is32bits, inst_max);
     if(helper.abort) {
         if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Abort dynablock on pass3\n");
diff --git a/src/dynarec/la64/dynarec_la64_private.h b/src/dynarec/la64/dynarec_la64_private.h
index a6250d09..0275218b 100644
--- a/src/dynarec/la64/dynarec_la64_private.h
+++ b/src/dynarec/la64/dynarec_la64_private.h
@@ -152,6 +152,9 @@ typedef struct dynarec_la64_s {
     void*               gdbjit_block;
     uint32_t            need_x87check; // x87 low precision check
     uint32_t            need_dump;     // need to dump the block
+    int                 need_reloc; // does the dynablock need relocations
+    int                 reloc_size;
+    uint32_t*           relocs;
 } dynarec_la64_t;
 
 void add_next(dynarec_la64_t *dyn, uintptr_t addr);
@@ -162,6 +165,7 @@ int get_first_jump_addr(dynarec_la64_t *dyn, uintptr_t next);
 int is_nops(dynarec_la64_t *dyn, uintptr_t addr, int n);
 int is_instructions(dynarec_la64_t *dyn, uintptr_t addr, int n);
 
+int isTable64(dynarec_la64_t *dyn, uint64_t val); // return 1 if val already in Table64
 int Table64(dynarec_la64_t *dyn, uint64_t val, int pass);  // add a value to table64 (if needed) and gives back the imm19 to use in LDR_literal
 
 void CreateJmpNext(void* addr, void* next);
diff --git a/src/dynarec/rv64/dynarec_rv64_private.h b/src/dynarec/rv64/dynarec_rv64_private.h
index f8006a6a..534227b4 100644
--- a/src/dynarec/rv64/dynarec_rv64_private.h
+++ b/src/dynarec/rv64/dynarec_rv64_private.h
@@ -195,6 +195,9 @@ typedef struct dynarec_rv64_s {
     void*               gdbjit_block;
     uint32_t            need_x87check; // x87 low precision check
     uint32_t            need_dump;     // need to dump the block
+    int                 need_reloc; // does the dynablock need relocations
+    int                 reloc_size;
+    uint32_t*           relocs;
 } dynarec_rv64_t;
 
 // v0 is hardware wired to vector mask register, which should be always reserved
@@ -211,6 +214,7 @@ int get_first_jump_addr(dynarec_rv64_t *dyn, uintptr_t next);
 int is_nops(dynarec_rv64_t *dyn, uintptr_t addr, int n);
 int is_instructions(dynarec_rv64_t *dyn, uintptr_t addr, int n);
 
+int isTable64(dynarec_rv64_t *dyn, uint64_t val); // return 1 if val already in Table64
 int Table64(dynarec_rv64_t *dyn, uint64_t val, int pass);  // add a value to table64 (if needed) and gives back the imm19 to use in LDR_literal
 
 void CreateJmpNext(void* addr, void* next);
diff --git a/src/include/env.h b/src/include/env.h
index 75eb0982..1c640091 100644
--- a/src/include/env.h
+++ b/src/include/env.h
@@ -125,7 +125,8 @@ extern char* ftrace_name;
     BOOLEAN(BOX64_X11GLX, x11glx, 1, 0)                                       \
     BOOLEAN(BOX64_X11SYNC, x11sync, 0, 0)                                     \
     BOOLEAN(BOX64_X11THREADS, x11threads, 0, 0)                               \
-    BOOLEAN(BOX64_X87_NO80BITS, x87_no80bits, 0, 1)
+    BOOLEAN(BOX64_X87_NO80BITS, x87_no80bits, 0, 1)                           \
+    BOOLEAN(BOX64_DYNACACHE, dynacache, 0, 0)                                 \
 
 #ifdef ARM64
 #define ENVSUPER2() \
@@ -207,5 +208,6 @@ box64env_t* GetCurEnvByAddr(uintptr_t addr);
 int IsAddrFileMapped(uintptr_t addr, const char** filename, uintptr_t* start);
 size_t SizeFileMapped(uintptr_t addr);
 mmaplist_t* GetMmaplistByAddr(uintptr_t addr);
+int IsAddrNeedReloc(uintptr_t addr);
 
 #endif // __ENV_H
diff --git a/src/tools/env.c b/src/tools/env.c
index cd4adb70..b279a988 100644
--- a/src/tools/env.c
+++ b/src/tools/env.c
@@ -807,3 +807,21 @@ size_t SizeFileMapped(uintptr_t addr)
     }
     return 0;
 }
+
+int IsAddrNeedReloc(uintptr_t addr)
+{
+    box64env_t* env = GetCurEnvByAddr(addr);
+    if(env->nodynarec)
+        return 0;
+    if(!env->dynacache)
+        return 0;
+    if(env->nodynarec_end && addr>=env->nodynarec_start && addr<env->nodynarec_end)
+        return 0;
+    #ifdef HAVE_TRACE
+    if(env->dynarec_test_end && addr>=env->dynarec_test_start && addr<env->dynarec_test_end)
+        return 0;
+    if(env->dynarec_trace && trace_end && addr>=trace_start && addr<trace_end)
+        return 0;
+    #endif
+    return 1;
+}
\ No newline at end of file
diff --git a/src/wrapped/generated/functions_list.txt b/src/wrapped/generated/functions_list.txt
index 82b573e2..bf306cfa 100644
--- a/src/wrapped/generated/functions_list.txt
+++ b/src/wrapped/generated/functions_list.txt
@@ -3506,7 +3506,6 @@
 #() iFEpuvvppp -> iFEpuppp
 wrappedalure:
 wrappedalut:
-wrappedandroidshmem:
 wrappedanl:
 wrappedatk:
 - vFp: