about summary refs log tree commit diff stats
path: root/src/dynarec/dynacache_reloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dynarec/dynacache_reloc.c')
-rw-r--r--src/dynarec/dynacache_reloc.c84
1 files changed, 82 insertions, 2 deletions
diff --git a/src/dynarec/dynacache_reloc.c b/src/dynarec/dynacache_reloc.c
index 7692e007..b145629e 100644
--- a/src/dynarec/dynacache_reloc.c
+++ b/src/dynarec/dynacache_reloc.c
@@ -4,6 +4,7 @@
 #include "os.h"
 #include "dynarec_private.h"
 #include "emu/x64run_private.h"
+#include "dynablock_private.h"
 #include "dynarec_arch.h"
 #include "custommem.h"
 #include "debug.h"
@@ -13,7 +14,7 @@
 #define RELOC_TBL64RETENDBL 3
 #define RELOC_CANCELBLOCK   4
 #define RELOC_TBL64TBLJMPH  5
-#define RELOC_TBL64TBLJMPL  5
+#define RELOC_TBL64TBLJMPL  6
 
 typedef union reloc_s {
     uint8_t type;
@@ -48,6 +49,8 @@ void AddRelocTable64Const(dynarec_native_t* dyn, int ninst, native_consts_t C, i
 {
     if(!dyn->need_reloc)
         return;
+    if(isTable64(dyn, getConst(C)))
+        return;
     if(pass<3)  {
         dyn->reloc_size++;
         return;
@@ -117,12 +120,13 @@ void AddRelocTable64Addr(dynarec_native_t* dyn, int ninst, uintptr_t addr, int p
     }
     if(!ok) return AddRelocCancelBlock(dyn, ninst, pass);
     if(pass<3) {
-        dyn->reloc_size+=2;
+        dyn->reloc_size++;
         return;
     }
     reloc_t reloc = {0};
     reloc.type = RELOC_TBL64ADDR;
     reloc.table64addr.idx = dyn->table64size;
+    dyn->relocs[dyn->reloc_size++] = reloc.x;
 }
 
 
@@ -159,4 +163,80 @@ void AddRelocTable64JmpTbl(dynarec_native_t* dyn, int ninst, uintptr_t addr, int
     reloc.type = RELOC_TBL64TBLJMPL;
     reloc.table64jmptbll.deltal = delta&0xffffff;
     dyn->relocs[dyn->reloc_size++] = reloc.x;
+}
+
+int ApplyRelocs(dynablock_t* block, intptr_t delta_block, intptr_t delta_map, uintptr_t mapping_start)
+{
+    if(!block || !block->relocs || !block->relocsize)
+        return 0;
+    size_t reloc_size = block->relocsize / sizeof(uint32_t);
+    reloc_t *relocs = block->relocs;
+    uint64_t *table64 = block->table64;
+    int idx;
+
+    int i = 0;
+    uintptr_t addr;
+    dynarec_log(LOG_DEBUG, "Will apply %zd reloc to dynablock starting at %p - %p\n", reloc_size, block->x64_addr, block->x64_addr + block->x64_size);
+    while(i<reloc_size) {
+        idx = -1;
+        switch(relocs[i].type) {
+            case RELOC_TBL64C:
+                idx = relocs[i].table64c.idx;
+                table64[idx] = getConst(relocs[i].table64c.C);
+                dynarec_log(LOG_DEBUG, "\tApply Relocs[%d]: TABLE64[%d]=Const:%d\n", i, idx, relocs[i].table64c.C);
+                break;
+            case RELOC_TBL64ADDR:
+                idx = relocs[i].table64addr.idx;
+                table64[idx] += delta_map;
+                dynarec_log(LOG_DEBUG, "\tApply Relocs[%d]: TABLE64[%d]=Addr in Map, delta=%zd\n", i, idx, delta_map);
+                break;
+            case RELOC_TBL64RETENDBL:
+                idx = relocs[i].table64retendbl.idx;
+                addr = (uintptr_t)block->x64_addr + block->x64_size + relocs[i].table64retendbl.delta;
+                table64[idx] = getJumpTableAddress64(addr);
+                dynarec_log(LOG_DEBUG, "\tApply Relocs[%d]: TABLE64[%d]=JmpTable64(%p)\n", i, idx, (void*)addr);
+                break;
+            case RELOC_CANCELBLOCK:
+                dynarec_log(LOG_DEBUG, "\tApply Relocs[%d]: Cancel Block\n", i);
+                block->dirty = 1;
+                block->hash = 0;
+                return 0;
+            case RELOC_TBL64TBLJMPH:
+                if(relocs[i+1].type!=RELOC_TBL64TBLJMPL)
+                    return -2;  // bad sequence
+                idx = relocs[i].table64jmptblh.idx;
+                addr = relocs[i].table64jmptblh.deltah;
+                addr = mapping_start + relocs[i+1].table64jmptbll.deltal + (addr<<24);
+                table64[idx] = getJumpTableAddress64(addr);
+                dynarec_log(LOG_DEBUG, "\tApply Relocs[%d,%d]: TABLE64[%d]=JmpTable64(%p)=%p\n", i, i+1, idx, (void*)addr, getJumpTableAddress64(addr));
+                break;
+            case RELOC_TBL64TBLJMPL:
+                break;
+            default: 
+                dynarec_log(LOG_DEBUG, "\tUnknown Relocs[%d]: %d\n", i, relocs[i].type);
+                return -1;
+        }
+        if(idx!=-1) {
+            if(idx>=block->table64size) {
+                dynarec_log(LOG_NONE, "Warning: Reloc Table64 idx out of range (%d vs %d)\n", idx, block->table64size);
+            }
+        }
+        ++i;
+    }
+    return 0;
+}
+
+int RelocsHaveCancel(dynablock_t* block)
+{
+    if(!block->relocs || !block->relocsize)
+        return 0;
+    size_t reloc_size = block->relocsize/sizeof(uint32_t);
+    for(size_t i=0; i<reloc_size; ++i)
+        if(((reloc_t*)block->relocs)[i].type == RELOC_CANCELBLOCK)
+            return 1;
+    return 0;
+}
+
+uintptr_t RelocGetNext() {
+    return getConst(const_native_next);
 }
\ No newline at end of file