about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorYang Liu <liuyang22@iscas.ac.cn>2025-05-07 22:50:37 +0800
committerGitHub <noreply@github.com>2025-05-07 16:50:37 +0200
commit5d14413b89d7bb78023307fc59d2d9da182554a4 (patch)
tree3822c9835ff42632837da6dde40a292e7048247f /src
parentec549690944d2768b811340bc999abdfbc60ca2c (diff)
downloadbox64-5d14413b89d7bb78023307fc59d2d9da182554a4.tar.gz
box64-5d14413b89d7bb78023307fc59d2d9da182554a4.zip
[DYNAREC] Use PE volatile metadata in dynarec (#2610)
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/arm64/dynarec_arm64_00.c6
-rw-r--r--src/dynarec/arm64/dynarec_arm64_helper.c11
-rw-r--r--src/dynarec/arm64/dynarec_arm64_helper.h6
-rw-r--r--src/dynarec/arm64/dynarec_arm64_private.h8
-rw-r--r--src/dynarec/dynarec_helper.h102
-rw-r--r--src/dynarec/dynarec_native_pass.c23
-rw-r--r--src/dynarec/la64/dynarec_la64_00.c6
-rw-r--r--src/dynarec/la64/dynarec_la64_helper.c10
-rw-r--r--src/dynarec/la64/dynarec_la64_helper.h6
-rw-r--r--src/dynarec/la64/dynarec_la64_private.h8
-rw-r--r--src/dynarec/rv64/dynarec_rv64_00_3.c6
-rw-r--r--src/dynarec/rv64/dynarec_rv64_helper.c10
-rw-r--r--src/dynarec/rv64/dynarec_rv64_helper.h6
-rw-r--r--src/dynarec/rv64/dynarec_rv64_private.h8
-rw-r--r--src/include/env.h187
-rw-r--r--src/include/pe_tools.h8
-rw-r--r--src/tools/pe_tools.c53
-rw-r--r--src/wrapped/wrappedlibc.c18
18 files changed, 290 insertions, 192 deletions
diff --git a/src/dynarec/arm64/dynarec_arm64_00.c b/src/dynarec/arm64/dynarec_arm64_00.c
index 34913701..351e1e0a 100644
--- a/src/dynarec/arm64/dynarec_arm64_00.c
+++ b/src/dynarec/arm64/dynarec_arm64_00.c
@@ -2387,7 +2387,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             }
             fpu_purgecache(dyn, ninst, 1, x1, x2, x3);  // using next, even if there no next
             i32 = F16;
-            retn_to_epilog(dyn, ninst, rex, i32);
+            retn_to_epilog(dyn, ip, ninst, rex, i32);
             *need_epilog = 0;
             *ok = 0;
             break;
@@ -2398,7 +2398,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                 READFLAGS(X_PEND);  // so instead, force the deferred flags, so it's not too slow, and flags are not lost
             }
             fpu_purgecache(dyn, ninst, 1, x1, x2, x3);  // using next, even if there no next
-            ret_to_epilog(dyn, ninst, rex);
+            ret_to_epilog(dyn, ip, ninst, rex);
             *need_epilog = 0;
             *ok = 0;
             break;
@@ -2724,7 +2724,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
             INST_NAME("IRET");
             SETFLAGS(X_ALL, SF_SET_NODF);    // Not a hack, EFLAGS are restored
             BARRIER(BARRIER_FLOAT);
-            iret_to_epilog(dyn, ninst, rex.is32bits, rex.w);
+            iret_to_epilog(dyn, ip, ninst, rex.is32bits, rex.w);
             *need_epilog = 0;
             *ok = 0;
             break;
diff --git a/src/dynarec/arm64/dynarec_arm64_helper.c b/src/dynarec/arm64/dynarec_arm64_helper.c
index 51f619b2..32f03214 100644
--- a/src/dynarec/arm64/dynarec_arm64_helper.c
+++ b/src/dynarec/arm64/dynarec_arm64_helper.c
@@ -30,7 +30,10 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
 {
     MAYUSE(dyn); MAYUSE(ninst); MAYUSE(delta);
 
-    if(l==LOCK_LOCK) { /*SMDMB();*/DMB_ISH(); }
+    if (l == LOCK_LOCK) {
+        dyn->insts[ninst].lock_prefixed = 1;
+        DMB_ISH();
+    }
 
     if(rex.is32bits)
         return geted_32(dyn, addr, ninst, nextop, ed, hint, fixaddress, unscaled, absmax, mask, l, s);
@@ -617,7 +620,7 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32
     #endif
 }
 
-void ret_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex)
+void ret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex)
 {
     MAYUSE(dyn); MAYUSE(ninst);
     MESSAGE(LOG_DUMP, "Ret to epilog\n");
@@ -658,7 +661,7 @@ void ret_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex)
     CLEARIP();
 }
 
-void retn_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex, int n)
+void retn_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex, int n)
 {
     MAYUSE(dyn); MAYUSE(ninst);
     MESSAGE(LOG_DUMP, "Retn to epilog\n");
@@ -705,7 +708,7 @@ void retn_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex, int n)
     CLEARIP();
 }
 
-void iret_to_epilog(dynarec_arm_t* dyn, int ninst, int is32bits, int is64bits)
+void iret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, int is64bits)
 {
     int64_t j64;
     //#warning TODO: is64bits
diff --git a/src/dynarec/arm64/dynarec_arm64_helper.h b/src/dynarec/arm64/dynarec_arm64_helper.h
index fa3cff10..f36601e6 100644
--- a/src/dynarec/arm64/dynarec_arm64_helper.h
+++ b/src/dynarec/arm64/dynarec_arm64_helper.h
@@ -1479,9 +1479,9 @@ uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
 // generic x64 helper
 void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst);
 void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32bits);
-void ret_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex);
-void retn_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex, int n);
-void iret_to_epilog(dynarec_arm_t* dyn, int ninst, int is32bits, int is64bits);
+void ret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex);
+void retn_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex, int n);
+void iret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, int is64bits);
 void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int save_reg);
 void call_i(dynarec_arm_t* dyn, int ninst, void* fnc);
 void call_n(dynarec_arm_t* dyn, int ninst, void* fnc, int w);
diff --git a/src/dynarec/arm64/dynarec_arm64_private.h b/src/dynarec/arm64/dynarec_arm64_private.h
index ae615571..60c24aa2 100644
--- a/src/dynarec/arm64/dynarec_arm64_private.h
+++ b/src/dynarec/arm64/dynarec_arm64_private.h
@@ -109,9 +109,11 @@ typedef struct instruction_arm64_s {
     uint16_t            ymm0_out;   // the ymm0 at th end of the opcode
     uint16_t            ymm0_pass2, ymm0_pass3;
     uint8_t             barrier_maybe;
-    uint8_t             will_write:2; // [strongmem] will write to memory
-    uint8_t             last_write:1; // [strongmem] the last write in a SEQ
-    uint8_t             lock:1;       // [strongmem] lock semantic
+    uint8_t             will_write:2;    // [strongmem] will write to memory
+    uint8_t             will_read:1;     // [strongmem] will read from memory
+    uint8_t             last_write:1;    // [strongmem] the last write in a SEQ
+    uint8_t             lock:1;          // [strongmem] lock semantic
+    uint8_t             lock_prefixed:1; // [strongmem] the opcode is lock prefixed
     uint8_t             wfe:1;        // opcode uses sevl + wfe
     uint8_t             set_nat_flags;  // 0 or combinaison of native flags define
     uint8_t             use_nat_flags;  // 0 or combinaison of native flags define
diff --git a/src/dynarec/dynarec_helper.h b/src/dynarec/dynarec_helper.h
index d8b0eb52..f5fbfeee 100644
--- a/src/dynarec/dynarec_helper.h
+++ b/src/dynarec/dynarec_helper.h
@@ -1,6 +1,10 @@
 #ifndef __DYNAREC_HELPER__H_

 #define __DYNAREC_HELPER__H_

 

+#include "env.h"

+#include "pe_tools.h"

+#include "debug.h"

+

 /* Box64 Strong Memory Model Emulation

  *

  * Definition of a SEQ:

@@ -32,6 +36,8 @@
 #define STRONGMEM_LAST_WRITE 1 // The level of a barrier before the last guest memory store will be put

 #define STRONGMEM_SEQ_WRITE  3 // The level of a barrier at every third memory store will be  put

 

+#define STRONGMEM_LEVEL() (box64_wine && VolatileRangesContains(ip) ? 0 : BOX64DRENV(dynarec_strongmem))

+

 #if STEP == 1

 

 #define SMWRITE()                                                \

@@ -49,15 +55,20 @@
         SMWRITE();                     \

     } while (0)

 

-#define SMWRITE2()                                                   \

-    do {                                                             \

-        if (BOX64DRENV(dynarec_strongmem) >= STRONGMEM_SIMD_WRITE) { \

-            dyn->smwrite = 1;                                        \

-            dyn->insts[ninst].will_write = 2;                        \

-        }                                                            \

+#define SMWRITE2()                                       \

+    do {                                                 \

+        if (STRONGMEM_LEVEL() >= STRONGMEM_SIMD_WRITE) { \

+            dyn->smwrite = 1;                            \

+            dyn->insts[ninst].will_write = 2;            \

+        }                                                \

+    } while (0)

+

+#define SMREAD()                                               \

+    do {                                                       \

+        /* Mark that current opcode read from guest memory. */ \

+        dyn->insts[ninst].will_read = 1;                       \

     } while (0)

 

-#define SMREAD()

 #define SMREADLOCK(lock)

 #define WILLWRITE()

 #define WILLWRITELOCK(lock)

@@ -71,7 +82,7 @@
 #define SMEND()                                                                                \

     do {                                                                                       \

         /* If there is any guest memory write, which is a SEQ, then compute the last_write. */ \

-        if (dyn->smwrite && (BOX64DRENV(dynarec_strongmem) >= STRONGMEM_LAST_WRITE)) {         \

+        if (dyn->smwrite && (STRONGMEM_LEVEL() >= STRONGMEM_LAST_WRITE)) {                     \

             int i = ninst;                                                                     \

             while (i >= 0 && !dyn->insts[i].will_write)                                        \

                 --i;                                                                           \

@@ -85,22 +96,23 @@
 #else

 

 // An opcode writes guest memory, this need to be put after the STORE instruction manually. It will also end the SEQ automaticaly on last_write immediatly

-#define SMWRITE()                                                     \

-    do {                                                              \

-        if(dyn->insts[ninst].last_write) {                            \

-            dyn->smwrite = 1;                                         \

-            SMEND();                                                  \

-        } else {                                                      \

-        /* Put a barrier at every third memory write. */              \

-        if (BOX64DRENV(dynarec_strongmem) >= STRONGMEM_SEQ_WRITE) {   \

-            if (++dyn->smwrite >= 3 /* Every third memory write */) { \

-                DMB_ISH();                                            \

-                dyn->smwrite = 1;                                     \

-            }                                                         \

-        } else {                                                      \

-            /* Mark that current sequence writes to guest memory. */  \

-            dyn->smwrite = 1;                                         \

-        } }                                                           \

+#define SMWRITE()                                                         \

+    do {                                                                  \

+        if (dyn->insts[ninst].last_write) {                               \

+            dyn->smwrite = 1;                                             \

+            SMEND();                                                      \

+        } else {                                                          \

+            /* Put a barrier at every third memory write. */              \

+            if (STRONGMEM_LEVEL() >= STRONGMEM_SEQ_WRITE) {               \

+                if (++dyn->smwrite >= 3 /* Every third memory write */) { \

+                    DMB_ISH();                                            \

+                    dyn->smwrite = 1;                                     \

+                }                                                         \

+            } else {                                                      \

+                /* Mark that current sequence writes to guest memory. */  \

+                dyn->smwrite = 1;                                         \

+            }                                                             \

+        }                                                                 \

     } while (0)

 

 // Similar to SMWRITE, but checks lock.

@@ -114,10 +126,10 @@
     } while (0)

 

 // Similar to SMWRITE, but for SIMD instructions.

-#define SMWRITE2()                                                 \

-    do {                                                           \

-        if (BOX64DRENV(dynarec_strongmem) >= STRONGMEM_SIMD_WRITE) \

-            SMWRITE();                                             \

+#define SMWRITE2()                                     \

+    do {                                               \

+        if (STRONGMEM_LEVEL() >= STRONGMEM_SIMD_WRITE) \

+            SMWRITE();                                 \

     } while (0)

 

 // An opcode reads guest memory, this need to be put before the LOAD instruction manually.

@@ -134,22 +146,22 @@
     } while (0)

 

 // An opcode will write memory, this will be put before the STORE instruction automatically.

-#define WILLWRITE()                                                                                            \

-    do {                                                                                                       \

-        if (BOX64DRENV(dynarec_strongmem) >= dyn->insts[ninst].will_write && dyn->smwrite == 0) {              \

-            /* Will write but never written, this is the start of a SEQ, put a barrier. */                     \

-            if (BOX64ENV(dynarec_weakbarrier))                                                                 \

-                DMB_ISHLD();                                                                                   \

-            else                                                                                               \

-                DMB_ISH();                                                                                     \

-        } else if (BOX64DRENV(dynarec_strongmem) >= STRONGMEM_LAST_WRITE && BOX64ENV(dynarec_weakbarrier) != 2 \

-            && dyn->insts[ninst].last_write) {                                                                 \

-            /* Last write, put a barrier */                                                                    \

-            if (BOX64ENV(dynarec_weakbarrier))                                                                 \

-                DMB_ISHST();                                                                                   \

-            else                                                                                               \

-                DMB_ISH();                                                                                     \

-        }                                                                                                      \

+#define WILLWRITE()                                                                                \

+    do {                                                                                           \

+        if (STRONGMEM_LEVEL() >= dyn->insts[ninst].will_write && dyn->smwrite == 0) {              \

+            /* Will write but never written, this is the start of a SEQ, put a barrier. */         \

+            if (BOX64ENV(dynarec_weakbarrier))                                                     \

+                DMB_ISHLD();                                                                       \

+            else                                                                                   \

+                DMB_ISH();                                                                         \

+        } else if (STRONGMEM_LEVEL() >= STRONGMEM_LAST_WRITE && BOX64ENV(dynarec_weakbarrier) != 2 \

+            && dyn->insts[ninst].last_write) {                                                     \

+            /* Last write, put a barrier */                                                        \

+            if (BOX64ENV(dynarec_weakbarrier))                                                     \

+                DMB_ISHST();                                                                       \

+            else                                                                                   \

+                DMB_ISH();                                                                         \

+        }                                                                                          \

     } while (0)

 

 // Similar to WILLWRITE, but checks lock.

@@ -171,7 +183,7 @@
 // Will be put at the end of the SEQ

 #define SMEND()                                                         \

     do {                                                                \

-        if (BOX64DRENV(dynarec_strongmem)) {                            \

+        if (STRONGMEM_LEVEL()) {                                        \

             /* It's a SEQ, put a barrier here. */                       \

             if (dyn->smwrite) {                                         \

                 /* Check if the next instruction has a end loop mark */ \

diff --git a/src/dynarec/dynarec_native_pass.c b/src/dynarec/dynarec_native_pass.c
index 1f55ada4..eab3e10b 100644
--- a/src/dynarec/dynarec_native_pass.c
+++ b/src/dynarec/dynarec_native_pass.c
@@ -18,6 +18,7 @@
 #include "dynablock_private.h"
 #include "custommem.h"
 #include "x64test.h"
+#include "pe_tools.h"
 
 #include "dynarec_arch.h"
 #include "dynarec_helper.h"
@@ -132,6 +133,14 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
         } else if (dyn->insts[ninst].will_write) {
             WILLWRITE();
         }
+
+        int is_opcode_volatile = box64_wine && VolatileRangesContains(ip);
+        if (is_opcode_volatile && !dyn->insts[ninst].lock_prefixed) {
+            if (dyn->insts[ninst].will_write)
+                DMB_ISH();
+            else if (dyn->insts[ninst].will_read)
+                DMB_ISHLD();
+        }
         #endif
         if((dyn->insts[ninst].x64.need_before&~X_PEND) && !ninst) {
             READFLAGS(dyn->insts[ninst].x64.need_before&~X_PEND);
@@ -149,7 +158,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
         if (BOX64DRENV(dynarec_dump) && (!BOX64ENV(dynarec_dump_range_end) || (ip >= BOX64ENV(dynarec_dump_range_start) && ip < BOX64ENV(dynarec_dump_range_end)))) {
             dyn->need_dump = BOX64DRENV(dynarec_dump);
         }
-#ifdef HAVE_TRACE
+        #ifdef HAVE_TRACE
         else if(my_context->dec && BOX64ENV(dynarec_trace)) {
         if((trace_end == 0)
             || ((ip >= trace_start) && (ip < trace_end)))  {
@@ -160,7 +169,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
                 MESSAGE(LOG_DUMP, "----------\n");
             }
         }
-#endif
+        #endif
 
         rep = 0;
         uint8_t pk = PK(0);
@@ -187,6 +196,16 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
         if(dyn->abort)
             return ip;
         INST_EPILOG;
+
+        #if STEP > 1
+        if (is_opcode_volatile && !dyn->insts[ninst].lock_prefixed) {
+            if (dyn->insts[ninst].will_write)
+                DMB_ISHST();
+            else if (dyn->insts[ninst].will_read)
+                DMB_ISHLD();
+        }
+        #endif
+
         fpu_reset_scratch(dyn);
         int next = ninst+1;
         #if STEP > 0
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c
index b44b3e75..4811bbac 100644
--- a/src/dynarec/la64/dynarec_la64_00.c
+++ b/src/dynarec/la64/dynarec_la64_00.c
@@ -1854,7 +1854,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             }
             fpu_purgecache(dyn, ninst, 1, x1, x2, x3); // using next, even if there no next
             i32 = F16;
-            retn_to_epilog(dyn, ninst, rex, i32);
+            retn_to_epilog(dyn, ip, ninst, rex, i32);
             *need_epilog = 0;
             *ok = 0;
             break;
@@ -1864,7 +1864,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                 READFLAGS(X_PEND); // so instead, force the deferred flags, so it's not too slow, and flags are not lost
             }
             fpu_purgecache(dyn, ninst, 1, x1, x2, x3); // using next, even if there no next
-            ret_to_epilog(dyn, ninst, rex);
+            ret_to_epilog(dyn, ip, ninst, rex);
             *need_epilog = 0;
             *ok = 0;
             break;
@@ -2032,7 +2032,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
             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);
+            iret_to_epilog(dyn, ip, ninst, rex.w);
             *need_epilog = 0;
             *ok = 0;
             break;
diff --git a/src/dynarec/la64/dynarec_la64_helper.c b/src/dynarec/la64/dynarec_la64_helper.c
index c76690d9..b6fc31c2 100644
--- a/src/dynarec/la64/dynarec_la64_helper.c
+++ b/src/dynarec/la64/dynarec_la64_helper.c
@@ -35,6 +35,10 @@ uintptr_t geted(dynarec_la64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
     MAYUSE(ninst);
     MAYUSE(delta);
 
+    if (l == LOCK_LOCK) {
+        dyn->insts[ninst].lock_prefixed = 1;
+    }
+
     if (rex.is32bits)
         return geted_32(dyn, addr, ninst, nextop, ed, hint, scratch, fixaddress, l, i12);
 
@@ -572,7 +576,7 @@ void jump_to_next(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst, int is3
     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)
+void ret_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int ninst, rex_t rex)
 {
     MAYUSE(dyn);
     MAYUSE(ninst);
@@ -611,7 +615,7 @@ void ret_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex)
     CLEARIP();
 }
 
-void retn_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex, int n)
+void retn_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int ninst, rex_t rex, int n)
 {
     MAYUSE(dyn);
     MAYUSE(ninst);
@@ -656,7 +660,7 @@ 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)
+void iret_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int ninst, int is64bits)
 {
     // #warning TODO: is64bits
     MAYUSE(ninst);
diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h
index 7d472bf6..8dfa9970 100644
--- a/src/dynarec/la64/dynarec_la64_helper.h
+++ b/src/dynarec/la64/dynarec_la64_helper.h
@@ -1011,9 +1011,9 @@ uintptr_t geted32(dynarec_la64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop
 void jump_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst);
 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 ret_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int ninst, rex_t rex);
+void retn_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int ninst, rex_t rex, int n);
+void iret_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, 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, int modreg);
 void emit_cmp8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5, int s6);
diff --git a/src/dynarec/la64/dynarec_la64_private.h b/src/dynarec/la64/dynarec_la64_private.h
index 2244b122..4bc621bd 100644
--- a/src/dynarec/la64/dynarec_la64_private.h
+++ b/src/dynarec/la64/dynarec_la64_private.h
@@ -93,9 +93,11 @@ typedef struct instruction_la64_s {
     uint16_t            ymm0_out;   // the ymm0 at th end of the opcode
     uint16_t            ymm0_pass2, ymm0_pass3;
     uint8_t             barrier_maybe;
-    uint8_t             will_write;
-    uint8_t             last_write;
-    uint8_t             lock;
+    uint8_t             will_write:2;    // [strongmem] will write to memory
+    uint8_t             will_read:1;     // [strongmem] will read from memory
+    uint8_t             last_write:1;    // [strongmem] the last write in a SEQ
+    uint8_t             lock:1;          // [strongmem] lock semantic
+    uint8_t             lock_prefixed:1; // [strongmem] the opcode is lock prefixed
     uint8_t             df_notneeded;
     uint8_t             nat_flags_fusion:1;
     uint8_t             nat_flags_nofusion:1;
diff --git a/src/dynarec/rv64/dynarec_rv64_00_3.c b/src/dynarec/rv64/dynarec_rv64_00_3.c
index 2dfa119e..c10742db 100644
--- a/src/dynarec/rv64/dynarec_rv64_00_3.c
+++ b/src/dynarec/rv64/dynarec_rv64_00_3.c
@@ -285,7 +285,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
             }
             fpu_purgecache(dyn, ninst, 1, x1, x2, x3); // using next, even if there no next
             i32 = F16;
-            retn_to_epilog(dyn, ninst, rex, i32);
+            retn_to_epilog(dyn, ip, ninst, rex, i32);
             *need_epilog = 0;
             *ok = 0;
             break;
@@ -296,7 +296,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
                 READFLAGS(X_PEND); // so instead, force the deferred flags, so it's not too slow, and flags are not lost
             }
             fpu_purgecache(dyn, ninst, 1, x1, x2, x3); // using next, even if there no next
-            ret_to_epilog(dyn, ninst, rex);
+            ret_to_epilog(dyn, ip, ninst, rex);
             *need_epilog = 0;
             *ok = 0;
             break;
@@ -553,7 +553,7 @@ uintptr_t dynarec64_00_3(dynarec_rv64_t* dyn, uintptr_t addr, uintptr_t ip, int
             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);
+            iret_to_epilog(dyn, ip, ninst, rex.w);
             *need_epilog = 0;
             *ok = 0;
             break;
diff --git a/src/dynarec/rv64/dynarec_rv64_helper.c b/src/dynarec/rv64/dynarec_rv64_helper.c
index f436ea18..4d584d35 100644
--- a/src/dynarec/rv64/dynarec_rv64_helper.c
+++ b/src/dynarec/rv64/dynarec_rv64_helper.c
@@ -34,6 +34,10 @@ uintptr_t geted(dynarec_rv64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
     MAYUSE(ninst);
     MAYUSE(delta);
 
+    if (l == LOCK_LOCK) {
+        dyn->insts[ninst].lock_prefixed = 1;
+    }
+
     if (rex.is32bits)
         return geted_32(dyn, addr, ninst, nextop, ed, hint, scratch, fixaddress, l, i12);
 
@@ -601,7 +605,7 @@ void jump_to_next(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst, int is3
 #endif
 }
 
-void ret_to_epilog(dynarec_rv64_t* dyn, int ninst, rex_t rex)
+void ret_to_epilog(dynarec_rv64_t* dyn, uintptr_t ip, int ninst, rex_t rex)
 {
     MAYUSE(dyn);
     MAYUSE(ninst);
@@ -664,7 +668,7 @@ void ret_to_epilog(dynarec_rv64_t* dyn, int ninst, rex_t rex)
     CLEARIP();
 }
 
-void retn_to_epilog(dynarec_rv64_t* dyn, int ninst, rex_t rex, int n)
+void retn_to_epilog(dynarec_rv64_t* dyn, uintptr_t ip, int ninst, rex_t rex, int n)
 {
     MAYUSE(dyn);
     MAYUSE(ninst);
@@ -732,7 +736,7 @@ void retn_to_epilog(dynarec_rv64_t* dyn, int ninst, rex_t rex, int n)
     CLEARIP();
 }
 
-void iret_to_epilog(dynarec_rv64_t* dyn, int ninst, int is64bits)
+void iret_to_epilog(dynarec_rv64_t* dyn, uintptr_t ip, int ninst, int is64bits)
 {
     // #warning TODO: is64bits
     MAYUSE(ninst);
diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h
index 48886fbd..900245fb 100644
--- a/src/dynarec/rv64/dynarec_rv64_helper.h
+++ b/src/dynarec/rv64/dynarec_rv64_helper.h
@@ -1434,9 +1434,9 @@ uintptr_t geted32(dynarec_rv64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop
 void jump_to_epilog(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst);
 void jump_to_epilog_fast(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst);
 void jump_to_next(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst, int is32bits);
-void ret_to_epilog(dynarec_rv64_t* dyn, int ninst, rex_t rex);
-void retn_to_epilog(dynarec_rv64_t* dyn, int ninst, rex_t rex, int n);
-void iret_to_epilog(dynarec_rv64_t* dyn, int ninst, int is64bits);
+void ret_to_epilog(dynarec_rv64_t* dyn, uintptr_t ip, int ninst, rex_t rex);
+void retn_to_epilog(dynarec_rv64_t* dyn, uintptr_t ip, int ninst, rex_t rex, int n);
+void iret_to_epilog(dynarec_rv64_t* dyn, uintptr_t ip, int ninst, int is64bits);
 void call_c(dynarec_rv64_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int savereg, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6);
 void call_n(dynarec_rv64_t* dyn, int ninst, void* fnc, int w);
 void grab_segdata(dynarec_rv64_t* dyn, uintptr_t addr, int ninst, int reg, int segment, int modreg);
diff --git a/src/dynarec/rv64/dynarec_rv64_private.h b/src/dynarec/rv64/dynarec_rv64_private.h
index 80507b49..16ea574f 100644
--- a/src/dynarec/rv64/dynarec_rv64_private.h
+++ b/src/dynarec/rv64/dynarec_rv64_private.h
@@ -125,9 +125,11 @@ typedef struct instruction_rv64_s {
     uint16_t            ymm0_out;   // the ymm0 at th end of the opcode
     uint16_t            ymm0_pass2, ymm0_pass3;
     int                 barrier_maybe;
-    uint8_t             will_write;
-    uint8_t             last_write;
-    uint8_t             lock;
+    uint8_t             will_write:2;    // [strongmem] will write to memory
+    uint8_t             will_read:1;     // [strongmem] will read from memory
+    uint8_t             last_write:1;    // [strongmem] the last write in a SEQ
+    uint8_t             lock:1;          // [strongmem] lock semantic
+    uint8_t             lock_prefixed:1; // [strongmem] the opcode is lock prefixed
     uint8_t             df_notneeded;
     uint8_t             nat_flags_fusion:1;
     uint8_t             nat_flags_nofusion:1;
diff --git a/src/include/env.h b/src/include/env.h
index 991840aa..0d4b2f5c 100644
--- a/src/include/env.h
+++ b/src/include/env.h
@@ -24,99 +24,100 @@
 extern char* ftrace_name;
 #define DEFAULT_LOG_LEVEL (ftrace_name ? LOG_INFO : (isatty(fileno(stdout)) ? LOG_INFO : LOG_NONE))
 
-#define ENVSUPER1()                                                     \
-    STRING(BOX64_ADDLIBS, addlibs)                                      \
-    BOOLEAN(BOX64_ALLOWMISSINGLIBS, allow_missing_libs, 0)              \
-    STRING(BOX64_ARGS, args)                                            \
-    STRING(BOX64_BASH, bash)                                            \
-    BOOLEAN(BOX64_CEFDISABLEGPU, cefdisablegpu, 0)                      \
-    BOOLEAN(BOX64_CEFDISABLEGPUCOMPOSITOR, cefdisablegpucompositor, 0)  \
-    INTEGER(BOX64_CPUTYPE, cputype, 0, 0, 1)                            \
-    BOOLEAN(BOX64_CRASHHANDLER, dummy_crashhandler, 1)                  \
-    BOOLEAN(BOX64_DLSYM_ERROR, dlsym_error, 0)                          \
-    INTEGER(BOX64_DUMP, dump, 0, 0, 2)                                  \
-    BOOLEAN(BOX64_DYNAREC_ALIGNED_ATOMICS, dynarec_aligned_atomics, 0)  \
-    INTEGER(BOX64_DYNAREC_BIGBLOCK, dynarec_bigblock, 2, 0, 3)          \
-    BOOLEAN(BOX64_DYNAREC_BLEEDING_EDGE, dynarec_bleeding_edge, 1)      \
-    INTEGER(BOX64_DYNAREC_CALLRET, dynarec_callret, 0, 0, 2)            \
-    BOOLEAN(BOX64_DYNAREC_DF, dynarec_df, 1)                            \
-    INTEGER(BOX64_DYNAREC_DIRTY, dynarec_dirty, 0, 0, 2)                \
-    BOOLEAN(BOX64_DYNAREC_DIV0, dynarec_div0, 0)                        \
-    INTEGER(BOX64_DYNAREC_DUMP, dynarec_dump, 0, 0, 2)                  \
-    STRING(BOX64_DYNAREC_DUMP_RANGE, dynarec_dump_range)                \
-    BOOLEAN(BOX64_DYNAREC_FASTNAN, dynarec_fastnan, 1)                  \
-    INTEGER(BOX64_DYNAREC_FASTROUND, dynarec_fastround, 1, 0, 2)        \
-    INTEGER(BOX64_DYNAREC_FORWARD, dynarec_forward, 128, 0, 1024)       \
-    STRING(BOX64_DYNAREC_GDBJIT, dynarec_gdbjit_str)                    \
-    INTEGER(BOX64_DYNAREC_LOG, dynarec_log, 0, 0, 3)                    \
-    INTEGER(BOX64_DYNAREC_MISSING, dynarec_missing, 0, 0, 2)            \
-    BOOLEAN(BOX64_DYNAREC_NATIVEFLAGS, dynarec_nativeflags, 1)          \
-    INTEGER(BOX64_DYNAREC_PAUSE, dynarec_pause, 0, 0, 3)                \
-    BOOLEAN(BOX64_DYNAREC_PERFMAP, dynarec_perf_map, 0)                 \
-    INTEGER(BOX64_DYNAREC_SAFEFLAGS, dynarec_safeflags, 1, 0, 2)        \
-    INTEGER(BOX64_DYNAREC_STRONGMEM, dynarec_strongmem, 0, 0, 3)        \
-    BOOLEAN(BOX64_DYNAREC_TBB, dynarec_tbb, 1)                          \
-    STRING(BOX64_DYNAREC_TEST, dynarec_test_str)                        \
-    BOOLEAN(BOX64_DYNAREC_TRACE, dynarec_trace, 0)                      \
-    BOOLEAN(BOX64_DYNAREC_WAIT, dynarec_wait, 1)                        \
-    BOOLEAN(BOX64_DYNAREC_WEAKBARRIER, dynarec_weakbarrier, 1)          \
-    INTEGER(BOX64_DYNAREC_X87DOUBLE, dynarec_x87double, 0, 0, 2)        \
-    STRING(BOX64_EMULATED_LIBS, emulated_libs)                          \
-    STRING(BOX64_ENV, env)                                              \
-    STRING(BOX64_ENV1, env1)                                            \
-    STRING(BOX64_ENV2, env2)                                            \
-    STRING(BOX64_ENV3, env3)                                            \
-    STRING(BOX64_ENV4, env4)                                            \
-    STRING(BOX64_ENV5, env5)                                            \
-    BOOLEAN(BOX64_EXIT, exit, 0)                                        \
-    BOOLEAN(BOX64_FIX_64BIT_INODES, fix_64bit_inodes, 0)                \
-    BOOLEAN(BOX64_IGNOREINT3, ignoreint3, 0)                            \
-    STRING(BOX64_INSERT_ARGS, insert_args)                              \
-    BOOLEAN(BOX64_INPROCESSGPU, inprocessgpu, 0)                        \
-    INTEGER(BOX64_JITGDB, jitgdb, 0, 0, 3)                              \
-    BOOLEAN(BOX64_JVM, jvm, 1)                                          \
-    STRING(BOX64_LD_LIBRARY_PATH, ld_library_path)                      \
-    BOOLEAN(BOX64_LIBCEF, libcef, 1)                                    \
-    STRING(BOX64_LIBGL, libgl)                                          \
-    ADDRESS(BOX64_LOAD_ADDR, load_addr)                                 \
-    INTEGER(BOX64_LOG, log, DEFAULT_LOG_LEVEL, 0, 3)                    \
-    INTEGER(BOX64_MALLOC_HACK, malloc_hack, 0, 0, 2)                    \
-    INTEGER(BOX64_MAXCPU, new_maxcpu, 0, 0, 100)                        \
-    BOOLEAN(BOX64_NOBANNER, nobanner, (isatty(fileno(stdout)) ? 0 : 1)) \
-    STRING(BOX64_NODYNAREC, nodynarec)                                  \
-    BOOLEAN(BOX64_NOGTK, nogtk, 0)                                      \
-    BOOLEAN(BOX64_NOPULSE, nopulse, 0)                                  \
-    BOOLEAN(BOX64_NORCFILES, noenvfiles, 0)                             \
-    BOOLEAN(BOX64_NOSANDBOX, nosandbox, 0)                              \
-    BOOLEAN(BOX64_NOSIGSEGV, nosigsegv, 0)                              \
-    BOOLEAN(BOX64_NOSIGILL, nosigill, 0)                                \
-    BOOLEAN(BOX64_NOVULKAN, novulkan, 0)                                \
-    STRING(BOX64_PATH, path)                                            \
-    BOOLEAN(BOX64_PREFER_EMULATED, prefer_emulated, 0)                  \
-    BOOLEAN(BOX64_PREFER_WRAPPED, prefer_wrapped, 0)                    \
-    STRING(BOX64_RCFILE, envfile)                                       \
-    BOOLEAN(BOX64_RDTSC_1GHZ, rdtsc_1ghz, 0)                            \
-    BOOLEAN(BOX64_RESERVE_HIGH, reserve_high, 0)                        \
-    INTEGER(BOX64_ROLLING_LOG, cycle_log, 0, 0, 2048)                   \
-    BOOLEAN(BOX64_SDL2_JGUID, sdl2_jguid, 0)                            \
-    BOOLEAN(BOX64_SHAEXT, shaext, 1)                                    \
-    BOOLEAN(BOX64_SHOWBT, showbt, 0)                                    \
-    BOOLEAN(BOX64_SHOWSEGV, showsegv, 0)                                \
-    BOOLEAN(BOX64_SSE_FLUSHTO0, sse_flushto0, 0)                        \
-    BOOLEAN(BOX64_SSE42, sse42, 1)                                      \
-    BOOLEAN(BOX64_SYNC_ROUNDING, sync_rounding, 0)                      \
-    BOOLEAN(BOX64_TRACE_COLOR, trace_regsdiff, 0)                       \
-    BOOLEAN(BOX64_TRACE_EMM, trace_emm, 0)                              \
-    STRING(BOX64_TRACE_FILE, trace_file)                                \
-    STRING(BOX64_TRACE_INIT, trace_init)                                \
-    INTEGER64(BOX64_TRACE_START, start_cnt, 0)                          \
-    BOOLEAN(BOX64_TRACE_XMM, trace_xmm, 0)                              \
-    STRING(BOX64_TRACE, trace)                                          \
-    BOOLEAN(BOX64_UNITYPLAYER, unityplayer, 1)                          \
-    BOOLEAN(BOX64_WRAP_EGL, wrap_egl, 0)                                \
-    BOOLEAN(BOX64_X11GLX, x11glx, 1)                                    \
-    BOOLEAN(BOX64_X11SYNC, x11sync, 0)                                  \
-    BOOLEAN(BOX64_X11THREADS, x11threads, 0)                            \
+#define ENVSUPER1()                                                        \
+    STRING(BOX64_ADDLIBS, addlibs)                                         \
+    BOOLEAN(BOX64_ALLOWMISSINGLIBS, allow_missing_libs, 0)                 \
+    STRING(BOX64_ARGS, args)                                               \
+    STRING(BOX64_BASH, bash)                                               \
+    BOOLEAN(BOX64_CEFDISABLEGPU, cefdisablegpu, 0)                         \
+    BOOLEAN(BOX64_CEFDISABLEGPUCOMPOSITOR, cefdisablegpucompositor, 0)     \
+    INTEGER(BOX64_CPUTYPE, cputype, 0, 0, 1)                               \
+    BOOLEAN(BOX64_CRASHHANDLER, dummy_crashhandler, 1)                     \
+    BOOLEAN(BOX64_DLSYM_ERROR, dlsym_error, 0)                             \
+    INTEGER(BOX64_DUMP, dump, 0, 0, 2)                                     \
+    BOOLEAN(BOX64_DYNAREC_ALIGNED_ATOMICS, dynarec_aligned_atomics, 0)     \
+    INTEGER(BOX64_DYNAREC_BIGBLOCK, dynarec_bigblock, 2, 0, 3)             \
+    BOOLEAN(BOX64_DYNAREC_BLEEDING_EDGE, dynarec_bleeding_edge, 1)         \
+    INTEGER(BOX64_DYNAREC_CALLRET, dynarec_callret, 0, 0, 2)               \
+    BOOLEAN(BOX64_DYNAREC_DF, dynarec_df, 1)                               \
+    INTEGER(BOX64_DYNAREC_DIRTY, dynarec_dirty, 0, 0, 2)                   \
+    BOOLEAN(BOX64_DYNAREC_DIV0, dynarec_div0, 0)                           \
+    INTEGER(BOX64_DYNAREC_DUMP, dynarec_dump, 0, 0, 2)                     \
+    STRING(BOX64_DYNAREC_DUMP_RANGE, dynarec_dump_range)                   \
+    BOOLEAN(BOX64_DYNAREC_FASTNAN, dynarec_fastnan, 1)                     \
+    INTEGER(BOX64_DYNAREC_FASTROUND, dynarec_fastround, 1, 0, 2)           \
+    INTEGER(BOX64_DYNAREC_FORWARD, dynarec_forward, 128, 0, 1024)          \
+    STRING(BOX64_DYNAREC_GDBJIT, dynarec_gdbjit_str)                       \
+    INTEGER(BOX64_DYNAREC_LOG, dynarec_log, 0, 0, 3)                       \
+    INTEGER(BOX64_DYNAREC_MISSING, dynarec_missing, 0, 0, 2)               \
+    BOOLEAN(BOX64_DYNAREC_NATIVEFLAGS, dynarec_nativeflags, 1)             \
+    INTEGER(BOX64_DYNAREC_PAUSE, dynarec_pause, 0, 0, 3)                   \
+    BOOLEAN(BOX64_DYNAREC_PERFMAP, dynarec_perf_map, 0)                    \
+    INTEGER(BOX64_DYNAREC_SAFEFLAGS, dynarec_safeflags, 1, 0, 2)           \
+    INTEGER(BOX64_DYNAREC_STRONGMEM, dynarec_strongmem, 0, 0, 3)           \
+    BOOLEAN(BOX64_DYNAREC_TBB, dynarec_tbb, 1)                             \
+    STRING(BOX64_DYNAREC_TEST, dynarec_test_str)                           \
+    BOOLEAN(BOX64_DYNAREC_TRACE, dynarec_trace, 0)                         \
+    BOOLEAN(BOX64_DYNAREC_VOLATILE_METADATA, dynarec_volatile_metadata, 0) \
+    BOOLEAN(BOX64_DYNAREC_WAIT, dynarec_wait, 1)                           \
+    BOOLEAN(BOX64_DYNAREC_WEAKBARRIER, dynarec_weakbarrier, 1)             \
+    INTEGER(BOX64_DYNAREC_X87DOUBLE, dynarec_x87double, 0, 0, 2)           \
+    STRING(BOX64_EMULATED_LIBS, emulated_libs)                             \
+    STRING(BOX64_ENV, env)                                                 \
+    STRING(BOX64_ENV1, env1)                                               \
+    STRING(BOX64_ENV2, env2)                                               \
+    STRING(BOX64_ENV3, env3)                                               \
+    STRING(BOX64_ENV4, env4)                                               \
+    STRING(BOX64_ENV5, env5)                                               \
+    BOOLEAN(BOX64_EXIT, exit, 0)                                           \
+    BOOLEAN(BOX64_FIX_64BIT_INODES, fix_64bit_inodes, 0)                   \
+    BOOLEAN(BOX64_IGNOREINT3, ignoreint3, 0)                               \
+    STRING(BOX64_INSERT_ARGS, insert_args)                                 \
+    BOOLEAN(BOX64_INPROCESSGPU, inprocessgpu, 0)                           \
+    INTEGER(BOX64_JITGDB, jitgdb, 0, 0, 3)                                 \
+    BOOLEAN(BOX64_JVM, jvm, 1)                                             \
+    STRING(BOX64_LD_LIBRARY_PATH, ld_library_path)                         \
+    BOOLEAN(BOX64_LIBCEF, libcef, 1)                                       \
+    STRING(BOX64_LIBGL, libgl)                                             \
+    ADDRESS(BOX64_LOAD_ADDR, load_addr)                                    \
+    INTEGER(BOX64_LOG, log, DEFAULT_LOG_LEVEL, 0, 3)                       \
+    INTEGER(BOX64_MALLOC_HACK, malloc_hack, 0, 0, 2)                       \
+    INTEGER(BOX64_MAXCPU, new_maxcpu, 0, 0, 100)                           \
+    BOOLEAN(BOX64_NOBANNER, nobanner, (isatty(fileno(stdout)) ? 0 : 1))    \
+    STRING(BOX64_NODYNAREC, nodynarec)                                     \
+    BOOLEAN(BOX64_NOGTK, nogtk, 0)                                         \
+    BOOLEAN(BOX64_NOPULSE, nopulse, 0)                                     \
+    BOOLEAN(BOX64_NORCFILES, noenvfiles, 0)                                \
+    BOOLEAN(BOX64_NOSANDBOX, nosandbox, 0)                                 \
+    BOOLEAN(BOX64_NOSIGSEGV, nosigsegv, 0)                                 \
+    BOOLEAN(BOX64_NOSIGILL, nosigill, 0)                                   \
+    BOOLEAN(BOX64_NOVULKAN, novulkan, 0)                                   \
+    STRING(BOX64_PATH, path)                                               \
+    BOOLEAN(BOX64_PREFER_EMULATED, prefer_emulated, 0)                     \
+    BOOLEAN(BOX64_PREFER_WRAPPED, prefer_wrapped, 0)                       \
+    STRING(BOX64_RCFILE, envfile)                                          \
+    BOOLEAN(BOX64_RDTSC_1GHZ, rdtsc_1ghz, 0)                               \
+    BOOLEAN(BOX64_RESERVE_HIGH, reserve_high, 0)                           \
+    INTEGER(BOX64_ROLLING_LOG, cycle_log, 0, 0, 2048)                      \
+    BOOLEAN(BOX64_SDL2_JGUID, sdl2_jguid, 0)                               \
+    BOOLEAN(BOX64_SHAEXT, shaext, 1)                                       \
+    BOOLEAN(BOX64_SHOWBT, showbt, 0)                                       \
+    BOOLEAN(BOX64_SHOWSEGV, showsegv, 0)                                   \
+    BOOLEAN(BOX64_SSE_FLUSHTO0, sse_flushto0, 0)                           \
+    BOOLEAN(BOX64_SSE42, sse42, 1)                                         \
+    BOOLEAN(BOX64_SYNC_ROUNDING, sync_rounding, 0)                         \
+    BOOLEAN(BOX64_TRACE_COLOR, trace_regsdiff, 0)                          \
+    BOOLEAN(BOX64_TRACE_EMM, trace_emm, 0)                                 \
+    STRING(BOX64_TRACE_FILE, trace_file)                                   \
+    STRING(BOX64_TRACE_INIT, trace_init)                                   \
+    INTEGER64(BOX64_TRACE_START, start_cnt, 0)                             \
+    BOOLEAN(BOX64_TRACE_XMM, trace_xmm, 0)                                 \
+    STRING(BOX64_TRACE, trace)                                             \
+    BOOLEAN(BOX64_UNITYPLAYER, unityplayer, 1)                             \
+    BOOLEAN(BOX64_WRAP_EGL, wrap_egl, 0)                                   \
+    BOOLEAN(BOX64_X11GLX, x11glx, 1)                                       \
+    BOOLEAN(BOX64_X11SYNC, x11sync, 0)                                     \
+    BOOLEAN(BOX64_X11THREADS, x11threads, 0)                               \
     BOOLEAN(BOX64_X87_NO80BITS, x87_no80bits, 0)
 
 #ifdef ARM64
diff --git a/src/include/pe_tools.h b/src/include/pe_tools.h
index 54c3d42e..d52f1438 100644
--- a/src/include/pe_tools.h
+++ b/src/include/pe_tools.h
@@ -1,7 +1,13 @@
 #ifndef __PE_TOOLS_H__
 #define __PE_TOOLS_H__
 
-
+// Parse the PE file and extract the volatile metadata, which contains volatile opcode entries and volatile ranges.
 void ParseVolatileMetadata(char* filename, void* addr);
 
+// Check if a given address is contained within the volatile ranges.
+int VolatileRangesContains(uintptr_t addr);
+
+// Check if a given address is contained within the volatile opcode entries.
+int VolatileOpcodesHas(uintptr_t addr);
+
 #endif // __PE_TOOLS_H__
diff --git a/src/tools/pe_tools.c b/src/tools/pe_tools.c
index 46c8a203..5d8bc2b4 100644
--- a/src/tools/pe_tools.c
+++ b/src/tools/pe_tools.c
@@ -6,6 +6,8 @@
 #include <stddef.h>
 
 #include "debug.h"
+#include "khash.h"
+#include "rbtree.h"
 
 typedef uint8_t BYTE;
 typedef uint16_t WORD;
@@ -182,6 +184,14 @@ typedef struct _IMAGE_VOLATILE_RANGE_METADATA {
     ULONG Size;
 } IMAGE_VOLATILE_RANGE_METADATA, *PIMAGE_VOLATILE_RANGE_METADATA;
 
+KHASH_SET_INIT_STR(string);
+KHASH_SET_INIT_INT64(volatileopcode);
+
+static kh_string_t* dllNames = NULL;                // never freed
+static kh_volatileopcode_t* volatileOpcodes = NULL; // never freed
+
+static rbtree_t* volatileRanges = NULL; // never freed
+
 static int HasSuffix(const char* str, const char* suffix)
 {
     size_t lenstr = strlen(str);
@@ -211,6 +221,22 @@ void ParseVolatileMetadata(char* filename, void* addr)
         return;
     }
 
+    if (!dllNames) dllNames = kh_init(string);
+    if (!volatileOpcodes) volatileOpcodes = kh_init(volatileopcode);
+    if (!volatileRanges) volatileRanges = rbtree_init("volatileRanges");
+
+    char* baseName = strrchr(filename, '/');
+    if (!baseName)
+        return;
+    else
+        baseName++;
+
+    khint_t k = kh_get(string, dllNames, baseName);
+    if (k != kh_end(dllNames)) return;
+
+    int ret;
+    k = kh_put(string, dllNames, strdup(baseName), &ret);
+
     FILE* file = fopen(filename, "rb");
     if (!file) return;
 
@@ -280,7 +306,7 @@ void ParseVolatileMetadata(char* filename, void* addr)
 
     PIMAGE_VOLATILE_METADATA volatileMetadata = (PIMAGE_VOLATILE_METADATA)(buffer + volatileMetadataOffset);
     if (volatileMetadata->VolatileAccessTable && volatileMetadata->VolatileAccessTableSize) {
-        printf_log(LOG_INFO, "Parsing volatile metadata of file: %s\n", filename);
+        printf_log(LOG_INFO, "Parsing volatile metadata of file %s loaded at %p\n", baseName, addr);
 
         DWORD volatileAccessTableOffset = RVAToFileOffset(sectionHeaders, numberOfSections, volatileMetadata->VolatileAccessTable, (BYTE*)buffer, ntHeaders64->OptionalHeader.SizeOfImage);
         if (volatileAccessTableOffset == 0) {
@@ -292,8 +318,10 @@ void ParseVolatileMetadata(char* filename, void* addr)
         PIMAGE_VOLATILE_RVA_METADATA volatileAccessTable = (PIMAGE_VOLATILE_RVA_METADATA)(buffer + volatileAccessTableOffset);
 
         for (DWORD i = 0; i < numEntries; i++) {
-            ULONG entry = volatileAccessTable[i].Rva;
-            printf_log(LOG_INFO, "Volatile Access Table Entry %d: %08X\n", i, entry);
+            ULONGLONG entry = volatileAccessTable[i].Rva + (ULONGLONG)addr;
+            int ret;
+            khint_t _ = kh_put(volatileopcode, volatileOpcodes, entry, &ret);
+            printf_log(LOG_DEBUG, "Volatile access table [%d]: %08lX\n", i, entry);
         }
     }
 
@@ -308,9 +336,22 @@ void ParseVolatileMetadata(char* filename, void* addr)
         PIMAGE_VOLATILE_RANGE_METADATA volatileRangeMetadata = (PIMAGE_VOLATILE_RANGE_METADATA)(buffer + volatileInfoRangeTableOffset);
 
         for (DWORD i = 0; i < numEntries; i++) {
-            ULONG Rva = volatileRangeMetadata[i].Rva;
-            ULONG Size = volatileRangeMetadata[i].Size;
-            printf_log(LOG_INFO, "Volatile Range Metadata Entry %d: %08X Size: %08X\n", i, Rva, Size);
+            ULONGLONG rva = volatileRangeMetadata[i].Rva + (ULONGLONG)addr;
+            ULONGLONG size = volatileRangeMetadata[i].Size;
+            rb_set(volatileRanges, rva, rva + size, i);
+            printf_log(LOG_DEBUG, "Volatile range metadata [%d]: %08lX-%08lX\n", i, rva, rva + size);
         }
     }
 }
+
+int VolatileRangesContains(uintptr_t addr)
+{
+    if (!volatileRanges) return 0;
+    return rb_get(volatileRanges, addr) != 0;
+}
+
+int VolatileOpcodesHas(uintptr_t addr)
+{
+    if (!volatileOpcodes) return 0;
+    return kh_get(volatileopcode, volatileOpcodes, addr) != kh_end(volatileOpcodes);
+}
diff --git a/src/wrapped/wrappedlibc.c b/src/wrapped/wrappedlibc.c
index 4815f57d..fbfc9b21 100644
--- a/src/wrapped/wrappedlibc.c
+++ b/src/wrapped/wrappedlibc.c
@@ -3033,14 +3033,16 @@ EXPORT void* my_mmap64(x64emu_t* emu, void *addr, size_t length, int prot, int f
     #endif
     if(ret!=MAP_FAILED) {
         if(emu && !(flags&MAP_ANONYMOUS) && (fd>0)) {
-            char filename[4096];
-            char buf[128];
-            sprintf(buf, "/proc/self/fd/%d", fd);
-            ssize_t r = readlink(buf, filename, sizeof(filename) - 1);
-            if (r != -1) filename[r] = 0;
-
-            DetectUnityPlayer(filename);
-            // ParseVolatileMetadata(filename, addr);
+            if ((box64_wine && BOX64ENV(dynarec_volatile_metadata)) || BOX64ENV(unityplayer)) {
+                char filename[4096];
+                char buf[128];
+                sprintf(buf, "/proc/self/fd/%d", fd);
+                ssize_t r = readlink(buf, filename, sizeof(filename) - 1);
+                if (r != -1) filename[r] = 0;
+
+                if (BOX64ENV(unityplayer)) DetectUnityPlayer(filename);
+                if (box64_wine && BOX64ENV(dynarec_volatile_metadata)) ParseVolatileMetadata(filename, addr);
+            }
             // the last_mmap will allow mmap created by wine, even those that have hole, to be fully tracked as one single mmap
             if((ret>=last_mmap_addr[0]) && ret+length<(last_mmap_addr[0]+last_mmap_len[0]))
                 RecordEnvMappings((uintptr_t)last_mmap_addr[0], last_mmap_len[0], fd);