1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include "os.h"
#include "debug.h"
#include "box64context.h"
#include "custommem.h"
#include "box64cpu.h"
#include "emu/x64emu_private.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynablock.h"
#include "../dynablock_private.h"
#include "dynarec_native.h"
#include "../dynarec_arch.h"
void updateflags_pass0(dynarec_arm_t* dyn, uint64_t jmp_df[]);
void updateflags_pass1(dynarec_arm_t* dyn, uint64_t jmp_df[]);
void updateflags_pass2(dynarec_arm_t* dyn, uint64_t jmp_df[]);
void updateflags_pass3(dynarec_arm_t* dyn, uint64_t jmp_df[]);
static dynablock_t* updaflags_arm64 = NULL;
static uint8_t dummy_code[] = {0x90, 0xc3}; // some dummy code so update_flags dynablock point to something
void* create_updateflags()
{
if(updaflags_arm64)
return updaflags_arm64->block;
uint64_t jmp_df[d_unknown+1] = {0};
dynarec_arm_t helper = {0};
instruction_arm64_t insts[1] = {0};
helper.insts = insts;
helper.need_dump = BOX64ENV(dynarec_dump);
helper.cap = 1;
helper.f.dfnone = 1;
helper.f.pending = SF_NODF;
helper.insts[0].x64.gen_flags = X_ALL;
// pass 0
updateflags_pass0(&helper, jmp_df);
// check if all flags are handled
int ok = 1;
for(int i=d_none; i<d_unknown; ++i)
if(!jmp_df[i]) {
printf_log(LOG_NONE, "Error, UpdateFlags case %d is not handled, will crash later\n", i);
ok = 0;
}
// pass 1
updateflags_pass1(&helper, jmp_df);
// pass 2
helper.native_size = 0;
updateflags_pass2(&helper, jmp_df);
// alloc memory for pass3
size_t native_size = (helper.native_size+7)&~7; // round the size...
size_t sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + 0 + 0 + 0 + sizeof(dynablock_t) + 0;
// dynablock_t* block (arm insts) table64 jmpnext code instsize arch callrets dynablock relocs
void* actual_p = (void*)AllocDynarecMap((uintptr_t)&dummy_code, sz, 1); // arbitrary address
void* p = (void*)(((uintptr_t)actual_p) + sizeof(void*));
void* tablestart = p + native_size;
void* next = tablestart + helper.table64size*sizeof(uint64_t);
void* instsize = next + 4*sizeof(void*);
void* arch = instsize + 0;
void* callrets = arch + 0;
if(actual_p==NULL) {
dynarec_log(LOG_INFO, "AllocDynarecMap(%zu) failed, canceling UpdateBlock\n", sz);
return NULL;
}
helper.block = p;
dynablock_t* block = (dynablock_t*)(callrets+0);
memset(block, 0, sizeof(dynablock_t));
void* relocs = helper.need_reloc?(block+1):NULL;
// fill the block
block->x64_addr = &dummy_code;
block->isize = 0;
block->actual_block = actual_p;
helper.relocs = relocs;
block->relocs = relocs;
block->table64size = helper.table64size;
helper.native_start = (uintptr_t)p;
helper.tablestart = (uintptr_t)tablestart;
helper.jmp_next = (uintptr_t)next+sizeof(void*);
helper.instsize = (instsize_t*)instsize;
*(dynablock_t**)actual_p = block;
helper.table64cap = helper.table64size;
helper.table64 = (uint64_t*)helper.tablestart;
helper.callrets = (callret_t*)callrets;
block->table64 = helper.table64;
helper.callret_size = 0;
// pass 3, emit (log emit native opcode)
if(helper.need_dump) {
dynarec_log(LOG_NONE, "%s%04d|Emitting %zu bytes for UpdateFlags", (helper.need_dump>1)?"\e[01;36m":"", GetTID(), helper.native_size);
PrintFunctionAddr(helper.start, " => ");
dynarec_log_prefix(0, LOG_NONE, "%s\n", (helper.need_dump>1)?"\e[m":"");
}
helper.native_size = 0;
updateflags_pass3(&helper, jmp_df);
helper.jmp_sz = helper.jmp_cap = 0;
helper.jmps = NULL;
// keep size of instructions for signal handling
block->instsize = instsize;
helper.table64 = NULL;
helper.instsize = NULL;
helper.predecessor = NULL;
block->size = sz;
block->isize = helper.size;
block->block = p;
block->jmpnext = next+sizeof(void*);
block->always_test = helper.always_test;
block->dirty = block->always_test;
block->is32bits = 0;
block->relocsize = helper.reloc_size*sizeof(uint32_t);
block->arch = NULL;
block->arch_size = 0;
block->callret_size = helper.callret_size;
block->callrets = helper.callrets;
block->native_size = native_size;
*(dynablock_t**)next = block;
*(void**)(next+3*sizeof(void*)) = NULL;
CreateJmpNext(block->jmpnext, next+3*sizeof(void*));
ClearCache(block->jmpnext, 4*sizeof(void*));
block->x64_size = 0;
// all done...
ClearCache(actual_p+sizeof(void*), native_size); // need to clear the cache before execution...
updaflags_arm64 = block;
return block->block;
}
|