mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-09 17:43:18 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17bc603077 | ||
|
|
7af9158baa | ||
|
|
571a041c25 | ||
|
|
0a02340e35 | ||
|
|
12ee624358 | ||
|
|
571de7f07f | ||
|
|
b055c2be65 | ||
|
|
78750b96e5 | ||
|
|
ce51207e44 | ||
|
|
a3dcaf4284 | ||
|
|
181274636e | ||
|
|
c4198554ad | ||
|
|
ed45a8d666 | ||
|
|
5a8b5c8af4 | ||
|
|
1e3c599b4e | ||
|
|
41ca58a403 | ||
|
|
e09b18d3fb | ||
|
|
4b7958f447 | ||
|
|
b0b11572d7 | ||
|
|
c1684db78a | ||
|
|
fdbdc615da | ||
|
|
5354a134fc | ||
|
|
800d3fd109 | ||
|
|
b7f8a1eb8b | ||
|
|
dbeea3b8a1 | ||
|
|
888705c7dc | ||
|
|
d9e649c023 | ||
|
|
14da2a9a67 | ||
|
|
d7e712f48b | ||
|
|
0f9b48d446 | ||
|
|
6e90c47e74 | ||
|
|
365d2b0eb2 | ||
|
|
3642119665 | ||
|
|
705cb79819 | ||
|
|
d8e5c5372a | ||
|
|
714ccbc321 | ||
|
|
0917fbe0c4 | ||
|
|
1517177668 | ||
|
|
2487fb4d98 | ||
|
|
de0718811e | ||
|
|
12b9b1a6e9 | ||
|
|
1f819c4924 | ||
|
|
1d209596a3 | ||
|
|
b1d5e27564 | ||
|
|
732f2f106b | ||
|
|
db6319b90f | ||
|
|
601eb63c9a | ||
|
|
d237d5e807 | ||
|
|
da47d34705 | ||
|
|
ce5a5bf356 | ||
|
|
c754cb75b6 | ||
|
|
f084966fd3 | ||
|
|
79dd8c29ae | ||
|
|
a260dff197 | ||
|
|
f83179c665 | ||
|
|
31508f673c | ||
|
|
a1f87da9f5 | ||
|
|
eb102f8a82 | ||
|
|
e1a2439fbf | ||
|
|
9fb2cb86ed | ||
|
|
f6b646ef67 | ||
|
|
068025d919 | ||
|
|
f88f59926e | ||
|
|
c9d593fa17 | ||
|
|
ed452e81ae | ||
|
|
604da55f08 | ||
|
|
57a5d517c8 | ||
|
|
2b6fa580df | ||
|
|
7f750e7ac1 | ||
|
|
b9779c2184 | ||
|
|
e52c207c75 | ||
|
|
bfdcb023b3 | ||
|
|
dce3292fc7 | ||
|
|
98a567e102 | ||
|
|
d6123a87c5 | ||
|
|
f94ceccc8a | ||
|
|
cc97914ed8 | ||
|
|
829be9e506 | ||
|
|
bea68ddbfa | ||
|
|
fa039a1320 | ||
|
|
cdaf19899e | ||
|
|
b5847d83cb | ||
|
|
685cc7b0ba | ||
|
|
b14be7f614 | ||
|
|
35f8500acd | ||
|
|
cb0cceb9ae | ||
|
|
1405d83a56 | ||
|
|
0878acf04c | ||
|
|
735d9c107d | ||
|
|
daf148c4d6 | ||
|
|
922fa046bb | ||
|
|
b247fd04df | ||
|
|
0b53a98648 | ||
|
|
f76fa67303 | ||
|
|
e6d3812d6c | ||
|
|
c02946a913 | ||
|
|
8ec2851439 | ||
|
|
f2c68385ab | ||
|
|
f428001f42 | ||
|
|
83104b32b8 | ||
|
|
1a12bd7269 | ||
|
|
04aa1af72e | ||
|
|
466a8cb107 | ||
|
|
23c9d574d9 | ||
|
|
5cc73fdf40 | ||
|
|
3cfd4c8ec2 | ||
|
|
9eb6d49616 | ||
|
|
8bd81dffcf | ||
|
|
79ca411d6a | ||
|
|
9cdf1f9711 | ||
|
|
c8b6834a5e | ||
|
|
e15eb5a7f6 | ||
|
|
3d4acc3aef | ||
|
|
1349601269 | ||
|
|
0751aed1f0 | ||
|
|
4f2ed9ba62 | ||
|
|
707f41af39 | ||
|
|
3d400cf91b | ||
|
|
a77093e154 | ||
|
|
6676fe3b3b | ||
|
|
1d85580fbc | ||
|
|
f01e987d31 | ||
|
|
eb96a1c03a | ||
|
|
e99387aa83 | ||
|
|
f8341bf934 | ||
|
|
20ccf221a8 | ||
|
|
b98fe181e8 | ||
|
|
34eea95426 | ||
|
|
5f470be79e | ||
|
|
1c8683343b | ||
|
|
56f37e8745 | ||
|
|
910a466fad | ||
|
|
d3a15b7ab6 | ||
|
|
cd8ee4c4b4 | ||
|
|
c253e4a48e | ||
|
|
90bd5b0cb1 | ||
|
|
fd729da8f1 | ||
|
|
9bfc027b15 | ||
|
|
cedd8e3670 | ||
|
|
3c31ecb115 | ||
|
|
cc25976743 | ||
|
|
6fea5e5854 | ||
|
|
bf6ac0d608 | ||
|
|
cb7c7ad913 | ||
|
|
bd9cddf211 | ||
|
|
3d33454564 | ||
|
|
a70109be83 | ||
|
|
5ec0a88949 | ||
|
|
12de380799 | ||
|
|
89a3c359a6 | ||
|
|
848390d9eb | ||
|
|
2f89043b35 | ||
|
|
fcfd0d794b | ||
|
|
dbd83a8b28 | ||
|
|
36d62235b3 | ||
|
|
79c4c8bdd3 | ||
|
|
6be2c376e2 | ||
|
|
db22d8b1c9 | ||
|
|
e4fa7bc969 | ||
|
|
98b0ac713d | ||
|
|
74eea34c6e | ||
|
|
bbe817e3be | ||
|
|
f53775ac39 | ||
|
|
dfb1cd4876 | ||
|
|
c2c34ccba3 | ||
|
|
c8d005af84 | ||
|
|
7c651088b5 | ||
|
|
9a9d51440a | ||
|
|
4b3e632d14 | ||
|
|
b52b321969 | ||
|
|
e5b36d2997 | ||
|
|
cc2016bbc9 | ||
|
|
a68be9117b | ||
|
|
f4fceb53bc | ||
|
|
495d566401 | ||
|
|
7a056851d9 | ||
|
|
44eb9cf678 | ||
|
|
597a56d0ff | ||
|
|
967132b04e | ||
|
|
423795b49e | ||
|
|
27b7382be5 | ||
|
|
25d342f829 | ||
|
|
f683404db9 | ||
|
|
d8c3c38d69 | ||
|
|
0400bea3bd | ||
|
|
10088c6566 | ||
|
|
a2abb4e8b1 | ||
|
|
f1625c0d92 | ||
|
|
5c4b0baf8b | ||
|
|
af1b5a9a51 | ||
|
|
f5a7e63936 | ||
|
|
13da8f0d75 | ||
|
|
adea4ceef2 | ||
|
|
cc85f79322 | ||
|
|
c22782d2ab | ||
|
|
994a575d32 | ||
|
|
39faa1538d | ||
|
|
153343fa9e | ||
|
|
0d3e9f21ee | ||
|
|
8c01412156 | ||
|
|
bd46fd7d4f | ||
|
|
cb25e077f9 | ||
|
|
0551f13f0e | ||
|
|
0965273711 | ||
|
|
dd9e8ae8ff | ||
|
|
f08bc7846a | ||
|
|
bac90cfe57 | ||
|
|
6547166c2d | ||
|
|
5a07587437 | ||
|
|
6a14d26c1d | ||
|
|
477617240a | ||
|
|
e8d2b6d25d | ||
|
|
d1a037b38b | ||
|
|
a552e5a48f | ||
|
|
b553c3f3ac | ||
|
|
551542f99a | ||
|
|
1e5bfcdbcd | ||
|
|
c1b6cb7302 | ||
|
|
70f5003784 | ||
|
|
c2a0d7bc32 | ||
|
|
34c1fec8f7 | ||
|
|
14ec226747 | ||
|
|
aebad0cf18 | ||
|
|
ecac60f4c9 | ||
|
|
21f8b852f2 | ||
|
|
4919f161cc | ||
|
|
3dda84e58b | ||
|
|
0823bfaed2 | ||
|
|
3bcb72a083 |
No files matched your search
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 180 KiB |
@@ -1,3 +1,12 @@
|
||||
v0.0.6
|
||||
======
|
||||
* Added Dynarec for ARM64
|
||||
* Many general CPU opcode added to the Dynarec
|
||||
* Many SSEx opcodes added to the Dynarec
|
||||
* Added a few more symbols in libc
|
||||
* A few changes to the "thread once" handling
|
||||
* New Logo and Icon from @grayduck
|
||||
|
||||
v0.0.4
|
||||
======
|
||||
* Added a lot of opcodes
|
||||
|
||||
+91
-11
@@ -5,8 +5,14 @@ option(RK3399 "Set to ON if targeting an Rockchip RK3399 based device" ${RK3399}
|
||||
option(USE_CCACHE "Set to ON to use ccache if present in the system" ${USE_CCACHE})
|
||||
option(HAVE_TRACE "Set to ON to have Trace ability (needs ZydisInfo library)" ${HAVE_TRACE})
|
||||
option(NOGIT "Set to ON if not building from a git clone repo (like when building from a zip download from github)" ${NOGIT})
|
||||
if(RK3399 OR RPI4ARM64)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC ON CACHE BOOL "")
|
||||
endif()
|
||||
option(LD80BITS "Set to ON if host device have 80bits long double (i.e. i386)" ${LD80BITS})
|
||||
option(NOALIGN "Set to ON if host device doesn't need re-align (i.e. i386)" ${NOALIGN})
|
||||
option(ARM_DYNAREC "Set to ON to use ARM Dynamic Recompilation" ${ARM_DYNAREC})
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.12.2")
|
||||
find_package(PythonInterp 3)
|
||||
@@ -57,7 +63,7 @@ else()
|
||||
set(BOX64 box64)
|
||||
endif()
|
||||
|
||||
set(BOX64_ELF_ADDRESS "0x50062800000") #random load address...
|
||||
set(BOX64_ELF_ADDRESS "0x500062800000") #random load address...
|
||||
|
||||
if(LD80BITS)
|
||||
add_definitions(-DHAVE_LD80BITS)
|
||||
@@ -71,6 +77,12 @@ if(HAVE_TRACE)
|
||||
add_definitions(-DHAVE_TRACE)
|
||||
endif()
|
||||
|
||||
if(ARM_DYNAREC)
|
||||
add_definitions(-DDYNAREC)
|
||||
add_definitions(-DARM64)
|
||||
enable_language(ASM)
|
||||
endif()
|
||||
|
||||
set(BOX64_ROOT ${CMAKE_SOURCE_DIR})
|
||||
|
||||
add_definitions(-std=gnu11 -funwind-tables -fvisibility=hidden)
|
||||
@@ -210,27 +222,95 @@ add_custom_command(
|
||||
# OUTPUT "${BOX64_ROOT}/src/dynarec/last_run.txt"
|
||||
# COMMAND "${PYTHON_EXECUTABLE}" "${BOX64_ROOT}/rebuild_printer.py" "${BOX64_ROOT}"
|
||||
# MAIN_DEPENDENCY "${BOX64_ROOT}/rebuild_printer.py"
|
||||
# DEPENDS "${BOX64_ROOT}/src/dynarec/arm_instructions.txt"
|
||||
# BYPRODUCTS "${BOX64_ROOT}/src/dynarec/arm_printer.c"
|
||||
# DEPENDS "${BOX64_ROOT}/src/dynarec/arm64_instructions.txt"
|
||||
# BYPRODUCTS "${BOX64_ROOT}/src/dynarec/arm64_printer.c"
|
||||
#)
|
||||
|
||||
add_custom_target(WRAPPERS DEPENDS "${BOX64_ROOT}/src/wrapped/generated/functions_list.txt")
|
||||
#add_custom_target(PRINTER DEPENDS "${BOX64_ROOT}/src/dynarec/last_run.txt")
|
||||
|
||||
if(ARM_DYNAREC)
|
||||
set(DYNAREC_SRC
|
||||
"${BOX64_ROOT}/src/dynarec/dynablock.c"
|
||||
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_functions.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64_printer.c"
|
||||
|
||||
"${BOX64_ROOT}/src/dynarec/arm64_prolog.S"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64_epilog.S"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64_next.S"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64_lock.S"
|
||||
)
|
||||
|
||||
set(DYNAREC_PASS
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_helper.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_emit_tests.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_emit_math.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_emit_logic.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_emit_shift.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_pass.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_00.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_64.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/dynarec_arm64_65.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_66.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_67.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/dynarec_arm64_d8.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/dynarec_arm64_d9.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/dynarec_arm64_da.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/dynarec_arm64_db.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/dynarec_arm64_dc.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/dynarec_arm64_dd.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/dynarec_arm64_de.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/dynarec_arm64_df.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_f0.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_660f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_f20f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_f30f.c"
|
||||
)
|
||||
|
||||
set(DYNAREC_PASS "${BOX64_ROOT}/src/wrapped/generated/wrapper.h" ${DYNAREC_PASS})
|
||||
|
||||
add_library(dynarec_arm OBJECT ${DYNAREC_SRC})
|
||||
|
||||
add_library(arm64_pass0 OBJECT ${DYNAREC_PASS})
|
||||
set_target_properties(arm64_pass0 PROPERTIES COMPILE_FLAGS "-DSTEP=0")
|
||||
add_library(arm64_pass1 OBJECT ${DYNAREC_PASS})
|
||||
set_target_properties(arm64_pass1 PROPERTIES COMPILE_FLAGS "-DSTEP=1")
|
||||
add_library(arm64_pass2 OBJECT ${DYNAREC_PASS})
|
||||
set_target_properties(arm64_pass2 PROPERTIES COMPILE_FLAGS "-DSTEP=2")
|
||||
add_library(arm64_pass3 OBJECT ${DYNAREC_PASS})
|
||||
set_target_properties(arm64_pass3 PROPERTIES COMPILE_FLAGS "-DSTEP=3")
|
||||
add_dependencies(arm64_pass0 WRAPPERS)
|
||||
add_dependencies(arm64_pass1 WRAPPERS)
|
||||
add_dependencies(arm64_pass2 WRAPPERS)
|
||||
add_dependencies(arm64_pass3 WRAPPERS)
|
||||
|
||||
add_library(dynarec STATIC
|
||||
$<TARGET_OBJECTS:dynarec_arm>
|
||||
$<TARGET_OBJECTS:arm64_pass0>
|
||||
$<TARGET_OBJECTS:arm64_pass1>
|
||||
$<TARGET_OBJECTS:arm64_pass2>
|
||||
$<TARGET_OBJECTS:arm64_pass3>
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
# creates git_head.h
|
||||
#if(ARM_DYNAREC)
|
||||
# add_custom_command(
|
||||
# OUTPUT "${BOX64_ROOT}/src/git_head.h"
|
||||
# COMMAND bash -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX64_ROOT}/src/git_head.h\""
|
||||
# DEPENDS dynarec ${ELFLOADER_SRC} ${WRAPPEDS}
|
||||
# VERBATIM)
|
||||
#else()
|
||||
if(ARM_DYNAREC)
|
||||
add_custom_command(
|
||||
OUTPUT "${BOX64_ROOT}/src/git_head.h"
|
||||
COMMAND bash -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX64_ROOT}/src/git_head.h\""
|
||||
DEPENDS dynarec ${ELFLOADER_SRC} ${WRAPPEDS}
|
||||
VERBATIM)
|
||||
else()
|
||||
add_custom_command(
|
||||
OUTPUT "${BOX64_ROOT}/src/git_head.h"
|
||||
COMMAND bash -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX64_ROOT}/src/git_head.h\""
|
||||
DEPENDS ${ELFLOADER_SRC} ${WRAPPEDS}
|
||||
VERBATIM)
|
||||
#endif()
|
||||
endif()
|
||||
|
||||
add_executable(${BOX64} ${ELFLOADER_SRC} ${WRAPPEDS} "${BOX64_ROOT}/src/git_head.h")
|
||||
add_dependencies(${BOX64} WRAPPERS)
|
||||
|
||||
Executable
+75
@@ -0,0 +1,75 @@
|
||||
Compiling
|
||||
----
|
||||
#### for RK3399
|
||||
|
||||
Using a 64bits OS:
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make -j4
|
||||
sudo make install
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
#### for PI4
|
||||
|
||||
Warning, you need a 64bits OS:
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -DRPI4ARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make -j4
|
||||
sudo make install
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
#### for Other ARM64 Linux platforms
|
||||
|
||||
`mkdir build; cd build; cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j$(nproc)`
|
||||
|
||||
#### for x86_64 Linux
|
||||
|
||||
`mkdir build; cd build; cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j$(nproc)`
|
||||
|
||||
#### use ccmake
|
||||
|
||||
Alternatively, you can use the curses-bases ccmake (or any other gui frontend for cmake) to select wich platform to use interactively.
|
||||
|
||||
#### Customize your build
|
||||
|
||||
*use ccache if you have it*
|
||||
|
||||
Add `-DUSE_CCACHE=1` if you have ccache (it's better if you plan to touch the sources)
|
||||
|
||||
*have some debug info*
|
||||
|
||||
The `-DCMAKE_BUILD_TYPE=RelWithDebInfo` argument makes a build that is both optimized for speed, and has debug information embedded. That way, if you have a crash or try to analyse performance, you'll have some symbols.
|
||||
|
||||
*to have a Trace Enabled build*
|
||||
|
||||
To have a trace enabled build ( ***it will be slower***), add `-DHAVE_TRACE=1` but you will need, at runtime, to have the [Zydis library](https://github.com/zyantific/zydis) library in your `LD_LIBRARY_PATH` or in the system library folders.
|
||||
|
||||
*to have ARM Dynarec*
|
||||
|
||||
The Dynarec is only available on the ARM architecture(Right now, anyways.). Notes also that VFPv3 and NEON are required for the Dynarec. Activate it by using `-DARM_DYNAREC=1`. Also, be sure to use `-marm` in compilation flags (because many compileur use Thumb as default, and the dynarec will not work in this mode).
|
||||
|
||||
*not building from a git clone*
|
||||
|
||||
If you are not building from a git clone (for example, downloading a release source zipped from github), you need to activate `-DNOGIT=1` from cmake to be able to build (normal process include git sha1 of HEAD in the version that box64 print).
|
||||
|
||||
----
|
||||
|
||||
Testing
|
||||
----
|
||||
A few tests are included.
|
||||
They can be launched with `ctest`
|
||||
They are very basic and don't test much for now.
|
||||
|
||||
@@ -1,7 +1,49 @@
|
||||
# box64
|
||||
|
||||

|
||||
Linux Userspace x86_64 Emulator with a twist
|
||||
|
||||
----
|
||||
|
||||
Box64 lets you run x86_64 Linux programs (such as games) on non-x86_64 Linux systems, like ARM (host system needs to be 64bit little-endian).
|
||||
Box64 lets you run x86_64 Linux programs (such as games) on non-x86_64 Linux systems, like ARM (host system needs to be 64bit little-endian).
|
||||
|
||||
Because Box64 uses the native versions of some "system" libraries, like libc, libm, SDL, and OpenGL, it's easy to integrate and use with most applications, and performance can be surprisingly high in some cases.
|
||||
|
||||
Box64 integrates a DynaRec (dynamic recompiler) for the ARM64 platform, providing a speed boost between 5 to 10 times faster than only using the interpreter.
|
||||
|
||||
Some x86 internal opcodes use parts of "Realmode X86 Emulator Library", see [x86primop.c](src/emu/x86primop.c) for copyright details
|
||||
|
||||
<img src="Box64Icon.png" width="96" height="96">
|
||||
|
||||
Logo and Icon made by @grayduck, thanks!
|
||||
|
||||
----
|
||||
|
||||
Usage
|
||||
----
|
||||
|
||||
There are a few environment variables to control the behaviour of Box64.
|
||||
|
||||
See [here](USAGE.md) for all environment variables and what they do.
|
||||
|
||||
Note: Box64's Dynarec uses a mechanism with Memory Protection and a SegFault signal handler to handle JIT code. In simpler terms, if you want to use GDB to debug a running program that use JIT'd code (like mono/Unity3D), you will still have many "normal" segfaults triggering. It is suggested to use something like `handle SIGSEGV nostop` in GDB to not stop at each segfault, and maybe put a breakpoint inside `my_memprotectionhandler` in `signals.c` if you want to trap SegFaults.
|
||||
|
||||
----
|
||||
|
||||
Compiling/Installation
|
||||
----
|
||||
> Compilation instructions can be found [here](COMPILE.md)
|
||||
|
||||
----
|
||||
|
||||
Version history
|
||||
----
|
||||
|
||||
The change log is available [here](CHANGELOG.md)
|
||||
|
||||
----
|
||||
|
||||
Final words
|
||||
----
|
||||
|
||||
(If you use Box64 in your project, please don't forget to mention Box64!)
|
||||
@@ -0,0 +1,136 @@
|
||||
|
||||
Usage
|
||||
----
|
||||
|
||||
There are many environment variables to control Box64 behaviour.
|
||||
|
||||
#### BOX64_LOG
|
||||
Controls the Verbosity level of the logs
|
||||
* 0: NONE : No message (except some fatal error). (Default.)
|
||||
* 1: INFO : Show some minimum log (Example: librairies not found)
|
||||
* 2: DEBUG : Details a lot of stuff (Example: relocations or functions called).
|
||||
* 3: DUMP : All DEBUG plus DUMP of all ELF Info.
|
||||
|
||||
#### BOX64_NOBANNER
|
||||
Disables Box64 printing its version and build
|
||||
* 0 : Enable printing its banner. (Default.)
|
||||
* 1 : Disable printing its banner.
|
||||
|
||||
#### BOX64_LD_LIBRARY_PATH
|
||||
Path to look for x86_64 libraries. Default is current folder and `lib` in current folder.
|
||||
Also, `/usr/lib/x86_64-linux-gnu` and `/lib/x86_64-linux-gnu` are added if they exist.
|
||||
|
||||
#### BOX64_PATH
|
||||
Path to look for x86_64 executable. Default is current folder and `bin` in current folder.
|
||||
|
||||
#### BOX64_DLSYM_ERROR
|
||||
Enables/Disables the logging of `dlsym` errors.
|
||||
* 0 : Don't log `dlsym` errors. (Default.)
|
||||
* 1 : Log dlsym errors.
|
||||
|
||||
#### BOX64_TRACE_FILE
|
||||
Send all log and trace to a file instead of `stdout`
|
||||
Also, if name contains `%pid` then this is replaced by the actual PID of box64 instance
|
||||
|
||||
#### BOX64_TRACE
|
||||
Only on build with trace enabled. Trace allow the logging of all instruction executed, along with register dump
|
||||
* 0 : No trace. (Default.)
|
||||
* 1 : Trace enabled. Trace start after the initialisation of all depending libraries is done.
|
||||
* symbolname : Trace only `symbolname` (trace is disable if the symbol is not found).
|
||||
* 0xXXXXXXX-0xYYYYYYY : Trace only between the 2 addresses.
|
||||
|
||||
#### BOX64_TRACE_INIT
|
||||
Use BOX64_TRACE_INIT instead of BOX_TRACE to start trace before the initialisation of libraries and the running program
|
||||
* 0 : No trace. (Default.)
|
||||
* 1 : Trace enabled. The trace start with the initialisation of all depending libraries is done.
|
||||
|
||||
#### BOX64_TRACE_START
|
||||
Only on builds with trace enabled.
|
||||
* NNNNNNN : Start trace only after NNNNNNNN opcode execute (number is an `uint64_t`).
|
||||
|
||||
#### BOX64_TRACE_XMM
|
||||
Only on builds with trace enabled.
|
||||
* 0 : The XMM (i.e. SSE/SSE2) register will not be logged with the general and x86 registers. (Default.)
|
||||
* 1 : Dump the XMM registers.
|
||||
|
||||
#### BOX64_LOAD_ADDR
|
||||
Try to load at 0xXXXXXX main binary (if binary is a PIE)
|
||||
* 0xXXXXXXXX : The load address . (Only active on PIE programs.)
|
||||
|
||||
#### BOX64_NOSIGSEGV
|
||||
Disable handling of SigSEGV. (Very useful for debugging.)
|
||||
* 0 : Let the x86 program set sighandler for SEGV (Default.)
|
||||
* 1 : Disable the handling of SigSEGV.
|
||||
|
||||
#### BOX64_NOSIGILL
|
||||
Disable handling of SigILL (to ease debugging mainly).
|
||||
* 0 : Let x86 program set sighandler for Illegal Instruction
|
||||
* 1 : Disables the handling of SigILL
|
||||
|
||||
#### BOX64_X11THREADS
|
||||
Call XInitThreads when loading X11. (This is mostly for old Loki games with the Loki_Compat library.)
|
||||
* 0 : Don't force call XInitThreads. (Default.)
|
||||
* 1 : Call XInitThreads as soon as libX11 is loaded.
|
||||
|
||||
#### BOX64_X11GLX
|
||||
Force libX11's GLX extension to be present.
|
||||
* 0 : Do not force libX11's GLX extension to be present.
|
||||
* 1 : GLX will always be present when using XQueryExtension. (Default.)
|
||||
|
||||
#### BOX64_DYNAREC_DUMP
|
||||
Enables/disables Box64's Dynarec's dump.
|
||||
* 0 : Disable Dynarec's blocks dump. (Default.)
|
||||
* 1 : Enable Dynarec's blocks dump.
|
||||
* 2 : Enable Dynarec's blocks dump with some colors.
|
||||
|
||||
#### BOX64_DYNAREC_LOG
|
||||
Set the level of DynaRec's logs.
|
||||
* 0 : NONE : No Logs for DynaRec. (Default.)
|
||||
* 1 :INFO : Minimum Dynarec Logs (only unimplemented OpCode).
|
||||
* 2 : DEBUG : Debug Logs for Dynarec (with details on block created / executed).
|
||||
* 3 : VERBOSE : All of the above plus more.
|
||||
|
||||
#### BOX64_DYNAREC
|
||||
Enables/Disables Box64's Dynarec.
|
||||
* 0 : Disables Dynarec.
|
||||
* 1 : Enable Dynarec. (Default.)
|
||||
|
||||
#### BOX64_DYNAREC_TRACE
|
||||
Enables/Disables trace for generated code.
|
||||
* 0 : Disable trace for generated code. (Default.)
|
||||
* 1 : Enable trace for generated code (like regular Trace, this will slow down the program a lot and generate huge logs).
|
||||
|
||||
#### BOX64_NODYNAREC
|
||||
Forbid dynablock creation in the interval specified (helpfull for debugging behaviour difference between Dynarec and Interpretor)
|
||||
* 0xXXXXXXXX-0xYYYYYYYY : define the interval where dynablock cannot start (inclusive-exclusive)
|
||||
|
||||
#### BOX64_LIBGL
|
||||
* libXXXX set the name for libGL (defaults to libGL.so.1).
|
||||
* /PATH/TO/libGLXXX : Sets the name and path for libGL
|
||||
You can also use SDL_VIDEO_GL_DRIVER
|
||||
|
||||
#### BOX64_LD_PRELOAD
|
||||
* XXXX[:YYYYY] force loading XXXX (and YYYY...) libraries with the binary
|
||||
PreLoaded libs can be emulated or native, and are treated the same way as if they were comming from the binary
|
||||
|
||||
#### BOX64_EMULATED_LIBS
|
||||
* XXXX[:YYYYY] force lib XXXX (and YYYY...) to be emulated (and not wrapped)
|
||||
Some games uses an old version of some libraries, with an ABI incompatible with native version.
|
||||
Note that LittleInferno for example is auto detected, and libvorbis.so.0 is automatical added to emulated libs, and same for Don't Starve (and Together / Server variant) that use an old SDL2 too
|
||||
|
||||
#### BOX64_ALLOWMISSINGLIBS
|
||||
Allow Box64 to continue even if a library is missing.
|
||||
* 0 : Box64 will stop if a library cannot be loaded. (Default.)
|
||||
* 1 : Continue even if a needed library cannot be loaded. Unadvised, this will, in most cases, crash later on.
|
||||
|
||||
#### BOX64_JITGDB
|
||||
|
||||
* 0 : Just print the Segfault message on segfault (default)
|
||||
* 1 : Launch `gdb` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process and go in an endless loop, waiting.
|
||||
When in gdb, you need to find the correct thread yourself (the one with `my_box64signalhandler` in is stack)
|
||||
then probably need to `finish` 1 or 2 functions (inside `usleep(..)`) and then you'll be in `my_box64signalhandler`,
|
||||
just before the printf of the Segfault message. Then simply
|
||||
`set waiting=0` to exit the infinite loop.
|
||||
* 2 : Launch `gdbserver` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process, and go in an endless loop, waiting.
|
||||
Use `gdb /PATH/TO/box64` and then `target remote 127.0.0.1:1234` to connect to the gdbserver (or use actual IP if not on the machine). After that, the procedure is the same as with ` BOX64_JITGDB=1`.
|
||||
This mode can be usefullwhen programs redirect all console output to a file (like Unity3D Games)
|
||||
+1
-1
@@ -3,6 +3,6 @@
|
||||
|
||||
#define BOX64_MAJOR 0
|
||||
#define BOX64_MINOR 0
|
||||
#define BOX64_REVISION 4
|
||||
#define BOX64_REVISION 6
|
||||
|
||||
#endif //__BOX64_VERSION_H_
|
||||
+748
-658
File diff suppressed because it is too large.
Load diff
Executable
+1184
File diff suppressed because it is too large.
Load diff
Executable
+54
@@ -0,0 +1,54 @@
|
||||
//arm epilog for dynarec
|
||||
//Save stuff, prepare stack and register
|
||||
//called with pointer to emu as 1st parameter
|
||||
//and address to jump to as 2nd parameter
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.global arm64_epilog
|
||||
arm64_epilog:
|
||||
//update register -> emu
|
||||
stp x10, x11, [x0, (8 * 0)]
|
||||
stp x12, x13, [x0, (8 * 2)]
|
||||
stp x14, x15, [x0, (8 * 4)]
|
||||
stp x16, x17, [x0, (8 * 6)]
|
||||
stp x18, x19, [x0, (8 * 8)]
|
||||
stp x20, x21, [x0, (8 * 10)]
|
||||
stp x22, x23, [x0, (8 * 12)]
|
||||
stp x24, x25, [x0, (8 * 14)]
|
||||
stp x26, x27, [x0, (8 * 16)] // put back reg value in emu, including EIP (so x27 must be EIP now)
|
||||
//restore all used register
|
||||
//vpop {d8-d15}
|
||||
ldp x19, x20, [sp, (8 * 0)]
|
||||
ldp x21, x22, [sp, (8 * 2)]
|
||||
ldp x23, x24, [sp, (8 * 4)]
|
||||
ldp x25, x26, [sp, (8 * 6)]
|
||||
ldr x27, [sp, (8 * 8)]
|
||||
ldp d8, d9, [sp, (8 *10)]
|
||||
ldp d10, d11, [sp, (8 *12)]
|
||||
ldp d12, d13, [sp, (8 *14)]
|
||||
ldp d14, d15, [sp, (8 *16)]
|
||||
add sp, sp, (8 * 18)
|
||||
ldp lr, fp, [sp], 16 // saved lr
|
||||
//end, return...
|
||||
ret
|
||||
|
||||
|
||||
.global arm64_epilog_fast
|
||||
arm64_epilog_fast:
|
||||
//restore all used register
|
||||
//vpop {d8-d15}
|
||||
ldp x19, x20, [sp, (8 * 0)]
|
||||
ldp x21, x22, [sp, (8 * 2)]
|
||||
ldp x23, x24, [sp, (8 * 4)]
|
||||
ldp x25, x26, [sp, (8 * 6)]
|
||||
ldr x27, [sp, (8 * 8)]
|
||||
ldp d8, d9, [sp, (8 *10)]
|
||||
ldp d10, d11, [sp, (8 *12)]
|
||||
ldp d12, d13, [sp, (8 *14)]
|
||||
ldp d14, d15, [sp, (8 *16)]
|
||||
add sp, sp, (8 * 18)
|
||||
ldp lr, fp, [sp], 16 // saved lr
|
||||
//end, return...
|
||||
ret
|
||||
Executable
+87
@@ -0,0 +1,87 @@
|
||||
//arm lock helper
|
||||
//there is 2 part: read and write
|
||||
// write return 0 on success, 1 on fail (value has been changed)
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.global arm64_lock_read_b
|
||||
.global arm64_lock_write_b
|
||||
.global arm64_lock_read_h
|
||||
.global arm64_lock_write_h
|
||||
.global arm64_lock_read_d
|
||||
.global arm64_lock_write_d
|
||||
.global arm64_lock_read_dd
|
||||
.global arm64_lock_write_dd
|
||||
.global arm64_lock_xchg
|
||||
.global arm64_lock_storeifnull
|
||||
|
||||
|
||||
arm64_lock_read_b:
|
||||
// address is x0, return is x0
|
||||
ldaxrb w0, [x0]
|
||||
ret
|
||||
|
||||
arm64_lock_write_b:
|
||||
// address is x0, value is x1, return is x0
|
||||
mov x2, x0
|
||||
stlxrb w0, w1, [x2]
|
||||
ret
|
||||
|
||||
arm64_lock_read_h:
|
||||
// address is x0, return is x0
|
||||
ldaxrh w0, [x0]
|
||||
ret
|
||||
|
||||
arm64_lock_write_h:
|
||||
// address is x0, value is x1, return is x0
|
||||
mov x2, x0
|
||||
stlxrh w0, w1, [x2]
|
||||
ret
|
||||
|
||||
arm64_lock_read_d:
|
||||
// address is x0, return is x0
|
||||
ldaxr w0, [x0]
|
||||
#ldx w0,[x0]
|
||||
ret
|
||||
|
||||
arm64_lock_write_d:
|
||||
// address is x0, value is w1, return is x0
|
||||
mov x2, x0
|
||||
stlxr w0, w1, [x2]
|
||||
#str w1, [x2]
|
||||
mov w0, 0
|
||||
ret
|
||||
|
||||
arm64_lock_read_dd:
|
||||
// address is x0, return is x0
|
||||
ldaxr x0, [x0]
|
||||
ret
|
||||
|
||||
arm64_lock_write_dd:
|
||||
// address is x0, value is x1, return is x0
|
||||
mov x2, x0
|
||||
stlxr w0, x1, [x2]
|
||||
ret
|
||||
|
||||
arm64_lock_xchg:
|
||||
// address is x0, value is x1, return old value in x0
|
||||
ldaxr x2, [x0]
|
||||
stlxr w3, x1, [x0]
|
||||
cmp w3, #1
|
||||
beq arm64_lock_xchg
|
||||
mov x0, x2
|
||||
ret
|
||||
|
||||
arm64_lock_storeifnull:
|
||||
// address is x0, value is x1, x1 store to x0 only if [x0] is 0. return new [x0] value (so x1 or old value)
|
||||
ldaxr x2, [x0]
|
||||
cmp x2, #0
|
||||
bne arm64_lock_storeifnull_exit
|
||||
mov x2, x1
|
||||
stlxr w3, x2, [x0]
|
||||
cmp w3, #1
|
||||
beq arm64_lock_storeifnull
|
||||
arm64_lock_storeifnull_exit:
|
||||
mov x0, x2
|
||||
ret
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#ifndef __ARM64_LOCK__H__
|
||||
#define __ARM64_LOCK__H__
|
||||
#include <stdint.h>
|
||||
|
||||
// LDAXRB of ADDR
|
||||
extern uint8_t arm64_lock_read_b(void* addr);
|
||||
// STLXRB of ADDR, return 0 if ok, 1 if not
|
||||
extern int arm64_lock_write_b(void* addr, uint8_t val);
|
||||
|
||||
// LDAXRH of ADDR
|
||||
extern uint16_t arm64_lock_read_h(void* addr);
|
||||
// STLXRH of ADDR, return 0 if ok, 1 if not
|
||||
extern int arm64_lock_write_h(void* addr, uint16_t val);
|
||||
|
||||
// LDAXR of ADDR
|
||||
extern uint32_t arm64_lock_read_d(void* addr);
|
||||
// STLXR of ADDR, return 0 if ok, 1 if not
|
||||
extern int arm64_lock_write_d(void* addr, uint32_t val);
|
||||
|
||||
// LDAXRD of ADDR
|
||||
extern uint64_t arm64_lock_read_dd(void* addr);
|
||||
// STLXR of ADDR, return 0 if ok, 1 if not
|
||||
extern int arm64_lock_write_dd(void* addr, uint64_t val);
|
||||
|
||||
// Atomicaly exchange value at [p] with val, return old p
|
||||
extern uintptr_t arm64_lock_xchg(void* p, uintptr_t val);
|
||||
|
||||
// Atomicaly store value to [p] only if [p] is NULL. Return new [p] value (so val or old)
|
||||
extern void* arm64_lock_storeifnull(void*p, void* val);
|
||||
|
||||
#endif //__ARM64_LOCK__H__
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
//arm update linker table for dynarec
|
||||
//called with pointer to emu as 1st parameter
|
||||
//and address of table to as 2nd parameter
|
||||
//ip is at r12
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.extern LinkNext
|
||||
|
||||
.global arm64_next
|
||||
arm64_next:
|
||||
// emu is r0
|
||||
// IP address is r1
|
||||
sub sp, sp, (8 * 12)
|
||||
stp x0, x1, [sp, (8 * 0)]
|
||||
stp x10, x11, [sp, (8 * 2)]
|
||||
stp x12, x13, [sp, (8 * 4)]
|
||||
stp x14, x15, [sp, (8 * 6)]
|
||||
stp x16, x17, [sp, (8 * 8)]
|
||||
str x18, [sp, (8 * 10)]
|
||||
// call the function
|
||||
bl LinkNext
|
||||
// preserve return value
|
||||
mov x3, x0
|
||||
// pop regs
|
||||
ldp x0, x1, [sp, (8 * 0)]
|
||||
ldp x10, x11, [sp, (8 * 2)]
|
||||
ldp x12, x13, [sp, (8 * 4)]
|
||||
ldp x14, x15, [sp, (8 * 6)]
|
||||
ldp x16, x17, [sp, (8 * 8)]
|
||||
ldr x18, [sp, (8 * 10)]
|
||||
add sp, sp, (8 * 12)
|
||||
// return offset is jump address
|
||||
br x3
|
||||
|
||||
Executable
+1038
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,6 @@
|
||||
#ifndef _ARM_PRINTER_H_
|
||||
#define _ARM_PRINTER_H_
|
||||
|
||||
const char* arm64_print(uint32_t opcode, uint64_t addr);
|
||||
|
||||
#endif //_ARM_PRINTER_H_
|
||||
Executable
+35
@@ -0,0 +1,35 @@
|
||||
//arm prologue for dynarec
|
||||
//Save stuff, prepare stack and register
|
||||
//called with pointer to emu as 1st parameter
|
||||
//and address to jump to as 2nd parameter
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.global arm64_prolog
|
||||
arm64_prolog:
|
||||
//save all 18 used register
|
||||
stp lr, fp, [sp, -16]! // save lr
|
||||
sub sp, sp, (8 * 18)
|
||||
stp x19, x20, [sp, (8 * 0)]
|
||||
stp x21, x22, [sp, (8 * 2)]
|
||||
stp x23, x24, [sp, (8 * 4)]
|
||||
stp x25, x26, [sp, (8 * 6)]
|
||||
str x27, [sp, (8 * 8)]
|
||||
stp d8, d9, [sp, (8 *10)]
|
||||
stp d10, d11, [sp, (8 *12)]
|
||||
stp d12, d13, [sp, (8 *14)]
|
||||
stp d14, d15, [sp, (8 *16)]
|
||||
//vpush {d8-d15} // save NEON regs?
|
||||
//setup emu -> register
|
||||
ldp x10, x11, [x0, (8 * 0)]
|
||||
ldp x12, x13, [x0, (8 * 2)]
|
||||
ldp x14, x15, [x0, (8 * 4)]
|
||||
ldp x16, x17, [x0, (8 * 6)]
|
||||
ldp x18, x19, [x0, (8 * 8)]
|
||||
ldp x20, x21, [x0, (8 * 10)]
|
||||
ldp x22, x23, [x0, (8 * 12)]
|
||||
ldp x24, x25, [x0, (8 * 14)]
|
||||
ldp x26, x27, [x0, (8 * 16)]
|
||||
//jump to function
|
||||
br x1
|
||||
Executable
+426
@@ -0,0 +1,426 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "tools/bridge_private.h"
|
||||
#include "x64run.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_private.h"
|
||||
#include "elfloader.h"
|
||||
#ifdef ARM64
|
||||
#include "dynarec_arm64.h"
|
||||
#include "arm64_lock.h"
|
||||
#else
|
||||
#error Unsupported architecture!
|
||||
#endif
|
||||
#include "custommem.h"
|
||||
#include "khash.h"
|
||||
|
||||
KHASH_MAP_INIT_INT(dynablocks, dynablock_t*)
|
||||
|
||||
uint32_t X31_hash_code(void* addr, int len)
|
||||
{
|
||||
if(!len) return 0;
|
||||
uint8_t* p = (uint8_t*)addr;
|
||||
int32_t h = *p;
|
||||
for (--len, ++p; len; --len, ++p) h = (h << 5) - h + (int32_t)*p;
|
||||
return (uint32_t)h;
|
||||
}
|
||||
|
||||
dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct)
|
||||
{
|
||||
if(!textsz) {
|
||||
printf_log(LOG_NONE, "Error, creating a NULL sized Dynablock\n");
|
||||
return NULL;
|
||||
}
|
||||
dynablocklist_t* ret = (dynablocklist_t*)calloc(1, sizeof(dynablocklist_t));
|
||||
ret->text = text;
|
||||
ret->textsz = textsz;
|
||||
if(direct && textsz) {
|
||||
ret->direct = (dynablock_t**)calloc(textsz, sizeof(dynablock_t*));
|
||||
if(!ret->direct) {printf_log(LOG_NONE, "Warning, fail to create direct block for dynablock @%p\n", (void*)text);}
|
||||
}
|
||||
dynarec_log(LOG_DEBUG, "New Dynablocklist %p, from %p->%p\n", ret, (void*)text, (void*)(text+textsz));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void FreeDynablock(dynablock_t* db)
|
||||
{
|
||||
if(db) {
|
||||
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x64=%p:%p parent=%p, father=%p, with %d son(s) already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size, db->parent, db->father, db->sons_size, db->gone);
|
||||
if(db->gone)
|
||||
return; // already in the process of deletion!
|
||||
db->done = 0;
|
||||
db->gone = 1;
|
||||
// remove from direct if there
|
||||
uintptr_t startdb = db->parent->text;
|
||||
uintptr_t enddb = db->parent->text + db->parent->textsz;
|
||||
if(db->parent->direct) {
|
||||
uintptr_t addr = (uintptr_t)db->x64_addr;
|
||||
if(addr>=startdb && addr<enddb)
|
||||
db->parent->direct[addr-startdb] = NULL;
|
||||
}
|
||||
// remove jumptable
|
||||
setJumpTableDefault64(db->x64_addr);
|
||||
// remove and free the sons
|
||||
for (int i=0; i<db->sons_size; ++i) {
|
||||
dynablock_t *son = (dynablock_t*)arm64_lock_xchg(&db->sons[i], 0);
|
||||
FreeDynablock(son);
|
||||
}
|
||||
// only the father free the DynarecMap
|
||||
if(!db->father) {
|
||||
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->block, db->size);
|
||||
FreeDynarecMap(db, (uintptr_t)db->block, db->size);
|
||||
}
|
||||
free(db->sons);
|
||||
free(db->instsize);
|
||||
free(db);
|
||||
}
|
||||
}
|
||||
|
||||
void FreeDynablockList(dynablocklist_t** dynablocks)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(!*dynablocks)
|
||||
return;
|
||||
dynarec_log(LOG_DEBUG, "Free Dynablocklist %p, with Direct Blocks %p\n", *dynablocks, (*dynablocks)->direct);
|
||||
if((*dynablocks)->direct) {
|
||||
for (int i=0; i<(*dynablocks)->textsz; ++i) {
|
||||
if((*dynablocks)->direct[i] && !(*dynablocks)->direct[i]->father)
|
||||
FreeDynablock((*dynablocks)->direct[i]);
|
||||
}
|
||||
free((*dynablocks)->direct);
|
||||
}
|
||||
(*dynablocks)->direct = NULL;
|
||||
|
||||
free(*dynablocks);
|
||||
*dynablocks = NULL;
|
||||
}
|
||||
|
||||
void MarkDynablock(dynablock_t* db)
|
||||
{
|
||||
if(db) {
|
||||
if(db->father)
|
||||
db = db->father; // mark only father
|
||||
if(db->need_test)
|
||||
return; // already done
|
||||
db->need_test = 1; // test only blocks that can be marked (and so deleted)
|
||||
setJumpTableDefault64(db->x64_addr);
|
||||
for(int i=0; i<db->sons_size; ++i)
|
||||
setJumpTableDefault64(db->sons[i]->x64_addr);
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t StartDynablockList(dynablocklist_t* db)
|
||||
{
|
||||
if(db)
|
||||
return db->text;
|
||||
return 0;
|
||||
}
|
||||
uintptr_t EndDynablockList(dynablocklist_t* db)
|
||||
{
|
||||
if(db)
|
||||
return db->text+db->textsz-1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2, uintptr_t end2)
|
||||
{
|
||||
if(start1 > end2 || start2 > end1)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(!dynablocks->direct)
|
||||
return;
|
||||
uintptr_t startdb = dynablocks->text;
|
||||
uintptr_t enddb = startdb + dynablocks->textsz -1;
|
||||
uintptr_t start = addr;
|
||||
uintptr_t end = addr+size-1;
|
||||
if(start<startdb)
|
||||
start = startdb;
|
||||
if(end>enddb)
|
||||
end = enddb;
|
||||
dynablock_t *db;
|
||||
if(end>startdb && start<enddb)
|
||||
for(uintptr_t i = start; i<end; ++i)
|
||||
if((db=dynablocks->direct[i-startdb]))
|
||||
if(IntervalIntersects((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr+db->x64_size-1, addr, addr+size+1))
|
||||
MarkDynablock(db);
|
||||
}
|
||||
|
||||
void FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
|
||||
if(dynablocks->direct) {
|
||||
dynablock_t* db;
|
||||
int ret;
|
||||
khint_t k;
|
||||
kh_dynablocks_t *blocks = kh_init(dynablocks);
|
||||
// copy in a temporary list
|
||||
if(dynablocks->direct) {
|
||||
uintptr_t startdb = dynablocks->text;
|
||||
uintptr_t enddb = startdb + dynablocks->textsz;
|
||||
uintptr_t start = addr;
|
||||
uintptr_t end = addr+size;
|
||||
if(start<startdb)
|
||||
start = startdb;
|
||||
if(end>enddb)
|
||||
end = enddb;
|
||||
if(end>startdb && start<enddb)
|
||||
for(uintptr_t i = start; i<end; ++i) {
|
||||
db = (dynablock_t*)arm64_lock_xchg(&dynablocks->direct[i-startdb], 0);
|
||||
if(db) {
|
||||
if(db->father)
|
||||
db = db->father;
|
||||
if(db->parent==dynablocks) {
|
||||
k = kh_put(dynablocks, blocks, (uintptr_t)db, &ret);
|
||||
kh_value(blocks, k) = db;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// purge the list
|
||||
kh_foreach_value(blocks, db,
|
||||
FreeDynablock(db);
|
||||
);
|
||||
kh_destroy(dynablocks, blocks);
|
||||
}
|
||||
}
|
||||
void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(dynablocks->direct) {
|
||||
uintptr_t new_addr = addr - dynablocks->maxsz;
|
||||
uintptr_t new_size = size + dynablocks->maxsz;
|
||||
MarkDirectDynablock(dynablocks, new_addr, new_size);
|
||||
// the blocks check before
|
||||
for(int idx=(new_addr)>>DYNAMAP_SHIFT; idx<(addr>>DYNAMAP_SHIFT); ++idx)
|
||||
MarkDirectDynablock(getDB(idx), new_addr, new_size);
|
||||
}
|
||||
}
|
||||
|
||||
dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return NULL;
|
||||
dynablock_t* db;
|
||||
kh_foreach_value(dynablocks, db,
|
||||
const uintptr_t s = (uintptr_t)db->block;
|
||||
const uintptr_t e = (uintptr_t)db->block+db->size;
|
||||
if((uintptr_t)addr>=s && (uintptr_t)addr<e)
|
||||
return db->father?db->father:db;
|
||||
)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static dynablocklist_t* getDBFromAddress(uintptr_t addr)
|
||||
{
|
||||
const uintptr_t idx = (addr>>DYNAMAP_SHIFT);
|
||||
return getDB(idx);
|
||||
}
|
||||
|
||||
dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* created)
|
||||
{
|
||||
if(!dynablocks) {
|
||||
dynarec_log(LOG_INFO, "Warning: Ask to create a dynablock with a NULL dynablocklist (addr=%p)\n", (void*)addr);
|
||||
*created = 0;
|
||||
return NULL;
|
||||
}
|
||||
if((addr<dynablocks->text) || (addr>=(dynablocks->text+dynablocks->textsz))) {
|
||||
// this should be useless
|
||||
//dynarec_log(LOG_INFO, "Warning: Refused to create a Direct Block that is out-of-bound: dynablocks=%p (%p:%p), addr=%p\n", dynablocks, (void*)(dynablocks->text), (void*)(dynablocks->text+dynablocks->textsz), (void*)addr);
|
||||
//*created = 0;
|
||||
//return NULL;
|
||||
return AddNewDynablock(getDBFromAddress(addr), addr, created);
|
||||
}
|
||||
dynablock_t* block = NULL;
|
||||
// first, check if it exist in direct access mode
|
||||
if(dynablocks->direct) {
|
||||
block = dynablocks->direct[addr-dynablocks->text];
|
||||
if(block) {
|
||||
dynarec_log(LOG_DUMP, "Block already exist in Direct Map\n");
|
||||
*created = 0;
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
||||
if (!*created)
|
||||
return block;
|
||||
|
||||
if(!dynablocks->direct) {
|
||||
dynablock_t** p = (dynablock_t**)calloc(dynablocks->textsz, sizeof(dynablock_t*));
|
||||
if(arm64_lock_storeifnull(&dynablocks->direct, p)!=p)
|
||||
free(p); // someone already create the direct array, too late...
|
||||
}
|
||||
|
||||
// create and add new block
|
||||
dynarec_log(LOG_DUMP, "Ask for DynaRec Block creation @%p\n", (void*)addr);
|
||||
|
||||
block = (dynablock_t*)calloc(1, sizeof(dynablock_t));
|
||||
block->parent = dynablocks;
|
||||
dynablock_t* tmp = (dynablock_t*)arm64_lock_storeifnull(&dynablocks->direct[addr-dynablocks->text], block);
|
||||
if(tmp != block) {
|
||||
// a block appeard!
|
||||
free(block);
|
||||
*created = 0;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
*created = 1;
|
||||
return block;
|
||||
}
|
||||
|
||||
/*
|
||||
return NULL if block is not found / cannot be created.
|
||||
Don't create if create==0
|
||||
*/
|
||||
static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, dynablock_t* current)
|
||||
{
|
||||
// try the quickest way first: get parent of current and check if ok!
|
||||
dynablocklist_t *dynablocks = NULL;
|
||||
dynablock_t* block = NULL;
|
||||
if(current) {
|
||||
dynablocks = current->parent;
|
||||
if(dynablocks && !(addr>=dynablocks->text && addr<(dynablocks->text+dynablocks->textsz)))
|
||||
dynablocks = NULL;
|
||||
}
|
||||
// nope, lets do the long way
|
||||
if(!dynablocks) {
|
||||
dynablocks = getDBFromAddress(addr);
|
||||
if(!dynablocks) {
|
||||
dynablocks = GetDynablocksFromAddress(emu->context, addr);
|
||||
if(!dynablocks)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
// check direct first, without lock
|
||||
if(dynablocks->direct/* && (addr>=dynablocks->text) && (addr<(dynablocks->text+dynablocks->textsz))*/)
|
||||
if((block = dynablocks->direct[addr-dynablocks->text]))
|
||||
return block;
|
||||
|
||||
int created = create;
|
||||
block = AddNewDynablock(dynablocks, addr, &created);
|
||||
if(!created)
|
||||
return block; // existing block...
|
||||
|
||||
#if 1
|
||||
if(box64_dynarec_dump)
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
#endif
|
||||
// fill the block
|
||||
block->x64_addr = (void*)addr;
|
||||
if(!FillBlock64(block, filladdr)) {
|
||||
void* old = (void*)arm64_lock_xchg(&dynablocks->direct[addr-dynablocks->text], 0);
|
||||
if(old!=block && old) {// put it back in place, strange things are happening here!
|
||||
dynarec_log(LOG_INFO, "Warning, a wild block appeared at %p: %p\n", (void*)addr, old);
|
||||
arm64_lock_xchg(&dynablocks->direct[addr-dynablocks->text], (uintptr_t)old);
|
||||
}
|
||||
free(block);
|
||||
block = NULL;
|
||||
}
|
||||
#if 1
|
||||
if(box64_dynarec_dump)
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
#endif
|
||||
// check size
|
||||
if(block && block->x64_size) {
|
||||
int blocksz = block->x64_size;
|
||||
if(dynablocks->maxsz<blocksz) {
|
||||
dynablocks->maxsz = blocksz;
|
||||
for(int idx=(addr>>DYNAMAP_SHIFT)+1; idx<=((addr+blocksz)>>DYNAMAP_SHIFT); ++idx) {
|
||||
dynablocklist_t* dblist;
|
||||
if((dblist = getDB(idx)))
|
||||
if(dblist->maxsz<blocksz)
|
||||
dblist->maxsz = blocksz;
|
||||
}
|
||||
}
|
||||
lockDB();
|
||||
protectDBnolock((uintptr_t)block->x64_addr, block->x64_size);
|
||||
// fill-in jumptable
|
||||
addJumpTableIfDefault64(block->x64_addr, block->block);
|
||||
for(int i=0; i<block->sons_size; ++i)
|
||||
addJumpTableIfDefault64(block->sons[i]->x64_addr, block->sons[i]->block);
|
||||
unlockDB();
|
||||
}
|
||||
|
||||
dynarec_log(LOG_DEBUG, " --- DynaRec Block %s @%p:%p (%p, 0x%x bytes, with %d son(s))\n", created?"created":"recycled", (void*)addr, (void*)(addr+((block)?block->x64_size:0)), (block)?block->block:0, (block)?block->size:0, (block)?block->sons_size:0);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, dynablock_t** current)
|
||||
{
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, *current);
|
||||
if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
|
||||
dynablock_t *father = db->father?db->father:db;
|
||||
uint32_t hash = X31_hash_code(father->x64_addr, father->x64_size);
|
||||
if(hash!=father->hash) {
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x64_addr, father->x64_addr+father->x64_size, hash, father->hash, father->sons_size, (void*)addr);
|
||||
// no more current if it gets invalidated too
|
||||
if(*current && father->x64_addr>=(*current)->x64_addr && (father->x64_addr+father->x64_size)<(*current)->x64_addr)
|
||||
*current = NULL;
|
||||
// Free father, it's now invalid!
|
||||
FreeDynablock(father);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, addr, create, *current);
|
||||
} else {
|
||||
father->need_test = 0;
|
||||
lockDB();
|
||||
protectDBnolock((uintptr_t)father->x64_addr, father->x64_size);
|
||||
// fill back jumptable
|
||||
addJumpTableIfDefault64(father->x64_addr, father->block);
|
||||
for(int i=0; i<father->sons_size; ++i)
|
||||
addJumpTableIfDefault64(father->sons[i]->x64_addr, father->sons[i]->block);
|
||||
unlockDB();
|
||||
}
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "Creating AlternateBlock at %p for %p\n", (void*)addr, (void*)filladdr);
|
||||
int create = 1;
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, NULL);
|
||||
if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
|
||||
dynablock_t *father = db->father?db->father:db;
|
||||
uint32_t hash = X31_hash_code(father->x64_addr, father->x64_size);
|
||||
if(hash!=father->hash) {
|
||||
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x64_addr, father->x64_addr+father->x64_size, hash, father->hash, father->sons_size, (void*)addr);
|
||||
// Free father, it's now invalid!
|
||||
FreeDynablock(father);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, filladdr, create, NULL);
|
||||
} else {
|
||||
father->need_test = 0;
|
||||
lockDB();
|
||||
protectDBnolock((uintptr_t)father->x64_addr, father->x64_size);
|
||||
// fill back jumptable
|
||||
addJumpTableIfDefault64(father->x64_addr, father->block);
|
||||
for(int i=0; i<father->sons_size; ++i)
|
||||
addJumpTableIfDefault64(father->sons[i]->x64_addr, father->sons[i]->block);
|
||||
unlockDB();
|
||||
}
|
||||
}
|
||||
return db;
|
||||
}
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#ifndef __DYNABLOCK_PRIVATE_H_
|
||||
#define __DYNABLOCK_PRIVATE_H_
|
||||
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
|
||||
typedef struct instsize_s {
|
||||
unsigned int x64:4;
|
||||
unsigned int nat:4;
|
||||
} instsize_t;
|
||||
|
||||
typedef struct dynablock_s {
|
||||
dynablocklist_t* parent;
|
||||
void* block;
|
||||
int size;
|
||||
void* x64_addr;
|
||||
uintptr_t x64_size;
|
||||
uint32_t hash;
|
||||
uint8_t need_test;
|
||||
uint8_t done;
|
||||
uint8_t gone;
|
||||
uint8_t dummy;
|
||||
int isize;
|
||||
dynablock_t** sons; // sons (kind-of dummy dynablock...)
|
||||
int sons_size;
|
||||
dynablock_t* father; // set only in the case of a son
|
||||
instsize_t* instsize;
|
||||
} dynablock_t;
|
||||
|
||||
typedef struct dynablocklist_s {
|
||||
uintptr_t text;
|
||||
int textsz;
|
||||
int maxsz; // maxblock size (for this block or previous block)
|
||||
dynablock_t** direct; // direct mapping (waste of space, so the array is created at first write)
|
||||
} dynablocklist_t;
|
||||
|
||||
#endif //__DYNABLOCK_PRIVATE_H_
|
||||
+19
-19
@@ -22,10 +22,10 @@
|
||||
#endif
|
||||
|
||||
#ifdef DYNAREC
|
||||
#ifdef ARM
|
||||
void arm_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
|
||||
void arm_epilog() EXPORTDYN;
|
||||
void arm_epilog_fast() EXPORTDYN;
|
||||
#ifdef ARM64
|
||||
void arm64_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
|
||||
void arm64_epilog() EXPORTDYN;
|
||||
void arm64_epilog_fast() EXPORTDYN;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -39,7 +39,7 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2)
|
||||
if(!addr) {
|
||||
x2-=8; // actual PC is 2 instructions ahead
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2);
|
||||
printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x86addr=%p)\n", x2, db, db?(void*)getX86Address(db, (uintptr_t)x2):NULL);
|
||||
printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x64addr=%p)\n", x2, db, db?(void*)getX64Address(db, (uintptr_t)x2):NULL);
|
||||
}
|
||||
#endif
|
||||
dynablock_t* current = NULL;
|
||||
@@ -47,17 +47,17 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2)
|
||||
dynablock_t* block = DBGetBlock(emu, addr, 1, ¤t);
|
||||
if(!block) {
|
||||
// no block, let link table as is...
|
||||
//tableupdate(arm_epilog, addr, table);
|
||||
return arm_epilog;
|
||||
//tableupdate(arm64_epilog, addr, table);
|
||||
return arm64_epilog;
|
||||
}
|
||||
if(!block->done) {
|
||||
// not finished yet... leave linker
|
||||
//tableupdate(arm_linker, addr, table);
|
||||
return arm_epilog;
|
||||
return arm64_epilog;
|
||||
}
|
||||
if(!(jblock=block->block)) {
|
||||
// null block, but done: go to epilog, no linker here
|
||||
return arm_epilog;
|
||||
return arm64_epilog;
|
||||
}
|
||||
//dynablock_t *father = block->father?block->father:block;
|
||||
return jblock;
|
||||
@@ -82,7 +82,7 @@ void DynaCall(x64emu_t* emu, uintptr_t addr)
|
||||
}
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
if(!box86_dynarec)
|
||||
if(!box64_dynarec)
|
||||
#endif
|
||||
EmuCall(emu, addr);
|
||||
#ifdef DYNAREC
|
||||
@@ -107,18 +107,18 @@ void DynaCall(x64emu_t* emu, uintptr_t addr)
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling Interpretor @%p, emu=%p\n", GetTID(), (void*)R_RIP, emu);
|
||||
Run(emu, 1);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x86 instructions (father=%p) emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize ,block->father, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x64 instructions (father=%p) emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize ,block->father, emu);
|
||||
CHECK_FLAGS(emu);
|
||||
// block is here, let's run it!
|
||||
#ifdef ARM
|
||||
arm_prolog(emu, block->block);
|
||||
#ifdef ARM64
|
||||
arm64_prolog(emu, block->block);
|
||||
#endif
|
||||
}
|
||||
if(emu->fork) {
|
||||
int forktype = emu->fork;
|
||||
emu->quit = 0;
|
||||
emu->fork = 0;
|
||||
emu = x86emu_fork(emu, forktype);
|
||||
emu = x64emu_fork(emu, forktype);
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
ejb->emu = emu;
|
||||
@@ -170,7 +170,7 @@ int DynaRun(x64emu_t* emu)
|
||||
}
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
if(!box86_dynarec)
|
||||
if(!box64_dynarec)
|
||||
#endif
|
||||
return Run(emu, 0);
|
||||
#ifdef DYNAREC
|
||||
@@ -186,17 +186,17 @@ int DynaRun(x64emu_t* emu)
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running Interpretor @%p, emu=%p\n", GetTID(), (void*)R_RIP, emu);
|
||||
Run(emu, 1);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x86 insts (father=%p) emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize, block->father, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x64 insts (father=%p) emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize, block->father, emu);
|
||||
// block is here, let's run it!
|
||||
#ifdef ARM
|
||||
arm_prolog(emu, block->block);
|
||||
#ifdef ARM64
|
||||
arm64_prolog(emu, block->block);
|
||||
#endif
|
||||
}
|
||||
if(emu->fork) {
|
||||
int forktype = emu->fork;
|
||||
emu->quit = 0;
|
||||
emu->fork = 0;
|
||||
emu = x86emu_fork(emu, forktype);
|
||||
emu = x64emu_fork(emu, forktype);
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
ejb->emu = emu;
|
||||
|
||||
Executable
+477
@@ -0,0 +1,477 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "custommem.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "tools/bridge_private.h"
|
||||
#include "x64run.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_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "elfloader.h"
|
||||
|
||||
void printf_x64_instruction(zydis_dec_t* dec, instruction_x64_t* inst, const char* name) {
|
||||
uint8_t *ip = (uint8_t*)inst->addr;
|
||||
if(ip[0]==0xcc && ip[1]=='S' && ip[2]=='C') {
|
||||
uintptr_t a = *(uintptr_t*)(ip+3);
|
||||
if(a==0) {
|
||||
dynarec_log(LOG_NONE, "%s%p: Exit x64emu%s\n", (box64_dynarec_dump>1)?"\e[1m":"", (void*)ip, (box64_dynarec_dump>1)?"\e[m":"");
|
||||
} else {
|
||||
dynarec_log(LOG_NONE, "%s%p: Native call to %p%s\n", (box64_dynarec_dump>1)?"\e[1m":"", (void*)ip, (void*)a, (box64_dynarec_dump>1)?"\e[m":"");
|
||||
}
|
||||
} else {
|
||||
if(dec) {
|
||||
dynarec_log(LOG_NONE, "%s%p: %s", (box64_dynarec_dump>1)?"\e[1m":"", ip, DecodeX64Trace(dec, inst->addr));
|
||||
} else {
|
||||
dynarec_log(LOG_NONE, "%s%p: ", (box64_dynarec_dump>1)?"\e[1m":"", ip);
|
||||
for(int i=0; i<inst->size; ++i) {
|
||||
dynarec_log(LOG_NONE, "%02X ", ip[i]);
|
||||
}
|
||||
dynarec_log(LOG_NONE, " %s", name);
|
||||
}
|
||||
// print Call function name if possible
|
||||
if(ip[0]==0xE8 || ip[0]==0xE9) { // Call / Jmp
|
||||
uintptr_t nextaddr = (uintptr_t)ip + 5 + *((int32_t*)(ip+1));
|
||||
printFunctionAddr(nextaddr, "=> ");
|
||||
} else if(ip[0]==0xFF) {
|
||||
if(ip[1]==0x25) {
|
||||
uintptr_t nextaddr = (uintptr_t)ip + 6 + *((int32_t*)(ip+2));
|
||||
printFunctionAddr(nextaddr, "=> ");
|
||||
}
|
||||
}
|
||||
// end of line and colors
|
||||
dynarec_log(LOG_NONE, "%s\n", (box64_dynarec_dump>1)?"\e[m":"");
|
||||
}
|
||||
}
|
||||
|
||||
void add_next(dynarec_arm_t *dyn, uintptr_t addr) {
|
||||
if(dyn->next_sz == dyn->next_cap) {
|
||||
dyn->next_cap += 16;
|
||||
dyn->next = (uintptr_t*)realloc(dyn->next, dyn->next_cap*sizeof(uintptr_t));
|
||||
}
|
||||
for(int i=0; i<dyn->next_sz; ++i)
|
||||
if(dyn->next[i]==addr)
|
||||
return;
|
||||
dyn->next[dyn->next_sz++] = addr;
|
||||
}
|
||||
uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr) {
|
||||
// get closest, but no addresses befores
|
||||
uintptr_t best = 0;
|
||||
int i = 0;
|
||||
while((i<dyn->next_sz) && (best!=addr)) {
|
||||
if(dyn->next[i]<addr) { // remove the address, it's before current address
|
||||
memmove(dyn->next+i, dyn->next+i+1, (dyn->next_sz-i-1)*sizeof(uintptr_t));
|
||||
--dyn->next_sz;
|
||||
} else {
|
||||
if((dyn->next[i]<best) || !best)
|
||||
best = dyn->next[i];
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
#define PK(A) (*((uint8_t*)(addr+(A))))
|
||||
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n)
|
||||
{
|
||||
if(!n)
|
||||
return 1;
|
||||
if(PK(0)==0x90)
|
||||
return is_nops(dyn, addr+1, n-1);
|
||||
if(n>1 && PK(0)==0x66) // if opcode start with 0x66, and there is more after, than is *can* be a NOP
|
||||
return is_nops(dyn, addr+1, n-1);
|
||||
if(n>2 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x00)
|
||||
return is_nops(dyn, addr+3, n-3);
|
||||
if(n>2 && PK(0)==0x8d && PK(1)==0x76 && PK(2)==0x00) // lea esi, [esi]
|
||||
return is_nops(dyn, addr+3, n-3);
|
||||
if(n>3 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x40 && PK(3)==0x00)
|
||||
return is_nops(dyn, addr+4, n-4);
|
||||
if(n>3 && PK(0)==0x8d && PK(1)==0x74 && PK(2)==0x26 && PK(3)==0x00)
|
||||
return is_nops(dyn, addr+4, n-4);
|
||||
if(n>4 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x44 && PK(3)==0x00 && PK(4)==0x00)
|
||||
return is_nops(dyn, addr+5, n-5);
|
||||
if(n>5 && PK(0)==0x8d && PK(1)==0xb6 && PK(2)==0x00 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00)
|
||||
return is_nops(dyn, addr+6, n-6);
|
||||
if(n>6 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x80 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00 && PK(6)==0x00)
|
||||
return is_nops(dyn, addr+7, n-7);
|
||||
if(n>6 && PK(0)==0x8d && PK(1)==0xb4 && PK(2)==0x26 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00 && PK(6)==0x00) // lea esi, [esi+0]
|
||||
return is_nops(dyn, addr+7, n-7);
|
||||
if(n>7 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x84 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00 && PK(6)==0x00 && PK(7)==0x00)
|
||||
return is_nops(dyn, addr+8, n-8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return size of next instuciton, -1 is unknown
|
||||
// not all instrction are setup
|
||||
int next_instruction(dynarec_arm_t *dyn, uintptr_t addr)
|
||||
{
|
||||
uint8_t opcode = PK(0);
|
||||
uint8_t nextop;
|
||||
switch (opcode) {
|
||||
case 0x66:
|
||||
opcode = PK(1);
|
||||
switch(opcode) {
|
||||
case 0x90:
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
case 0x81:
|
||||
nextop = PK(1);
|
||||
return fakeed(dyn, addr+2, 0, nextop)-addr + 4;
|
||||
case 0x83:
|
||||
nextop = PK(1);
|
||||
return fakeed(dyn, addr+2, 0, nextop)-addr + 1;
|
||||
case 0x84:
|
||||
case 0x85:
|
||||
case 0x88:
|
||||
case 0x89:
|
||||
case 0x8A:
|
||||
case 0x8B:
|
||||
case 0x8C:
|
||||
case 0x8D:
|
||||
case 0x8E:
|
||||
case 0x8F:
|
||||
nextop = PK(1);
|
||||
return fakeed(dyn, addr+2, 0, nextop)-addr;
|
||||
case 0x50:
|
||||
case 0x51:
|
||||
case 0x52:
|
||||
case 0x53:
|
||||
case 0x54:
|
||||
case 0x55:
|
||||
case 0x56:
|
||||
case 0x57:
|
||||
case 0x58:
|
||||
case 0x59:
|
||||
case 0x5A:
|
||||
case 0x5B:
|
||||
case 0x5C:
|
||||
case 0x5D:
|
||||
case 0x5E:
|
||||
case 0x5F:
|
||||
case 0x90:
|
||||
case 0x91:
|
||||
case 0x92:
|
||||
case 0x93:
|
||||
case 0x94:
|
||||
case 0x95:
|
||||
case 0x96:
|
||||
case 0x97:
|
||||
case 0x98:
|
||||
case 0x99:
|
||||
case 0x9B:
|
||||
case 0x9C:
|
||||
case 0x9D:
|
||||
case 0x9E:
|
||||
case 0x9F:
|
||||
return 1;
|
||||
case 0xA0:
|
||||
case 0xA1:
|
||||
case 0xA2:
|
||||
case 0xA3:
|
||||
return 5;
|
||||
case 0xB0:
|
||||
case 0xB1:
|
||||
case 0xB2:
|
||||
case 0xB3:
|
||||
case 0xB4:
|
||||
case 0xB5:
|
||||
case 0xB6:
|
||||
case 0xB7:
|
||||
return 2;
|
||||
case 0xB8:
|
||||
case 0xB9:
|
||||
case 0xBA:
|
||||
case 0xBB:
|
||||
case 0xBC:
|
||||
case 0xBD:
|
||||
case 0xBE:
|
||||
case 0xBF:
|
||||
return 5;
|
||||
case 0xFF:
|
||||
nextop = PK(1);
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: // INC Ed
|
||||
case 1: //DEC Ed
|
||||
case 2: // CALL Ed
|
||||
case 4: // JMP Ed
|
||||
case 6: // Push Ed
|
||||
return fakeed(dyn, addr+2, 0, nextop)-addr;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#undef PK
|
||||
|
||||
int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n)
|
||||
{
|
||||
int i = 0;
|
||||
while(i<n) {
|
||||
int j=next_instruction(dyn, addr+i);
|
||||
if(j<=0) return 0;
|
||||
i+=j;
|
||||
}
|
||||
return (i==n)?1:0;
|
||||
}
|
||||
|
||||
uint32_t needed_flags(dynarec_arm_t *dyn, int ninst, uint32_t setf, int recurse)
|
||||
{
|
||||
if(recurse == 10)
|
||||
return X_PEND;
|
||||
if(ninst == dyn->size)
|
||||
return X_PEND; // no more instructions, or too many jmp loop, stop
|
||||
|
||||
uint32_t needed = dyn->insts[ninst].x64.use_flags;
|
||||
if(needed) {
|
||||
setf &= ~needed;
|
||||
if(!setf) // all flags already used, no need to continue
|
||||
return needed;
|
||||
}
|
||||
|
||||
if(!needed && !dyn->insts[ninst].x64.set_flags && !dyn->insts[ninst].x64.jmp_insts) {
|
||||
int start = ninst;
|
||||
int end = ninst;
|
||||
while(end<dyn->size && !dyn->insts[end].x64.use_flags && !dyn->insts[end].x64.set_flags && !dyn->insts[end].x64.jmp_insts)
|
||||
++end;
|
||||
needed = needed_flags(dyn, end, setf, recurse);
|
||||
for(int i=start; i<end; ++i)
|
||||
dyn->insts[i].x64.need_flags = needed;
|
||||
return needed;
|
||||
}
|
||||
|
||||
if(dyn->insts[ninst].x64.set_flags && (dyn->insts[ninst].x64.state_flags!=SF_MAYSET)) {
|
||||
if((setf & ~dyn->insts[ninst].x64.set_flags) == 0)
|
||||
return needed; // all done, gives all the flags needed
|
||||
setf |= dyn->insts[ninst].x64.set_flags; // add new flags to continue
|
||||
}
|
||||
|
||||
int jinst = dyn->insts[ninst].x64.jmp_insts;
|
||||
if(dyn->insts[ninst].x64.jmp) {
|
||||
dyn->insts[ninst].x64.need_flags = (jinst==-1)?X_PEND:needed_flags(dyn, jinst, setf, recurse+1);
|
||||
if(dyn->insts[ninst].x64.use_flags) // conditionnal jump
|
||||
dyn->insts[ninst].x64.need_flags |= needed_flags(dyn, ninst+1, setf, recurse);
|
||||
} else
|
||||
dyn->insts[ninst].x64.need_flags = needed_flags(dyn, ninst+1, setf, recurse);
|
||||
if(dyn->insts[ninst].x64.state_flags==SF_MAYSET)
|
||||
needed |= dyn->insts[ninst].x64.need_flags;
|
||||
else
|
||||
needed |= (dyn->insts[ninst].x64.need_flags & ~dyn->insts[ninst].x64.set_flags);
|
||||
if(needed == (X_PEND|X_ALL))
|
||||
needed = X_ALL;
|
||||
return needed;
|
||||
}
|
||||
|
||||
instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x64_size, int arm_size)
|
||||
{
|
||||
// x64 instruction is <16 bytes
|
||||
int toadd;
|
||||
if(x64_size>arm_size)
|
||||
toadd = 1 + x64_size/15;
|
||||
else
|
||||
toadd = 1 + arm_size/15;
|
||||
if((*size)+toadd>(*cap)) {
|
||||
*cap = (*size)+toadd;
|
||||
insts = (instsize_t*)realloc(insts, (*cap)*sizeof(instsize_t));
|
||||
}
|
||||
while(toadd) {
|
||||
if(x64_size>15)
|
||||
insts[*size].x64 = 15;
|
||||
else
|
||||
insts[*size].x64 = x64_size;
|
||||
x64_size -= insts[*size].x64;
|
||||
if(arm_size>15)
|
||||
insts[*size].nat = 15;
|
||||
else
|
||||
insts[*size].nat = arm_size;
|
||||
arm_size -= insts[*size].nat;
|
||||
++(*size);
|
||||
--toadd;
|
||||
}
|
||||
return insts;
|
||||
}
|
||||
|
||||
// add a value to table64 (if needed) and gives back the imm19 to use in LDR_literal
|
||||
int Table64(dynarec_arm_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;
|
||||
// not found, add it
|
||||
if(idx==-1) {
|
||||
idx = dyn->table64size++;
|
||||
dyn->table64 = (uint64_t*)realloc(dyn->table64, dyn->table64size * sizeof(uint64_t));
|
||||
dyn->table64[idx] = val;
|
||||
}
|
||||
// calculate offset
|
||||
int delta = dyn->tablestart + idx*sizeof(uint64_t) - (uintptr_t)dyn->block;
|
||||
return delta;
|
||||
}
|
||||
|
||||
|
||||
void arm_pass0(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
void arm_pass1(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
void arm_pass2(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
void arm_pass3(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
|
||||
void* FillBlock64(dynablock_t* block, uintptr_t addr) {
|
||||
if(addr>=box64_nodynarec_start && addr<box64_nodynarec_end)
|
||||
return NULL;
|
||||
// init the helper
|
||||
dynarec_arm_t helper = {0};
|
||||
helper.start = addr;
|
||||
arm_pass0(&helper, addr);
|
||||
if(!helper.size) {
|
||||
dynarec_log(LOG_DEBUG, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
|
||||
block->done = 1;
|
||||
return (void*)block;
|
||||
}
|
||||
helper.cap = helper.size+3; // needs epilog handling
|
||||
helper.insts = (instruction_arm64_t*)calloc(helper.cap, sizeof(instruction_arm64_t));
|
||||
// pass 1, addresses, x64 jump addresses, flags
|
||||
arm_pass1(&helper, addr);
|
||||
// calculate barriers
|
||||
uintptr_t start = helper.insts[0].x64.addr;
|
||||
uintptr_t end = helper.insts[helper.size].x64.addr+helper.insts[helper.size].x64.size;
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
if(helper.insts[i].x64.jmp) {
|
||||
uintptr_t j = helper.insts[i].x64.jmp;
|
||||
if(j<start || j>=end)
|
||||
helper.insts[i].x64.jmp_insts = -1;
|
||||
else {
|
||||
// find jump address instruction
|
||||
int k=-1;
|
||||
for(int i2=0; i2<helper.size && k==-1; ++i2) {
|
||||
if(helper.insts[i2].x64.addr==j)
|
||||
k=i2;
|
||||
}
|
||||
if(k!=-1) // -1 if not found, mmm, probably wrong, exit anyway
|
||||
helper.insts[k].x64.barrier = 1;
|
||||
helper.insts[i].x64.jmp_insts = k;
|
||||
}
|
||||
}
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
if(helper.insts[i].x64.set_flags && !helper.insts[i].x64.need_flags) {
|
||||
helper.insts[i].x64.need_flags = needed_flags(&helper, i+1, helper.insts[i].x64.set_flags, 0);
|
||||
if((helper.insts[i].x64.need_flags&X_PEND) && (helper.insts[i].x64.state_flags==SF_MAYSET))
|
||||
helper.insts[i].x64.need_flags = X_ALL;
|
||||
}
|
||||
|
||||
// pass 2, instruction size
|
||||
arm_pass2(&helper, addr);
|
||||
// ok, now allocate mapped memory, with executable flag on
|
||||
int sz = helper.arm_size + helper.table64size*sizeof(uint64_t);
|
||||
void* p = (void*)AllocDynarecMap(block, sz);
|
||||
if(p==NULL) {
|
||||
dynarec_log(LOG_DEBUG, "AllocDynarecMap(%p, %d) failed, cancelling block\n", block, sz);
|
||||
free(helper.insts);
|
||||
free(helper.next);
|
||||
free(helper.table64);
|
||||
return NULL;
|
||||
}
|
||||
helper.block = p;
|
||||
helper.arm_start = (uintptr_t)p;
|
||||
helper.tablestart = helper.arm_start + helper.arm_size;
|
||||
if(helper.sons_size) {
|
||||
helper.sons_x64 = (uintptr_t*)calloc(helper.sons_size, sizeof(uintptr_t));
|
||||
helper.sons_arm = (void**)calloc(helper.sons_size, sizeof(void*));
|
||||
}
|
||||
// pass 3, emit (log emit arm opcode)
|
||||
if(box64_dynarec_dump) {
|
||||
dynarec_log(LOG_NONE, "%s%04d|Emitting %d bytes for %d x64 bytes", (box64_dynarec_dump>1)?"\e[01;36m":"", GetTID(), helper.arm_size, helper.isize);
|
||||
printFunctionAddr(helper.start, " => ");
|
||||
dynarec_log(LOG_NONE, "%s\n", (box64_dynarec_dump>1)?"\e[m":"");
|
||||
}
|
||||
helper.arm_size = 0;
|
||||
int oldtable64size = helper.table64size;
|
||||
arm_pass3(&helper, addr);
|
||||
if(sz!=(helper.arm_size + helper.table64size*8)) {
|
||||
printf_log(LOG_NONE, "BOX64: Warning, size difference in block between pass2 (%d) & pass3 (%d)!\n", sz, helper.arm_size+helper.table64size*8);
|
||||
uint8_t *dump = (uint8_t*)helper.start;
|
||||
printf_log(LOG_NONE, "Dump of %d x64 opcodes:\n", helper.size);
|
||||
for(int i=0; i<helper.size; ++i) {
|
||||
printf_log(LOG_NONE, "%p:", dump);
|
||||
for(; dump<(uint8_t*)helper.insts[i+1].x64.addr; ++dump)
|
||||
printf_log(LOG_NONE, " %02X", *dump);
|
||||
printf_log(LOG_NONE, "\t%d -> %d\n", helper.insts[i].size2, helper.insts[i].size);
|
||||
}
|
||||
printf_log(LOG_NONE, "Table64 \t%d -> %d\n", oldtable64size*8, helper.table64size*8);
|
||||
printf_log(LOG_NONE, " ------------\n");
|
||||
}
|
||||
// add table64 if needed
|
||||
if(helper.table64size) {
|
||||
memcpy(p+helper.arm_size, helper.table64, helper.table64size*8);
|
||||
}
|
||||
// all done...
|
||||
__clear_cache(p, p+sz); // need to clear the cache before execution...
|
||||
// keep size of instructions for signal handling
|
||||
{
|
||||
size_t cap = 1;
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
cap += 1 + ((helper.insts[i].x64.size>helper.insts[i].size)?helper.insts[i].x64.size:helper.insts[i].size)/15;
|
||||
size_t size = 0;
|
||||
block->instsize = (instsize_t*)calloc(cap, sizeof(instsize_t));
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
block->instsize = addInst(block->instsize, &size, &cap, helper.insts[i].x64.size, helper.insts[i].size/4);
|
||||
block->instsize = addInst(block->instsize, &size, &cap, 0, 0); // add a "end of block" mark, just in case
|
||||
}
|
||||
// ok, free the helper now
|
||||
free(helper.insts);
|
||||
free(helper.next);
|
||||
free(helper.table64);
|
||||
block->size = sz;
|
||||
block->isize = helper.size;
|
||||
block->block = p;
|
||||
block->need_test = 0;
|
||||
//block->x64_addr = (void*)start;
|
||||
block->x64_size = end-start;
|
||||
if(box64_dynarec_largest<block->x64_size)
|
||||
box64_dynarec_largest = block->x64_size;
|
||||
block->hash = X31_hash_code(block->x64_addr, block->x64_size);
|
||||
// fill sons if any
|
||||
dynablock_t** sons = NULL;
|
||||
int sons_size = 0;
|
||||
if(helper.sons_size) {
|
||||
sons = (dynablock_t**)calloc(helper.sons_size, sizeof(dynablock_t*));
|
||||
for (int i=0; i<helper.sons_size; ++i) {
|
||||
int created = 1;
|
||||
dynablock_t *son = AddNewDynablock(block->parent, helper.sons_x64[i], &created);
|
||||
if(created) { // avoid breaking a working block!
|
||||
son->block = helper.sons_arm[i];
|
||||
son->x64_addr = (void*)helper.sons_x64[i];
|
||||
son->x64_size = end-helper.sons_x64[i];
|
||||
if(!son->x64_size) {printf_log(LOG_NONE, "Warning, son with null x64 size! (@%p / ARM=%p)", son->x64_addr, son->block);}
|
||||
son->father = block;
|
||||
son->done = 1;
|
||||
sons[sons_size++] = son;
|
||||
if(!son->parent)
|
||||
son->parent = block->parent;
|
||||
}
|
||||
}
|
||||
if(sons_size) {
|
||||
block->sons = sons;
|
||||
block->sons_size = sons_size;
|
||||
} else
|
||||
free(sons);
|
||||
}
|
||||
free(helper.sons_x64);
|
||||
free(helper.sons_arm);
|
||||
block->done = 1;
|
||||
return (void*)block;
|
||||
}
|
||||
Executable
+2105
File diff suppressed because it is too large.
Load diff
Executable
+862
@@ -0,0 +1,862 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
#define GETG \
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3) \
|
||||
|
||||
#define GETGX(a) \
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd)
|
||||
|
||||
#define GETGX_empty(a) \
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg_empty(dyn, ninst, x1, gd)
|
||||
|
||||
#define GETEX(a, D) \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3)); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0); \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
VLDR128_U12(a, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
#define GETGM(a) \
|
||||
gd = ((nextop&0x38)>>3); \
|
||||
a = mmx_get_reg(dyn, ninst, x1, gd)
|
||||
#define GETEM(a, D) \
|
||||
if(MODREG) { \
|
||||
a = mmx_get_reg(dyn, ninst, x1, (nextop&7)); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0); \
|
||||
a = fpu_get_scratch_double(dyn); \
|
||||
VLD1_64(a, ed); \
|
||||
}
|
||||
#define PUTEM(a) \
|
||||
if(!MODREG) { \
|
||||
VST1_64(a, ed); \
|
||||
}
|
||||
|
||||
uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
int32_t i32, i32_, j32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb2;
|
||||
uint8_t eb1, eb2;
|
||||
int v0, v1;
|
||||
int q0, q1;
|
||||
int d0;
|
||||
int s0;
|
||||
int fixedaddress;
|
||||
MAYUSE(s0);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(v0);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(j32);
|
||||
MAYUSE(i32);
|
||||
MAYUSE(u8);
|
||||
#if STEP == 3
|
||||
//static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
|
||||
#endif
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
|
||||
|
||||
case 0x10:
|
||||
INST_NAME("MOVUPS Gx,Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, ed);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress); // no alignment issue with ARMv8 NEON :)
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("MOVUPS Ex,Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
INST_NAME("MOVHLPS Gx,Ex");
|
||||
GETGX(v0);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
VMOVeD(v0, 0, v1, 1);
|
||||
} else {
|
||||
INST_NAME("MOVLPS Gx,Ex");
|
||||
GETGX(v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
VLD1_64(v0, 0, ed);
|
||||
}
|
||||
break;
|
||||
case 0x13:
|
||||
nextop = F8;
|
||||
INST_NAME("MOVLPS Ex,Gx");
|
||||
GETGX(v0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
VMOVeD(v1, 0, v0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
VST1_64(v0, 0, ed); // better to use VST1 than VSTR_64, to avoid NEON->VFPU transfert I assume
|
||||
}
|
||||
break;
|
||||
case 0x14:
|
||||
INST_NAME("UNPCKLPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0);
|
||||
VZIP1Q_32(v0, v0, q0);
|
||||
break;
|
||||
case 0x15:
|
||||
INST_NAME("UNPCKHPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0);
|
||||
VZIP2Q_32(v0, v0, q0);
|
||||
break;
|
||||
case 0x16:
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
INST_NAME("MOVLHPS Gx,Ex");
|
||||
GETGX(v0);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
VMOVeD(v0, 1, v1, 0);
|
||||
} else {
|
||||
INST_NAME("MOVHPS Gx,Ex");
|
||||
GETGX(v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
VLD1_64(v0, 1, ed);
|
||||
}
|
||||
break;
|
||||
case 0x17:
|
||||
nextop = F8;
|
||||
INST_NAME("MOVHPS Ex,Gx");
|
||||
GETGX(v0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
VMOVeD(v1, 0, v0, 1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
VST1_64(v0, 1, ed);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1F:
|
||||
INST_NAME("NOP (multibyte)");
|
||||
nextop = F8;
|
||||
FAKEED;
|
||||
break;
|
||||
|
||||
case 0x28:
|
||||
INST_NAME("MOVAPS Gx,Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, ed);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x29:
|
||||
INST_NAME("MOVAPS Ex,Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x2E:
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
if(opcode==0x2F) {INST_NAME("COMISS Gx, Ex");} else {INST_NAME("UCOMISS Gx, Ex");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
if(MODREG) {
|
||||
s0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
} else {
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(s0, ed, fixedaddress);
|
||||
}
|
||||
FCMPS(v0, s0);
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
READFLAGS(F); \
|
||||
GETFLAGS; \
|
||||
nextop=F8; \
|
||||
GETGD; \
|
||||
if(MODREG) { \
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
CSELxw(gd, ed, gd, YES); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, 0); \
|
||||
Bcond(NO, +8); \
|
||||
LDRxw_U12(gd, ed, fixedaddress); \
|
||||
if(!rex.w) {MOVw_REG(gd, gd);} \
|
||||
}
|
||||
|
||||
GOCOND(0x40, "CMOV", "Gd, Ed");
|
||||
#undef GO
|
||||
|
||||
case 0x54:
|
||||
INST_NAME("ANDPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0);
|
||||
VANDQ(v0, v0, q0);
|
||||
break;
|
||||
case 0x55:
|
||||
INST_NAME("ANDNPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0);
|
||||
VBICQ(v0, q0, v0);
|
||||
break;
|
||||
case 0x56:
|
||||
INST_NAME("ORPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0);
|
||||
VORRQ(v0, v0, q0);
|
||||
break;
|
||||
case 0x57:
|
||||
INST_NAME("XORPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0);
|
||||
VEORQ(v0, v0, q0);
|
||||
break;
|
||||
case 0x58:
|
||||
INST_NAME("ADDPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0);
|
||||
VFADDQS(v0, v0, q0);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0);
|
||||
VFMULQS(v0, v0, q0);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTPS2PD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(q1);
|
||||
FCVTL(q1, q0);
|
||||
break;
|
||||
case 0x5B:
|
||||
INST_NAME("CVTDQ2PS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX_empty(q1);
|
||||
SCVTQFS(q1, q0);
|
||||
break;
|
||||
case 0x5C:
|
||||
INST_NAME("SUBPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0);
|
||||
VFSUBQS(v0, v0, q0);
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
READFLAGS(F); \
|
||||
i32_ = F32S; \
|
||||
BARRIER(2); \
|
||||
JUMP(addr+i32_);\
|
||||
GETFLAGS; \
|
||||
if(dyn->insts) { \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst+1].address-(dyn->arm_size); \
|
||||
Bcond(NO, i32); \
|
||||
jump_to_next(dyn, addr+i32_, 0, ninst); \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->arm_size); \
|
||||
Bcond(YES, i32); \
|
||||
} \
|
||||
}
|
||||
|
||||
GOCOND(0x80, "J", "Id");
|
||||
#undef GO
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
READFLAGS(F); \
|
||||
GETFLAGS; \
|
||||
nextop=F8; \
|
||||
CSETw(x3, YES); \
|
||||
if(MODREG) { \
|
||||
if(rex.rex) { \
|
||||
eb1= xRAX+(nextop&7)+(rex.b<<3); \
|
||||
eb2 = 0; \
|
||||
} else { \
|
||||
ed = (nextop&7); \
|
||||
eb2 = (ed>>2)*8; \
|
||||
eb1 = xRAX+(ed&3); \
|
||||
} \
|
||||
BFIx(eb1, x3, eb2, 8); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff, 0, rex, 0, 0); \
|
||||
STRB_U12(x3, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
GOCOND(0x90, "SET", "Eb");
|
||||
#undef GO
|
||||
|
||||
case 0xA2:
|
||||
INST_NAME("CPUID");
|
||||
MOVx_REG(x1, xRAX);
|
||||
CALL_(my_cpuid, -1, 0);
|
||||
break;
|
||||
case 0xA3:
|
||||
INST_NAME("BT Ed, Gd");
|
||||
SETFLAGS(X_CF, SF_SET);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, 0);
|
||||
UBFXw(x1, gd, 5+rex.w, 3-rex.w); // r1 = (gd>>5);
|
||||
ADDx_REG_LSL(x3, wback, x1, 2); //(&ed)+=r1*4;
|
||||
LDRxw_U12(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
wback = x3;
|
||||
}
|
||||
if(rex.w) {
|
||||
ANDx_mask(x2, gd, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
ANDw_mask(x2, gd, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
LSRxw_REG(x4, ed, x2);
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
break;
|
||||
|
||||
case 0xA5:
|
||||
nextop = F8;
|
||||
INST_NAME("SHLD Ed, Gd, CL");
|
||||
UXTBw(x3, xRCX);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEDW(x4, x1, 0);
|
||||
GETGD;
|
||||
MOVxw_REG(x2, gd);
|
||||
CALL_(rex.w?((void*)shld64):((void*)shld32), ed, x4);
|
||||
WBACK;
|
||||
break;
|
||||
|
||||
case 0xAB:
|
||||
INST_NAME("BTS Ed, Gd");
|
||||
SETFLAGS(X_CF, SF_SET);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, 0);
|
||||
UBFXw(x1, gd, 5+rex.w, 3-rex.w); // r1 = (gd>>5);
|
||||
ADDx_REG_LSL(x3, wback, x1, 2); //(&ed)+=r1*4;
|
||||
LDRxw_U12(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
wback = x3;
|
||||
}
|
||||
if(rex.w) {
|
||||
ANDx_mask(x2, gd, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
ANDw_mask(x2, gd, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
LSRxw_REG(x4, ed, x2);
|
||||
if(rex.w) {
|
||||
ANDSx_mask(x4, x4, 1, 0, 0); //mask=1
|
||||
} else {
|
||||
ANDSw_mask(x4, x4, 0, 0); //mask=1
|
||||
}
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
MOV32w(x4, 1);
|
||||
LSLxw_REG(x4, x4, x2);
|
||||
EORxw_REG(x4, ed, x4);
|
||||
CSELxw(ed, ed, x4, cNE);
|
||||
if(wback) {
|
||||
STRxw_U12(ed, wback, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xAD:
|
||||
nextop = F8;
|
||||
INST_NAME("SHRD Ed, Gd, CL");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
UXTBw(x3, xRCX);
|
||||
GETEDW(x4, x1, 0);
|
||||
GETGD;
|
||||
MOVxw_REG(x2, gd);
|
||||
CALL_(rex.w?((void*)shrd64):((void*)shrd32), ed, x4);
|
||||
WBACK;
|
||||
break;
|
||||
|
||||
case 0xAE:
|
||||
nextop = F8;
|
||||
if((nextop&0xF8)==0xE8) {
|
||||
INST_NAME("LFENCE");
|
||||
} else
|
||||
if((nextop&0xF8)==0xF0) {
|
||||
INST_NAME("MFENCE");
|
||||
} else
|
||||
if((nextop&0xF8)==0xF8) {
|
||||
INST_NAME("SFENCE");
|
||||
} else {
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FXSAVE Ed");
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3);
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(rex.w?((void*)fpu_fxsave64):((void*)fpu_fxsave32), -1);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FXRSTOR Ed");
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3);
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(rex.w?((void*)fpu_fxrstor64):((void*)fpu_fxrstor32), -1);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("LDMXCSR Md");
|
||||
GETED(0);
|
||||
STRw_U12(ed, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("STMXCSR Md");
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
LDRw_U12(ed, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
LDRw_U12(x4, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
STRw_U12(x4, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xAF:
|
||||
INST_NAME("IMUL Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
if(rex.w) {
|
||||
// 64bits imul
|
||||
UFLAG_IF {
|
||||
SMULH(x3, gd, ed);
|
||||
MULx(gd, gd, ed);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_RES(gd);
|
||||
UFLAG_DF(x3, d_imul64);
|
||||
} else {
|
||||
MULxw(gd, gd, ed);
|
||||
}
|
||||
} else {
|
||||
// 32bits imul
|
||||
UFLAG_IF {
|
||||
SMULL(gd, gd, ed);
|
||||
UFLAG_RES(gd);
|
||||
LSRx(x3, gd, 32);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_DF(x3, d_imul32);
|
||||
MOVw_REG(gd, gd);
|
||||
} else {
|
||||
MULxw(gd, gd, ed);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xB3:
|
||||
INST_NAME("BTR Ed, Gd");
|
||||
SETFLAGS(X_CF, SF_SET);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, 0);
|
||||
UBFXw(x1, gd, 5+rex.w, 3-rex.w); // r1 = (gd>>5);
|
||||
ADDx_REG_LSL(x3, wback, x1, 2); //(&ed)+=r1*4;
|
||||
LDRxw_U12(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
wback = x3;
|
||||
}
|
||||
if(rex.w) {
|
||||
ANDx_mask(x2, gd, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
ANDw_mask(x2, gd, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
LSRxw_REG(x4, ed, x2);
|
||||
if(rex.w) {
|
||||
ANDSx_mask(x4, x4, 1, 0, 0); //mask=1
|
||||
} else {
|
||||
ANDSw_mask(x4, x4, 0, 0); //mask=1
|
||||
}
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
MOV32w(x4, 1);
|
||||
LSLxw_REG(x4, x4, x2);
|
||||
EORxw_REG(x4, ed, x4);
|
||||
CSELxw(ed, ed, x4, cEQ);
|
||||
if(wback) {
|
||||
STRxw_U12(ed, wback, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xB6:
|
||||
INST_NAME("MOVZX Gd, Eb");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
if(rex.rex) {
|
||||
eb1 = xRAX+(nextop&7)+(rex.b<<3);
|
||||
eb2 = 0; \
|
||||
} else {
|
||||
ed = (nextop&7);
|
||||
eb1 = xRAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
}
|
||||
UBFXxw(gd, eb1, eb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff, 0, rex, 0, 0);
|
||||
LDRB_U12(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0xB7:
|
||||
INST_NAME("MOVZX Gd, Ew");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
UBFXxw(gd, ed, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
LDRH_U12(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xBA:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 4:
|
||||
INST_NAME("BT Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
gd = x2;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
u8 = F8;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xff0<<2, 3, rex, 0, 0);
|
||||
u8 = F8;
|
||||
fixedaddress+=(u8>>(rex.w?6:5))*(rex.w?8:4);
|
||||
LDRxw_U12(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
u8&=rex.w?0x3f:0x1f;
|
||||
if(u8) {
|
||||
LSRxw(x1, ed, u8);
|
||||
ed = x1;
|
||||
}
|
||||
BFIw(xFlags, ed, F_CF, 1);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("BTS Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
u8 = F8;
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xff0<<2, 3, rex, 0, 0);
|
||||
u8 = F8;
|
||||
fixedaddress+=(u8>>(rex.w?6:5))*(rex.w?8:4);
|
||||
LDRxw_U12(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
LSRxw(x4, ed, u8&(rex.w?0x3f:0x1f));
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
TBNZ_MARK3(x4, 0); // bit already set, jump to next instruction
|
||||
MOV32w(x4, 1);
|
||||
EORxw_REG_LSL(ed, ed, x4, u8&(rex.w?0x3f:0x1f));
|
||||
if(wback) {
|
||||
STRxw_U12(ed, wback, fixedaddress);
|
||||
}
|
||||
MARK3;
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("BTR Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
u8 = F8;
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xff0<<2, 3, rex, 0, 0);
|
||||
u8 = F8;
|
||||
fixedaddress+=(u8>>(rex.w?6:5))*(rex.w?8:4);
|
||||
LDRxw_U12(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
LSRxw(x4, ed, u8&(rex.w?0x3f:0x1f));
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
TBZ_MARK3(x4, 0); // bit already clear, jump to next instruction
|
||||
//MOVW(x14, 1); // already 0x01
|
||||
EORxw_REG_LSL(ed, ed, x4, u8&(rex.w?0x3f:0x1f));
|
||||
if(wback) {
|
||||
STRxw_U12(ed, wback, fixedaddress);
|
||||
}
|
||||
MARK3;
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("BTC Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
u8 = F8;
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xff0<<2, 3, rex, 0, 0);
|
||||
u8 = F8;
|
||||
fixedaddress+=(u8>>(rex.w?6:5))*(rex.w?8:4);
|
||||
LDRxw_U12(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
LSRxw(x4, ed, u8&(rex.w?0x3f:0x1f));
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
MOV32w(x4, 1);
|
||||
EORxw_REG_LSL(ed, ed, x4, u8&(rex.w?0x3f:0x1f));
|
||||
if(wback) {
|
||||
STRxw_U12(ed, wback, fixedaddress);
|
||||
}
|
||||
MARK3;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xBB:
|
||||
INST_NAME("BTC Ed, Gd");
|
||||
SETFLAGS(X_CF, SF_SET);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, 0);
|
||||
UBFXw(x1, gd, 5+rex.w, 3-rex.w); // r1 = (gd>>5);
|
||||
ADDx_REG_LSL(x3, wback, x1, 2); //(&ed)+=r1*4;
|
||||
LDRxw_U12(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
wback = x3;
|
||||
}
|
||||
if(rex.w) {
|
||||
ANDx_mask(x2, gd, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
ANDw_mask(x2, gd, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
LSRxw_REG(x4, ed, x2);
|
||||
if(rex.w) {
|
||||
ANDx_mask(x4, x4, 1, 0, 0); //mask=1
|
||||
} else {
|
||||
ANDw_mask(x4, x4, 0, 0); //mask=1
|
||||
}
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
MOV32w(x4, 1);
|
||||
LSLxw_REG(x4, x4, x2);
|
||||
EORxw_REG(ed, ed, x4);
|
||||
if(wback) {
|
||||
STRxw_U12(ed, wback, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0xBC:
|
||||
INST_NAME("BSF Gd, Ed");
|
||||
SETFLAGS(X_ZF, SF_SET);
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
TSTxw_REG(ed, ed);
|
||||
B_MARK(cEQ);
|
||||
RBITxw(x1, ed); // reverse
|
||||
CLZxw(gd, x1); // x2 gets leading 0 == BSF
|
||||
MARK;
|
||||
CSETw(x1, cEQ); //ZF not set
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
SET_DFNONE(x1);
|
||||
break;
|
||||
case 0xBD:
|
||||
INST_NAME("BSR Gd, Ed");
|
||||
SETFLAGS(X_ZF, SF_SET);
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
TSTxw_REG(ed, ed);
|
||||
B_MARK(cEQ);
|
||||
CLZxw(gd, ed); // x2 gets leading 0
|
||||
SUBxw_U12(gd, gd, rex.w?63:31);
|
||||
NEGxw_REG(gd, gd); // complement
|
||||
MARK;
|
||||
CSETw(x1, cEQ); //ZF not set
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
SET_DFNONE(x1);
|
||||
break;
|
||||
case 0xBE:
|
||||
INST_NAME("MOVSX Gd, Eb");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
if(rex.rex) {
|
||||
wback = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wb2 = 0;
|
||||
} else {
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2)*8;
|
||||
wback = xRAX+(wback&3);
|
||||
}
|
||||
SBFXxw(gd, wback, wb2, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 0xfff, 0, rex, 0, 0);
|
||||
LDRSBxw_U12(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0xBF:
|
||||
INST_NAME("MOVSX Gd, Ew");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
SXTHxw(gd, ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
LDRSHxw_U12(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC6:
|
||||
INST_NAME("SHUFPS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
if(!MODREG)
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 1);
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
// first two elements from Gx
|
||||
for(int i=0; i<2; ++i) {
|
||||
VMOVeS(d0, i, v0, (u8>>(i*2)&3));
|
||||
}
|
||||
// second two from Ex
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
for(int i=2; i<4; ++i) {
|
||||
VMOVeS(d0, i, v1, (u8>>(i*2)&3));
|
||||
}
|
||||
} else {
|
||||
for(int i=2; i<4; ++i) {
|
||||
ADDx_U12(x2, ed, (u8>>(i*2)&3)*4);
|
||||
VLD1_32(d0, i, x2);
|
||||
}
|
||||
}
|
||||
VMOVQ(v0, d0);
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF: /* BSWAP reg */
|
||||
INST_NAME("BSWAP Reg");
|
||||
gd = xRAX+(opcode&7)+(rex.b<<3);
|
||||
REVxw(gd, gd);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
int32_t j32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback;
|
||||
int64_t i64;
|
||||
int fixedaddress;
|
||||
MAYUSE(j32);
|
||||
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
// REX prefix before the F0 are ignored
|
||||
rex.rex = 0;
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gd, FS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_segdata(dyn, addr, ninst, x4, _FS);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x4, 0);
|
||||
emit_xor32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x6, _FS);
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //ADD
|
||||
if(opcode==0x81) {INST_NAME("ADD Ed, Id");} else {INST_NAME("ADD Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEDO(x6, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_add32c(dyn, ninst, rex, ed, i64, x3, x4, x5);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 1: //OR
|
||||
if(opcode==0x81) {INST_NAME("OR Ed, Id");} else {INST_NAME("OR Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEDO(x6, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_or32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 2: //ADC
|
||||
if(opcode==0x81) {INST_NAME("ADC Ed, Id");} else {INST_NAME("ADC Ed, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEDO(x6, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
emit_adc32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 3: //SBB
|
||||
if(opcode==0x81) {INST_NAME("SBB Ed, Id");} else {INST_NAME("SBB Ed, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEDO(x6, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
emit_sbb32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 4: //AND
|
||||
if(opcode==0x81) {INST_NAME("AND Ed, Id");} else {INST_NAME("AND Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEDO(x6, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_and32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 5: //SUB
|
||||
if(opcode==0x81) {INST_NAME("SUB Ed, Id");} else {INST_NAME("SUB Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEDO(x6, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_sub32c(dyn, ninst, rex, ed, i64, x3, x4, x5);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 6: //XOR
|
||||
if(opcode==0x81) {INST_NAME("XOR Ed, Id");} else {INST_NAME("XOR Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEDO(x6, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
emit_xor32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 7: //CMP
|
||||
if(opcode==0x81) {INST_NAME("CMP Ed, Id");} else {INST_NAME("CMP Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEDO(x6, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
if(i64) {
|
||||
MOV64xw(x2, i64);
|
||||
emit_cmp32(dyn, ninst, rex, ed, x2, x3, x4, x5);
|
||||
} else
|
||||
emit_cmp32_0(dyn, ninst, rex, ed, x3, x4);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x89:
|
||||
INST_NAME("MOV FS:Ed, Gd");
|
||||
grab_segdata(dyn, addr, ninst, x4, _FS);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVxw_REG(xRAX+(nextop&7)+(rex.b<<3), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
STRxw_REG(gd, ed, x4);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, FS:Ed");
|
||||
grab_segdata(dyn, addr, ninst, x4, _FS);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVxw_REG(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
LDRxw_REG(gd, ed, x4);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC7:
|
||||
INST_NAME("MOV FS:Ed, Id");
|
||||
grab_segdata(dyn, addr, ninst, x4, _FS);
|
||||
nextop=F8;
|
||||
if(MODREG) { // reg <= i32
|
||||
i64 = F32S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV64xw(ed, i64);
|
||||
} else { // mem <= i32
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 4);
|
||||
i64 = F32S;
|
||||
MOV64xw(x3, i64);
|
||||
STRxw_REG(x3, ed, x4);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
Executable
+783
@@ -0,0 +1,783 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
int32_t i32, j32;
|
||||
int16_t i16;
|
||||
uint16_t u16;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1;
|
||||
int fixedaddress;
|
||||
MAYUSE(u16);
|
||||
MAYUSE(u8);
|
||||
MAYUSE(j32);
|
||||
|
||||
while((opcode==0x2E) || (opcode==0x66)) // ignoring CS: or multiple 0x66
|
||||
opcode = F8;
|
||||
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
// REX prefix before the F0 are ignored
|
||||
rex.rex = 0;
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
case 0x01:
|
||||
INST_NAME("ADD Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_add16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_add16(dyn, ninst, x1, x2, x3, x4);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x05:
|
||||
INST_NAME("ADD AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
i32 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_add16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x09:
|
||||
INST_NAME("OR Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_or16(dyn, ninst, x1, x2, x4, x2);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x0B:
|
||||
INST_NAME("OR Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_or16(dyn, ninst, x1, x2, x4, x3);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x0D:
|
||||
INST_NAME("OR AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
i32 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_or16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x0F:
|
||||
addr = dynarec64_660F(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("ADC Ew, Gw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_adc16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x13:
|
||||
INST_NAME("ADC Gw, Ew");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_adc16(dyn, ninst, x1, x2, x4, x3);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x15:
|
||||
INST_NAME("ADC AX, Iw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
i32 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_adc16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x19:
|
||||
INST_NAME("SBB Ew, Gw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_sbb16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x1B:
|
||||
INST_NAME("SBB Gw, Ew");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_sbb16(dyn, ninst, x1, x2, x4, x3);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x1D:
|
||||
INST_NAME("SBB AX, Iw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
i16 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i16);
|
||||
emit_sbb16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x21:
|
||||
INST_NAME("AND Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_and16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x23:
|
||||
INST_NAME("AND Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_and16(dyn, ninst, x1, x2, x3, x4);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x25:
|
||||
INST_NAME("AND AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
i32 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_and16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x29:
|
||||
INST_NAME("SUB Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_sub16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x2B:
|
||||
INST_NAME("SUB Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_sub16(dyn, ninst, x1, x2, x3, x4);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("SUB AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
i32 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_sub16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x31:
|
||||
INST_NAME("XOR Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_xor16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_xor16(dyn, ninst, x1, x2, x3, x4);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x35:
|
||||
INST_NAME("XOR AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
i32 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_xor16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0x39:
|
||||
INST_NAME("CMP Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
case 0x3B:
|
||||
INST_NAME("CMP Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
case 0x3D:
|
||||
INST_NAME("CMP AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
i32 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
if(i32) {
|
||||
MOV32w(x2, i32);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
} else {
|
||||
emit_cmp16_0(dyn, ninst, x1, x3, x4);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x69:
|
||||
INST_NAME("IMUL Gw,Ew,Iw");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
GETSEW(x1, 2);
|
||||
i32 = F16S;
|
||||
MOV32w(x2, i32);
|
||||
MULw(x2, x2, x1);
|
||||
UFLAG_RES(x2);
|
||||
gd=x2;
|
||||
GWBACK;
|
||||
break;
|
||||
|
||||
case 0x6B:
|
||||
INST_NAME("IMUL Gw,Ew,Ib");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
GETSEW(x1, 1);
|
||||
i32 = F8S;
|
||||
MOV32w(x2, i32);
|
||||
MULw(x2, x2, x1);
|
||||
UFLAG_RES(x2);
|
||||
gd=x2;
|
||||
GWBACK;
|
||||
break;
|
||||
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //ADD
|
||||
if(opcode==0x81) {
|
||||
INST_NAME("ADD Ew, Iw");
|
||||
} else {
|
||||
INST_NAME("ADD Ew, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1, (opcode==81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
emit_add16(dyn, ninst, ed, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1: //OR
|
||||
if(opcode==0x81) {INST_NAME("OR Ew, Iw");} else {INST_NAME("OR Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1, (opcode==81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
emit_or16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2: //ADC
|
||||
if(opcode==0x81) {INST_NAME("ADC Ew, Iw");} else {INST_NAME("ADC Ew, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1, (opcode==81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
emit_adc16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 3: //SBB
|
||||
if(opcode==0x81) {INST_NAME("SBB Ew, Iw");} else {INST_NAME("SBB Ew, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1, (opcode==81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
emit_sbb16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4: //AND
|
||||
if(opcode==0x81) {INST_NAME("AND Ew, Iw");} else {INST_NAME("AND Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1, (opcode==81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
emit_and16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 5: //SUB
|
||||
if(opcode==0x81) {INST_NAME("SUB Ew, Iw");} else {INST_NAME("SUB Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1, (opcode==81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
emit_sub16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 6: //XOR
|
||||
if(opcode==0x81) {INST_NAME("XOR Ew, Iw");} else {INST_NAME("XOR Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1, (opcode==81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
emit_xor16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 7: //CMP
|
||||
if(opcode==0x81) {INST_NAME("CMP Ew, Iw");} else {INST_NAME("CMP Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1, (opcode==81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
if(i16) {
|
||||
MOV32w(x2, i16);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
} else
|
||||
emit_cmp16_0(dyn, ninst, x1, x3, x4);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x85:
|
||||
INST_NAME("TEST Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
|
||||
case 0x89:
|
||||
INST_NAME("MOV Ew, Gw");
|
||||
nextop = F8;
|
||||
GETGD; // don't need GETGW here
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
if(ed!=gd) {
|
||||
BFIx(ed, gd, 0, 16);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
STRH_U12(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gw, Ew");
|
||||
nextop = F8;
|
||||
GETGD; // don't need GETGW neither
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
if(ed!=gd) {
|
||||
BFIx(gd, ed, 0, 16);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
|
||||
LDRH_U12(x1, ed, fixedaddress);
|
||||
BFIx(gd, x1, 0, 16);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x90:
|
||||
INST_NAME("NOP");
|
||||
break;
|
||||
|
||||
case 0xA5:
|
||||
if(rep) {
|
||||
INST_NAME("REP MOVSW");
|
||||
CBZx_NEXT(xRCX);
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
LDRH_S9_postindex(x1, xRSI, 2);
|
||||
STRH_S9_postindex(x1, xRDI, 2);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK(xRCX);
|
||||
B_NEXT_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
LDRH_S9_postindex(x1, xRSI, -2);
|
||||
STRH_S9_postindex(x1, xRDI, -2);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK2(xRCX);
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("MOVSW");
|
||||
GETDIR(x3, 2);
|
||||
LDRH_U12(x1, xRSI, 0);
|
||||
STRH_U12(x1, xRDI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x3);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA9:
|
||||
INST_NAME("TEST AX,Iw");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
u16 = F16;
|
||||
MOV32w(x2, u16);
|
||||
UBFXx(x1, xRAX, 0, 16);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
|
||||
case 0xB8:
|
||||
case 0xB9:
|
||||
case 0xBA:
|
||||
case 0xBB:
|
||||
case 0xBC:
|
||||
case 0xBD:
|
||||
case 0xBE:
|
||||
case 0xBF:
|
||||
INST_NAME("MOV Reg16, Iw");
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
gd = xRAX+(opcode&7)+(rex.b<<3);
|
||||
BFIx(gd, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0xC1:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ew, Ib");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(rol16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ew, Ib");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(ror16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ew, Ib");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(rcl16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ew, Ib");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(rcr16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
INST_NAME("SHL Ew, Ib");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, (u8&0x1f));
|
||||
UFLAG_OP12(ed, x2)
|
||||
LSLw_REG(ed, ed, x2);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shl16);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("SHR Ed, Ib");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, (u8&0x1f));
|
||||
UFLAG_OP12(ed, x2)
|
||||
LSRw_REG(ed, ed, x2);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shr16);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("SAR Ed, Ib");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETSEW(x1, 0);
|
||||
u8 = F8;
|
||||
MOV32w(x2, (u8&0x1f));
|
||||
UFLAG_OP12(ed, x2)
|
||||
ASRw_REG(ed, ed, x2);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_sar16);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC7:
|
||||
INST_NAME("MOV Ew, Iw");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
BFIx(ed, x1, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 2);
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
STRH_U12(x1, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD1:
|
||||
case 0xD3:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("ROL Ew, 1");
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("ROL Ew, CL");
|
||||
ANDSw_mask(x2, xRCX, 0, 0b00100);
|
||||
}
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1, 0);
|
||||
CALL_(rol16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("ROR Ew, 1");
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("ROR Ew, CL");
|
||||
ANDSw_mask(x2, xRCX, 0, 0b00100);
|
||||
}
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1, 0);
|
||||
CALL_(ror16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2:
|
||||
if(opcode==0xD1) {INST_NAME("RCL Ew, 1"); } else { INST_NAME("RCL Ew, CL");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
if(opcode==0xD1) {MOV32w(x2, 1);} else {ANDSw_mask(x2, xRCX, 0, 0b00100);}
|
||||
GETEW(x1, 0);
|
||||
CALL_(rcl16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 3:
|
||||
if(opcode==0xD1) {INST_NAME("RCR Ew, 1");} else {INST_NAME("RCR Ew, CL");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
if(opcode==0xD1) {MOV32w(x2, 1);} else {ANDSw_mask(x2, xRCX, 0, 0b00100);}
|
||||
GETEW(x1, 0);
|
||||
CALL_(rcr16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SHL Ew, 1");
|
||||
MOV32w(x4, 1);
|
||||
} else {
|
||||
INST_NAME("SHL Ew, CL");
|
||||
ANDSw_mask(x4, xRCX, 0, 0b00100);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1, 0);
|
||||
UFLAG_OP12(ed, x4)
|
||||
LSLw_REG(ed, ed, x4);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shl16);
|
||||
break;
|
||||
case 5:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SHR Ew, 1");
|
||||
MOV32w(x4, 1);
|
||||
} else {
|
||||
INST_NAME("SHR Ew, CL");
|
||||
ANDSw_mask(x4, xRCX, 0, 0b00100);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1, 0);
|
||||
UFLAG_OP12(ed, x4)
|
||||
LSRw_REG(ed, ed, x4);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shr16);
|
||||
break;
|
||||
case 7:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SAR Ew, 1");
|
||||
MOV32w(x4, 1);
|
||||
} else {
|
||||
INST_NAME("SAR Ew, CL");
|
||||
ANDSw_mask(x4, xRCX, 0, 0b00100);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETSEW(x1, 0);
|
||||
UFLAG_OP12(ed, x4)
|
||||
ASRw_REG(ed, ed, x4);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_sar16);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF7:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
case 1:
|
||||
INST_NAME("TEST Ew, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1, 2);
|
||||
u16 = F16;
|
||||
MOV32w(x2, u16);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("NOT Ew");
|
||||
GETEW(x1, 0);
|
||||
MVNw_REG(ed, ed);
|
||||
EWBACK;
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("NEG Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1, 0);
|
||||
emit_neg16(dyn, ninst, ed, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("MUL AX, Ew");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_DF(x1, d_mul16);
|
||||
GETEW(x1, 0);
|
||||
UXTHw(x2, xRAX);
|
||||
MULw(x1, x2, x1);
|
||||
UFLAG_RES(x1);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
BFXILx(xRDX, x1, 16, 16);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("IMUL AX, Ew");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
GETSEW(x1, 0);
|
||||
SXTHw(x2, xRAX);
|
||||
MULw(x1, x2, x1);
|
||||
UFLAG_RES(x1);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
BFXILx(xRDX, x1, 16, 16);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1, 0);
|
||||
CALL(div16, -1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("IDIV Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEW(x1, 0);
|
||||
CALL(idiv16, -1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("INC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
GETEW(x1, 0);
|
||||
emit_inc16(dyn, ninst, x1, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("DEC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SET);
|
||||
GETEW(x1, 0);
|
||||
emit_dec16(dyn, ninst, x1, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
Executable
+928
@@ -0,0 +1,928 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
// Get EX as a quad
|
||||
#define GETEX(a, D) \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3)); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, D); \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
VLDR128_U12(a, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
#define GETG gd = ((nextop&0x38)>>3)+(rex.r<<3)
|
||||
|
||||
#define GETGX(a) \
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd)
|
||||
|
||||
#define GETGX_empty(a) \
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg_empty(dyn, ninst, x1, gd)
|
||||
|
||||
uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
int32_t i32, j32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1;
|
||||
uint8_t eb1, eb2;
|
||||
int v0, v1;
|
||||
int q0, q1;
|
||||
int d0;
|
||||
int fixedaddress;
|
||||
|
||||
MAYUSE(d0);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(j32);
|
||||
#if 0//STEP == 3
|
||||
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
|
||||
#endif
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
|
||||
case 0x12:
|
||||
INST_NAME("MOVLPD Gx, Eq");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
if(MODREG) {
|
||||
// access register instead of memory is bad opcode!
|
||||
DEFAULT;
|
||||
return addr;
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
VLD1_64(v0, 0, ed);
|
||||
break;
|
||||
case 0x13:
|
||||
INST_NAME("MOVLPD Eq, Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
if(MODREG) {
|
||||
// access register instead of memory is bad opcode!
|
||||
DEFAULT;
|
||||
return addr;
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
VST1_64(v0, 0, ed);
|
||||
break;
|
||||
case 0x14:
|
||||
INST_NAME("UNPCKLPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
VMOVeD(v0, 1, v1, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
VLD1_64(v0, 1, ed);
|
||||
}
|
||||
break;
|
||||
case 0x15:
|
||||
INST_NAME("UNPCKHPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
VMOVeD(v0, 0, v0, 1);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
VMOVeD(v0, 1, v1, 1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
ADDx_U12(ed, ed, 8);
|
||||
VLD1_64(v0, 1, ed);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1F:
|
||||
INST_NAME("NOP (multibyte)");
|
||||
nextop = F8;
|
||||
FAKEED;
|
||||
break;
|
||||
|
||||
case 0x28:
|
||||
INST_NAME("MOVAPD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, ed);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x29:
|
||||
INST_NAME("MOVAPD Ex,Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x2E:
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
if(opcode==0x2F) {INST_NAME("COMISD Gx, Ex");} else {INST_NAME("UCOMISD Gx, Ex");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(q0, 0);
|
||||
FCMPD(v0, q0);
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
READFLAGS(F); \
|
||||
GETFLAGS; \
|
||||
nextop=F8; \
|
||||
GETGD; \
|
||||
if(MODREG) { \
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 0); \
|
||||
LDRH_U12(x1, ed, fixedaddress); \
|
||||
ed = x1; \
|
||||
} \
|
||||
Bcond(NO, +8); \
|
||||
BFIx(gd, ed, 0, 16);
|
||||
|
||||
GOCOND(0x40, "CMOV", "Gw, Ew");
|
||||
#undef GO
|
||||
|
||||
case 0x54:
|
||||
INST_NAME("ANDPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0);
|
||||
VANDQ(v0, v0, q0);
|
||||
break;
|
||||
case 0x55:
|
||||
INST_NAME("ANDNPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0);
|
||||
VBICQ(v0, q0, v0);
|
||||
break;
|
||||
case 0x56:
|
||||
INST_NAME("ORPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0);
|
||||
VORRQ(v0, v0, q0);
|
||||
break;
|
||||
case 0x57:
|
||||
INST_NAME("XORPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
GETGX(v0);
|
||||
VEORQ(v0, v0, q0);
|
||||
break;
|
||||
|
||||
case 0x5A:
|
||||
INST_NAME("CVTPD2PS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(v1, 0);
|
||||
GETGX_empty(v0);
|
||||
FCVTXN(v0, v1);
|
||||
break;
|
||||
case 0x5B:
|
||||
INST_NAME("CVTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(v1, 0);
|
||||
GETGX_empty(v0);
|
||||
#ifdef PRECISE_CVT
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
UBFXx(x1, x1, 13, 2); // extract round requested
|
||||
LSLx_REG(x1, x1, 3);
|
||||
ADDx_U12(x1, x1, 8); // add the actual add+jump opcodes
|
||||
// Construct a "switch case", with each case 2 instructions, so 8 bytes
|
||||
BL(+4); // Branch with Link to next, so LR gets next PC address
|
||||
ADDx_REG(xLR, xLR, x1);
|
||||
B(xLR); // could use RET, but it's not really one
|
||||
VFCVTNSQS(v0, v1); // 0: Nearest (even)
|
||||
B_NEXT_nocond;
|
||||
VFCVTMSQS(v0, v1); // 1: Toward -inf
|
||||
B_NEXT_nocond;
|
||||
VFCVTPSQS(v0, v1); // 2: Toward +inf
|
||||
B_NEXT_nocond;
|
||||
VFCVTZSQS(v0, v1); // 3: Toward 0
|
||||
#else
|
||||
VFCVTNSQS(v0, v1);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0x60:
|
||||
INST_NAME("PUNPCKLBW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(q0, 0);
|
||||
VZIP1Q_8(v0, v0, q0);
|
||||
break;
|
||||
case 0x61:
|
||||
INST_NAME("PUNPCKLWD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(q0, 0);
|
||||
VZIP1Q_16(v0, v0, q0);
|
||||
break;
|
||||
case 0x62:
|
||||
INST_NAME("PUNPCKLDQ Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(q0, 0);
|
||||
VZIP1Q_32(v0, v0, q0);
|
||||
break;
|
||||
|
||||
case 0x64:
|
||||
INST_NAME("PCMPGTB Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(v1, 0);
|
||||
VCMGTQ_8(v0, v0, v1);
|
||||
break;
|
||||
case 0x65:
|
||||
INST_NAME("PCMPGTW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(v1, 0);
|
||||
VCMGTQ_16(v0, v0, v1);
|
||||
break;
|
||||
case 0x66:
|
||||
INST_NAME("PCMPGTD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(v1, 0);
|
||||
VCMGTQ_32(v0, v0, v1);
|
||||
break;
|
||||
|
||||
case 0x68:
|
||||
INST_NAME("PUNPCKHBW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0);
|
||||
GETEX(q1, 1);
|
||||
VZIP2Q_8(q0, q0, q1);
|
||||
break;
|
||||
case 0x69:
|
||||
INST_NAME("PUNPCKHWD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0);
|
||||
GETEX(q1, 1);
|
||||
VZIP2Q_16(q0, q0, q1);
|
||||
break;
|
||||
case 0x6A:
|
||||
INST_NAME("PUNPCKHDQ Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0);
|
||||
GETEX(q1, 1);
|
||||
VZIP2Q_32(q0, q0, q1);
|
||||
break;
|
||||
case 0x6B:
|
||||
INST_NAME("PACKSSDW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(v1, 0);
|
||||
SQXTN_16(v0, v0);
|
||||
if(v0==v1) {
|
||||
VMOVeD(v0, 1, v0, 0);
|
||||
} else {
|
||||
SQXTN2_16(v0, v1);
|
||||
}
|
||||
break;
|
||||
case 0x6C:
|
||||
INST_NAME("PUNPCKLQDQ Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
VMOVeD(v0, 1, v1, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
VLD1_64(v0, 1, ed);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x6E:
|
||||
INST_NAME("MOVD Gx, Ed");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
GETED(0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
if(rex.w) {
|
||||
FMOVDx(v0, ed);
|
||||
} else {
|
||||
VEORQ(v0, v0, v0); // RAZ vector
|
||||
VMOVQSfrom(v0, 0, ed);
|
||||
}
|
||||
break;
|
||||
case 0x6F:
|
||||
INST_NAME("MOVDQA Gx,Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x70:
|
||||
INST_NAME("PSHUFD Gx,Ex,Ib");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
i32 = -1;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
if(MODREG) {
|
||||
u8 = F8;
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
if(u8==0x4E) {
|
||||
if(v0==v1) {
|
||||
VSWP(v0, v0+1);
|
||||
} else {
|
||||
VMOVeD(v0, 0, v1, 1);
|
||||
VMOVeD(v0, 1, v1, 0);
|
||||
}
|
||||
} else {
|
||||
uint32_t swp[4] = {
|
||||
(0)|(1<<8)|(2<<16)|(3<<24),
|
||||
(4)|(5<<8)|(6<<16)|(7<<24),
|
||||
(8)|(9<<8)|(10<<16)|(11<<24),
|
||||
(12)|(13<<8)|(14<<16)|(15<<24)
|
||||
};
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if(v0==v1) {
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VMOVQ(q1, v1);
|
||||
} else
|
||||
q1 = v1;
|
||||
MOV32w(x2, swp[(u8>>(0*2))&3]);
|
||||
MOV32w(x3, swp[(u8>>(1*2))&3]);
|
||||
VMOVQSfrom(d0, 0, x2);
|
||||
VMOVQSfrom(d0, 1, x3);
|
||||
MOV32w(x2, swp[(u8>>(2*2))&3]);
|
||||
MOV32w(x3, swp[(u8>>(3*2))&3]);
|
||||
VMOVQSfrom(d0, 2, x2);
|
||||
VMOVQSfrom(d0, 3, x3);
|
||||
VTBLQ1_8(v0, v1, d0);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 1);
|
||||
u8 = F8;
|
||||
if (u8) {
|
||||
for (int i=0; i<4; ++i) {
|
||||
int32_t idx = (u8>>(i*2))&3;
|
||||
if(idx!=i32) {
|
||||
ADDx_U12(x2, ed, idx*4);
|
||||
i32 = idx;
|
||||
}
|
||||
VLD1_32(v0, i, x2);
|
||||
}
|
||||
} else {
|
||||
VLD1R_32(v0, ed);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x71:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 2:
|
||||
INST_NAME("PSRLW Ex, Ib");
|
||||
GETEX(q0, 1);
|
||||
u8 = F8;
|
||||
if(u8) {
|
||||
if (u8>15) {
|
||||
VEORQ(q0, q0, q0);
|
||||
} else if(u8) {
|
||||
VSHRQ_16(q0, q0, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("PSRAW Ex, Ib");
|
||||
GETEX(q0, 1);
|
||||
u8 = F8;
|
||||
if(u8>15) u8=15;
|
||||
if(u8) {
|
||||
VSSHRQ_16(q0, q0, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("PSLLW Ex, Ib");
|
||||
GETEX(q0, 1);
|
||||
u8 = F8;
|
||||
if(u8) {
|
||||
if (u8>15) {
|
||||
VEORQ(q0, q0, q0);
|
||||
} else {
|
||||
VSHLQ_16(q0, q0, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x72:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 2:
|
||||
INST_NAME("PSRLD Ex, Ib");
|
||||
GETEX(q0, 1);
|
||||
u8 = F8;
|
||||
if(u8) {
|
||||
if (u8>31) {
|
||||
VEORQ(q0, q0, q0);
|
||||
} else if(u8) {
|
||||
VSHRQ_32(q0, q0, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("PSRAD Ex, Ib");
|
||||
GETEX(q0, 1);
|
||||
u8 = F8;
|
||||
if(u8>31) u8=31;
|
||||
if(u8) {
|
||||
VSSHRQ_32(q0, q0, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("PSLLD Ex, Ib");
|
||||
GETEX(q0, 1);
|
||||
u8 = F8;
|
||||
if(u8) {
|
||||
if (u8>31) {
|
||||
VEORQ(q0, q0, q0);
|
||||
} else {
|
||||
VSHLQ_32(q0, q0, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x73:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 2:
|
||||
INST_NAME("PSRLQ Ex, Ib");
|
||||
GETEX(q0, 1);
|
||||
u8 = F8;
|
||||
if(u8) {
|
||||
if (u8>63) {
|
||||
VEORQ(q0, q0, q0);
|
||||
} else if(u8) {
|
||||
VSHRQ_64(q0, q0, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("PSRLDQ Ex, Ib");
|
||||
GETEX(q0, 1);
|
||||
u8 = F8;
|
||||
if(u8) {
|
||||
if(u8>15) {
|
||||
VEORQ(q0, q0, q0);
|
||||
} else {
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VEORQ(q1, q1, q1);
|
||||
VEXTQ_8(q0, q0, q1, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("PSLLQ Ex, Ib");
|
||||
GETEX(q0, 1);
|
||||
u8 = F8;
|
||||
if(u8) {
|
||||
if (u8>63) {
|
||||
VEORQ(q0, q0, q0);
|
||||
} else {
|
||||
VSHLQ_64(q0, q0, u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("PSLLDQ Ex, Ib");
|
||||
GETEX(q0, 1);
|
||||
u8 = F8;
|
||||
if(u8) {
|
||||
if(u8>15) {
|
||||
VEORQ(q0, q0, q0);
|
||||
} else if(u8>0) {
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VEORQ(q1, q1, q1);
|
||||
VEXTQ_8(q0, q1, q0, 16-u8);
|
||||
}
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(q0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7E:
|
||||
INST_NAME("MOVD Ed,Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
if(rex.w) {
|
||||
if(MODREG) {
|
||||
ed = xRAX + (nextop&7) + (rex.b<<3);
|
||||
VMOVQDto(ed, v0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VSTR64_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
} else {
|
||||
if(MODREG) {
|
||||
ed = xRAX + (nextop&7) + (rex.b<<3);
|
||||
VMOVSto(ed, v0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VSTR32_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x7F:
|
||||
INST_NAME("MOVDQA Ex,Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA3:
|
||||
INST_NAME("BT Ew, Gw");
|
||||
SETFLAGS(X_CF, SF_SET);
|
||||
nextop = F8;
|
||||
gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3); // GETGD
|
||||
GETEW(x4, 0);
|
||||
ANDw_mask(x2, gd, 0, 0b000011); // mask=0x0f
|
||||
LSRw_REG(x1, ed, x2);
|
||||
BFIw(xFlags, x1, F_CF, 1);
|
||||
break;
|
||||
case 0xA4:
|
||||
case 0xA5:
|
||||
nextop = F8;
|
||||
if(opcode==0xA4) {
|
||||
INST_NAME("SHLD Ew, Gw, Ib");
|
||||
} else {
|
||||
INST_NAME("SHLD Ew, Gw, CL");
|
||||
UXTBw(x3, xRCX);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEWW(x4, x1, (opcode==0xA4)?1:0);
|
||||
GETGW(x2);
|
||||
if(opcode==0xA4) {
|
||||
u8 = F8;
|
||||
MOV32w(x3, u8);
|
||||
}
|
||||
CALL_(shld16, x1, wback);
|
||||
EWBACKW(x1);
|
||||
break;
|
||||
|
||||
case 0xAB:
|
||||
INST_NAME("BTS Ew, Gw");
|
||||
SETFLAGS(X_CF, SF_SET);
|
||||
nextop = F8;
|
||||
gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3); // GETGD
|
||||
GETEW(x4, 0);
|
||||
ANDw_mask(x2, gd, 0, 0b000011); // mask=0x0f
|
||||
LSRw_REG(x1, ed, x2);
|
||||
BFIw(xFlags, x1, F_CF, 1);
|
||||
ANDSw_mask(x1, x1, 0, 0); //mask=1
|
||||
B_NEXT(cNE);
|
||||
MOV32w(x1, 1);
|
||||
LSLxw_REG(x1, x1, x2);
|
||||
EORxw_REG(ed, ed, x1);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0xAC:
|
||||
case 0xAD:
|
||||
nextop = F8;
|
||||
if(opcode==0xAC) {
|
||||
INST_NAME("SHRD Ew, Gw, Ib");
|
||||
} else {
|
||||
INST_NAME("SHRD Ew, Gw, CL");
|
||||
UXTBw(x3, xRCX);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEWW(x4, x1, (opcode==0xAC)?1:0);
|
||||
GETGW(x2);
|
||||
if(opcode==0xAC) {
|
||||
u8 = F8;
|
||||
MOV32w(x3, u8);
|
||||
}
|
||||
CALL_(shrd16, x1, wback);
|
||||
EWBACKW(x1);
|
||||
break;
|
||||
|
||||
case 0xAF:
|
||||
INST_NAME("IMUL Gw,Ew");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
GETSEW(x1, 0);
|
||||
GETSGW(x2);
|
||||
MULw(x2, x2, x1);
|
||||
UFLAG_RES(x2);
|
||||
GWBACK;
|
||||
break;
|
||||
|
||||
case 0xB3:
|
||||
INST_NAME("BTR Ew, Gw");
|
||||
SETFLAGS(X_CF, SF_SET);
|
||||
nextop = F8;
|
||||
gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3); // GETGD
|
||||
GETEW(x4, 0);
|
||||
ANDw_mask(x2, gd, 0, 0b000011); // mask=0x0f
|
||||
LSRw_REG(x1, ed, x2);
|
||||
BFIw(xFlags, x1, F_CF, 1);
|
||||
ANDSw_mask(x1, x1, 0, 0); //mask=1
|
||||
B_NEXT(cEQ);
|
||||
MOV32w(x1, 1);
|
||||
LSLxw_REG(x1, x1, x2);
|
||||
EORxw_REG(ed, ed, x1);
|
||||
EWBACK;
|
||||
break;
|
||||
|
||||
case 0xBB:
|
||||
INST_NAME("BTC Ew, Gw");
|
||||
SETFLAGS(X_CF, SF_SET);
|
||||
nextop = F8;
|
||||
gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3); // GETGD
|
||||
GETEW(x4, 0);
|
||||
ANDw_mask(x2, gd, 0, 0b000011); // mask=0x0f
|
||||
LSRw_REG(x1, ed, x2);
|
||||
BFIw(xFlags, x1, F_CF, 1);
|
||||
ANDw_mask(x1, x1, 0, 0); //mask=1
|
||||
MOV32w(x1, 1);
|
||||
LSLxw_REG(x1, x1, x2);
|
||||
EORxw_REG(ed, ed, x1);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0xBC:
|
||||
INST_NAME("BSF Ew,Gw");
|
||||
SETFLAGS(X_ZF, SF_SET);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEW(x1, 0); // Get EW
|
||||
TSTw_REG(x1, x1);
|
||||
B_MARK(cEQ);
|
||||
RBITw(x1, x1); // reverse
|
||||
CLZw(x2, x1); // x2 gets leading 0 == BSF
|
||||
BFIw(gd, x2, 0, 16);
|
||||
MARK;
|
||||
CSETw(x1, cEQ); //ZF not set
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
SET_DFNONE(x1);
|
||||
break;
|
||||
case 0xBD:
|
||||
INST_NAME("BSR Ew,Gw");
|
||||
SETFLAGS(X_ZF, SF_SET);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEW(x1, 0); // Get EW
|
||||
TSTw_REG(x1, x1); // Don't use CBZ here, as the flag is reused later
|
||||
B_MARK(cEQ);
|
||||
LSLw(x1, x1, 16); // put bits on top
|
||||
CLZw(x2, x1); // x2 gets leading 0
|
||||
SUBw_U12(x2, x2, 15);
|
||||
NEGw_REG(x2, x2); // complement
|
||||
BFIx(gd, x2, 0, 16);
|
||||
MARK;
|
||||
CSETw(x1, cEQ); //ZF not set
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
SET_DFNONE(x1);
|
||||
break;
|
||||
case 0xBE:
|
||||
INST_NAME("MOVSX Gw, Eb");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
if(rex.rex) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
eb1=ed;
|
||||
eb2=0;
|
||||
} else {
|
||||
ed = (nextop&7);
|
||||
eb1 = xRAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
}
|
||||
SBFXw(x1, eb1, eb2, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff, 0, rex, 0, 0);
|
||||
LDRSBw_U12(x1, ed, fixedaddress);
|
||||
}
|
||||
BFIx(gd, x1, 0, 16);
|
||||
break;
|
||||
|
||||
|
||||
case 0xD4:
|
||||
INST_NAME("PADDQ Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(q0, 0);
|
||||
VADDQ_64(v0, v0, q0);
|
||||
break;
|
||||
|
||||
case 0xD6:
|
||||
INST_NAME("MOVQ Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
FMOVD(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VSTR64_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xDB:
|
||||
INST_NAME("PAND Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(q0, 0);
|
||||
VANDQ(v0, v0, q0);
|
||||
break;
|
||||
|
||||
case 0xDF:
|
||||
INST_NAME("PANDN Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(q0, 0);
|
||||
VBICQ(v0, q0, v0);
|
||||
break;
|
||||
|
||||
case 0xEB:
|
||||
INST_NAME("POR Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(q0, 0);
|
||||
VORRQ(v0, v0, q0);
|
||||
break;
|
||||
|
||||
case 0xEF:
|
||||
INST_NAME("PXOR Gx,Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG && ((nextop&7)+(rex.b<<3)==gd)) {
|
||||
// special case for PXOR Gx, Gx
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VEORQ(q0, q0, q0);
|
||||
} else {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(q1, 0);
|
||||
VEORQ(q0, q0, q1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF4:
|
||||
INST_NAME("PMULUDQ Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(v1, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VUZP1Q_32(q0, v0, v0); //A3 A2 A1 A0 -> A3 A1 A2 A0
|
||||
if(MODREG) {
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
} else {
|
||||
q1 = v1;
|
||||
}
|
||||
VUZP1Q_32(q1, v1, v1);
|
||||
VUMULL_32(v0, q0, q1);
|
||||
break;
|
||||
|
||||
case 0xF8:
|
||||
INST_NAME("PSUBB Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(q0, 0);
|
||||
VSUBQ_8(v0, v0, q0);
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("PSUBW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(q0, 0);
|
||||
VSUBQ_16(v0, v0, q0);
|
||||
break;
|
||||
case 0xFA:
|
||||
INST_NAME("PSUBD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(q0, 0);
|
||||
VSUBQ_32(v0, v0, q0);
|
||||
break;
|
||||
case 0xFB:
|
||||
INST_NAME("PSUBQ Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(q0, 0);
|
||||
VSUBQ_64(v0, v0, q0);
|
||||
break;
|
||||
case 0xFC:
|
||||
INST_NAME("PADDB Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(q0, 0);
|
||||
VADDQ_8(v0, v0, q0);
|
||||
break;
|
||||
case 0xFD:
|
||||
INST_NAME("PADDW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(q0, 0);
|
||||
VADDQ_16(v0, v0, q0);
|
||||
break;
|
||||
case 0xFE:
|
||||
INST_NAME("PADDD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(q0, 0);
|
||||
VADDQ_32(v0, v0, q0);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
Executable
+102
@@ -0,0 +1,102 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t opcode = F8;
|
||||
int8_t i8;
|
||||
int32_t i32, j32;
|
||||
MAYUSE(j32);
|
||||
MAYUSE(i32);
|
||||
|
||||
// REX prefix before the 67 are ignored
|
||||
rex.rex = 0;
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
#define GO(NO, YES) \
|
||||
BARRIER(2); \
|
||||
JUMP(addr+i8);\
|
||||
if(dyn->insts) { \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst+1].address-(dyn->arm_size); \
|
||||
Bcond(NO, i32); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->arm_size); \
|
||||
Bcond(YES, i32); \
|
||||
} \
|
||||
}
|
||||
case 0xE0:
|
||||
INST_NAME("LOOPNZ (32bits)");
|
||||
READFLAGS(X_ZF);
|
||||
i8 = F8S;
|
||||
MOVw_REG(x1, xRCX);
|
||||
SUBSw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 32);
|
||||
B_NEXT(cEQ); // ECX is 0, no LOOP
|
||||
TSTw_mask(xFlags, 0b011010, 0); //mask=0x40
|
||||
GO(cNE, cEQ);
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("LOOPZ (32bits)");
|
||||
READFLAGS(X_ZF);
|
||||
i8 = F8S;
|
||||
MOVw_REG(x1, xRCX);
|
||||
SUBSw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 32);
|
||||
B_NEXT(cEQ); // ECX is 0, no LOOP
|
||||
TSTw_mask(xFlags, 0b011010, 0); //mask=0x40
|
||||
GO(cEQ, cNE);
|
||||
break;
|
||||
case 0xE2:
|
||||
INST_NAME("LOOP (32bits)");
|
||||
i8 = F8S;
|
||||
MOVw_REG(x1, xRCX);
|
||||
SUBSw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 32);
|
||||
GO(cEQ, cNE);
|
||||
break;
|
||||
case 0xE3:
|
||||
INST_NAME("JECXZ");
|
||||
i8 = F8S;
|
||||
MOVw_REG(x1, xRCX);
|
||||
TSTw_REG(x1, x1);
|
||||
GO(cNE, cEQ);
|
||||
break;
|
||||
#undef GO
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
Executable
+670
@@ -0,0 +1,670 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
#include "../tools/bridge_private.h"
|
||||
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
// emit OR32 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_or32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_or64:d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
ORRxw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit OR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_or32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV64xw(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_or64:d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_PEND) {} else {MOV64xw(s3, c);}
|
||||
ORRxw_REG(s1, s1, s3);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR32 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_xor64:d_xor32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
EORxw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV64xw(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_xor64:d_xor32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_PEND) {} else {MOV64xw(s3, c);}
|
||||
EORxw_REG(s1, s1, s3);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND32 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_and32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_and64:d_and32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSxw_REG(s1, s1, s2);
|
||||
} else {
|
||||
ANDxw_REG(s1, s1, s2);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_and32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV64xw(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_and64:d_and32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_PEND) {} else {MOV64xw(s3, c);}
|
||||
IFX(X_ALL) {
|
||||
ANDSxw_REG(s1, s1, s3);
|
||||
} else {
|
||||
ANDxw_REG(s1, s1, s3);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit OR8 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_or8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
ORRw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit OR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
MOV32w(s3, c&0xff);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_or8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
ORRw_REG(s1, s1, s3);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR8 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_xor8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
EORx_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
MOV32w(s3, c&0xff);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_xor8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
EORw_REG(s1, s1, s3);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND8 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_REG(s1, s1, s2);
|
||||
} else {
|
||||
ANDw_REG(s1, s1, s2);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw_REG(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
MOV32w(s3, c&0xff);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_REG(s1, s1, s3);
|
||||
} else {
|
||||
ANDw_REG(s1, s1, s3);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// emit OR16 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_or16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
ORRw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 15); //mask=0xffff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit OR16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
//void emit_or16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
//{
|
||||
// IFX(X_PEND) {
|
||||
// MOVW(s3, c);
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
// STR_IMM9(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// SET_DF(s4, d_or16);
|
||||
// } else IFX(X_ALL) {
|
||||
// SET_DFNONE(s4);
|
||||
// }
|
||||
// if(c>=0 && c<256) {
|
||||
// IFX(X_ALL) {
|
||||
// ORRS_IMM8(s1, s1, c, 0);
|
||||
// } else {
|
||||
// ORR_IMM8(s1, s1, c, 0);
|
||||
// }
|
||||
// } else {
|
||||
// IFX(X_PEND) {} else {MOVW(s3, c);}
|
||||
// IFX(X_ALL) {
|
||||
// ORRS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// } else {
|
||||
// ORR_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// }
|
||||
// }
|
||||
// IFX(X_PEND) {
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, res));
|
||||
// }
|
||||
// IFX(X_CF | X_AF | X_ZF) {
|
||||
// BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
// }
|
||||
// IFX(X_OF) {
|
||||
// BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
// }
|
||||
// IFX(X_ZF) {
|
||||
// ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
// }
|
||||
// IFX(X_SF) {
|
||||
// MOV_REG_LSR_IMM5(s3, s1, 15);
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s3, s4);
|
||||
// }
|
||||
//}
|
||||
|
||||
// emit XOR16 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_xor16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
EORw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 15); //mask=0xffff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
//void emit_xor16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
//{
|
||||
// IFX(X_PEND) {
|
||||
// MOVW(s3, c);
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
// STR_IMM9(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// SET_DF(s4, d_xor16);
|
||||
// } else IFX(X_ALL) {
|
||||
// SET_DFNONE(s4);
|
||||
// }
|
||||
// if(c>=0 && c<256) {
|
||||
// IFX(X_ALL) {
|
||||
// XORS_IMM8(s1, s1, c);
|
||||
// } else {
|
||||
// XOR_IMM8(s1, s1, c);
|
||||
// }
|
||||
// } else {
|
||||
// IFX(X_PEND) {} else {MOVW(s3, c);}
|
||||
// IFX(X_ALL) {
|
||||
// XORS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// } else {
|
||||
// XOR_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// }
|
||||
// }
|
||||
// IFX(X_PEND) {
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, res));
|
||||
// }
|
||||
// IFX(X_CF | X_AF | X_ZF) {
|
||||
// BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
// }
|
||||
// IFX(X_OF) {
|
||||
// BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
// }
|
||||
// IFX(X_ZF) {
|
||||
// ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
// }
|
||||
// IFX(X_SF) {
|
||||
// MOV_REG_LSR_IMM5(s3, s1, 15);
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s3, s4);
|
||||
// }
|
||||
//}
|
||||
|
||||
// emit AND16 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_and16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
ANDSw_REG(s1, s1, s2);
|
||||
} else {
|
||||
ANDw_REG(s1, s1, s2);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw_REG(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
//void emit_and16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
//{
|
||||
// IFX(X_PEND) {
|
||||
// MOVW(s3, c);
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
// STR_IMM9(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// SET_DF(s4, d_and16);
|
||||
// } else IFX(X_ALL) {
|
||||
// SET_DFNONE(s4);
|
||||
// }
|
||||
// if(c>=0 && c<256) {
|
||||
// IFX(X_ALL) {
|
||||
// ANDS_IMM8(s1, s1, c);
|
||||
// } else {
|
||||
// AND_IMM8(s1, s1, c);
|
||||
// }
|
||||
// } else {
|
||||
// IFX(X_PEND) {} else {MOVW(s3, c);}
|
||||
// IFX(X_ALL) {
|
||||
// ANDS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// } else {
|
||||
// AND_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// }
|
||||
// }
|
||||
// IFX(X_PEND) {
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, res));
|
||||
// }
|
||||
// IFX(X_CF | X_AF | X_ZF) {
|
||||
// BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
// }
|
||||
// IFX(X_OF) {
|
||||
// BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
// }
|
||||
// IFX(X_ZF) {
|
||||
// ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
// }
|
||||
// IFX(X_SF) {
|
||||
// MOV_REG_LSR_IMM5(s3, s1, 15);
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s3, s4);
|
||||
// }
|
||||
//}
|
||||
Executable
+1856
File diff suppressed because it is too large.
Load diff
Executable
+461
@@ -0,0 +1,461 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
#include "../tools/bridge_private.h"
|
||||
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
// emit SHL32 instruction, from s1 , shift s2, store result in s1 using s3 and s4 as scratch. s3 can be same as s2
|
||||
void emit_shl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
int32_t j32;
|
||||
MAYUSE(j32);
|
||||
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_shl64:d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(F_OF) {
|
||||
CMPSxw_U12(s2, 0);
|
||||
IFX(F_OF) {
|
||||
Bcond(cNE, +8);
|
||||
BFCx(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
Bcond(cNE, +8);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
}
|
||||
IFX(X_CF | X_OF) {
|
||||
MOV32w(s4, rex.w?64:32);
|
||||
SUBxw_REG(s4, s4, s2);
|
||||
LSRxw_REG(s4, s1, s4);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
LSLxw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
BFCx(xFlags, F_ZF, 1);
|
||||
Bcond(cNE, +8);
|
||||
ORRw_mask(xFlags, xFlags, 0b011010, 0); // mask=0x40
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPSxw_U12(s2, 1); // if s2==1
|
||||
IFX(X_SF) {} else {LSRxw(s4, s1, (rex.w)?63:31);}
|
||||
Bcond(cNE, 4+3*4);
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
EORxw_REG(s4, s4, xFlags); // CF is set if OF is asked
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHL32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shl32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_shl64:d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c==0) {
|
||||
IFX(F_OF) {
|
||||
BFCx(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
LSRxw(s3, s1, (rex.w?64:32)-c);
|
||||
BFIxw(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
LSLxw(s1, s1, c);
|
||||
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
BFCx(xFlags, F_ZF, 1);
|
||||
Bcond(cNE, +8);
|
||||
ORRw_mask(xFlags, xFlags, 0b011010, 0); // mask=0x40
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
IFX(X_SF) {} else {LSRxw(s4, s1, (rex.w)?63:31);}
|
||||
Bcond(cNE, +12);
|
||||
EORxw_REG(s4, s4, xFlags); // CF is set if OF is asked
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
} else {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHR32 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s2 can be same as s3
|
||||
void emit_shr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
int32_t j32;
|
||||
MAYUSE(j32);
|
||||
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_shr64:d_shr32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
CMPSxw_U12(s2, 0); //if(!c)
|
||||
IFX(X_PEND) {
|
||||
Bcond(cNE, +12);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
SUBxw_U12(s3, s2, 1);
|
||||
LSRxw_REG(s3, s1, s3);
|
||||
BFIw(xFlags, s3, 0, 1);
|
||||
}
|
||||
LSRxw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
BFCx(xFlags, F_ZF, 1);
|
||||
Bcond(cNE, +8);
|
||||
ORRw_mask(xFlags, xFlags, 0b011010, 0); // mask=0x40
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPSxw_U12(s2, 1); // if s2==1
|
||||
Bcond(cNE, 4+3*4);
|
||||
if(rex.w) {
|
||||
LSRx(s4, s1, 62);
|
||||
} else {
|
||||
LSRw(s4, s1, 30);
|
||||
}
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_shr64:d_shr32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
LSRxw_REG(s3, s1, c-1);
|
||||
BFIw(xFlags, s3, 0, 1);
|
||||
}
|
||||
LSRxw(s1, s1, c);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
BFCx(xFlags, F_ZF, 1);
|
||||
Bcond(cNE, +8);
|
||||
ORRw_mask(xFlags, xFlags, 0b011010, 0); // mask=0x40
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
LSRxw(s4, s1, rex.w?62:30);
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SAR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_sar32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_sar64:d_sar32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
ASRxw(s1, s1, c);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_REG(s1, s1);
|
||||
BFCx(xFlags, F_ZF, 1);
|
||||
Bcond(cNE, +8);
|
||||
ORRw_mask(xFlags, xFlags, 0b011010, 0); // mask=0x40
|
||||
}
|
||||
IFX(X_CF) {
|
||||
ASRxw(s3, s1, c-1);
|
||||
BFIw(xFlags, s3, 0, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit ROL32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rol32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_rol32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
RORxw(s1, s1, (rex.w?64:32)-c);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, s1, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
ADDxw_REG_LSR(s3, s1, s1, rex.w?63:31);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit ROR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_ror32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_ror64:d_ror32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
RORxw(s1, s1, c);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
LSRxw(s3, s1, rex.w?63:31);
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
LSRxw(s3, s1, rex.w?62:30);
|
||||
EORxw_REG_LSR(s3, s3, s3, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHRD32 instruction, from s1, fill s2 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
//void emit_shrd32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4)
|
||||
//{
|
||||
// c&=0x1f;
|
||||
// IFX(X_PEND) {
|
||||
// MOVW(s3, c);
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
// STR_IMM9(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// // same flags calc as shr32
|
||||
// SET_DF(s4, d_shr32);
|
||||
// } else IFX(X_ALL) {
|
||||
// SET_DFNONE(s4);
|
||||
// }
|
||||
// if(!c) {
|
||||
// IFX(X_PEND) {
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, res));
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
// IFX(X_CF) {
|
||||
// MOVS_REG_LSR_IMM5(s1, s1, c);
|
||||
// } else {
|
||||
// MOV_REG_LSR_IMM5(s1, s1, c);
|
||||
// }
|
||||
// IFX(X_ZF|X_CF) {
|
||||
// BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
|
||||
// }
|
||||
// IFX(X_CF) {
|
||||
// ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
|
||||
// }
|
||||
// IFX(X_ZF) {
|
||||
// ORRS_REG_LSL_IMM5(s1, s1, s2, 32-c);
|
||||
// } else {
|
||||
// ORR_REG_LSL_IMM5(s1, s1, s2, 32-c);
|
||||
// }
|
||||
// IFX(X_PEND) {
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, res));
|
||||
// }
|
||||
// IFX(X_ZF) {
|
||||
// ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
// }
|
||||
// IFX(X_SF) {
|
||||
// MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_OF) {
|
||||
// if(c==1) {
|
||||
// MOV_REG_LSR_IMM5(s4, s1, 30);
|
||||
// XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
// BFI(xFlags, s4, F_OF, 1);
|
||||
// }
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s3, s4);
|
||||
// }
|
||||
//}
|
||||
|
||||
//void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4)
|
||||
//{
|
||||
// c&=0x1f;
|
||||
// IFX(X_PEND) {
|
||||
// MOVW(s3, c);
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
// STR_IMM9(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// // same flags computation as with shl32
|
||||
// SET_DF(s4, d_shl32);
|
||||
// } else IFX(X_ALL) {
|
||||
// SET_DFNONE(s4);
|
||||
// }
|
||||
// if(c==0) {
|
||||
// IFX(F_OF) {
|
||||
// BFC(xFlags, F_OF, 1);
|
||||
// }
|
||||
// IFX(X_PEND) {
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, res));
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
// IFX(X_CF) {
|
||||
// MOV_REG_LSR_IMM5(s3, s1, 32-c);
|
||||
// BFI(xFlags, s3, F_CF, 1);
|
||||
// }
|
||||
// IFX(X_OF) {
|
||||
// MOVS_REG_LSL_IMM5(s1, s1, c);
|
||||
// } else {
|
||||
// MOV_REG_LSL_IMM5(s1, s1, c);
|
||||
// }
|
||||
// IFX(X_OF) {
|
||||
// if(c==1) {
|
||||
// UBFX(s3, s2, 0, 1);
|
||||
// XOR_IMM8_COND(cCS, s3, s3, 1);
|
||||
// BFI(xFlags, s3, F_OF, 1);
|
||||
// } else {
|
||||
// BFC(xFlags, F_OF, 1);
|
||||
// }
|
||||
// }
|
||||
// IFX(X_ZF) {
|
||||
// ORRS_REG_LSR_IMM5(s1, s1, s2, 32-c);
|
||||
// } else {
|
||||
// ORR_REG_LSR_IMM5(s1, s1, s2, 32-c);
|
||||
// }
|
||||
//
|
||||
// IFX(X_PEND) {
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, res));
|
||||
// }
|
||||
// IFX(X_ZF) {
|
||||
// ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
// BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
// }
|
||||
// IFX(X_SF) {
|
||||
// MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s3, s4);
|
||||
// }
|
||||
//}
|
||||
Executable
+372
@@ -0,0 +1,372 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
#include "../tools/bridge_private.h"
|
||||
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
// emit CMP32 instruction, from cmp s1 , s2, using s3 and s4 as scratch
|
||||
void emit_cmp32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_cmp64:d_cmp32);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ORNxw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
BICxw(s4, s2, s1); // s4 = ~op1 & op2
|
||||
}
|
||||
SUBSxw_REG(s5, s1, s2); // res = s1 - s2
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ANDxw_REG(s3, s3, s5); // s3 = (~op1 | op2) & res
|
||||
ORRxw_REG(s3, s3, s4); // s3 = (~op1 & op2) | ((~op1 | op2) & res)
|
||||
LSRxw(s4, s3, 3);
|
||||
BFIx(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_ZF|X_CF|X_OF) {
|
||||
MOV32w(s4, (1<<F_ZF)|(1<<F_CF)|(1<<F_OF));
|
||||
BICx(xFlags, xFlags, s4);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
Bcond(cNE, +8);
|
||||
ORRw_mask(xFlags, xFlags, 0b011010, 0); // mask=0x40
|
||||
}
|
||||
IFX(X_CF) {
|
||||
// inverted carry
|
||||
Bcond(cCS, +8);
|
||||
ORRw_mask(xFlags, xFlags, 0, 0); // mask=0x01
|
||||
}
|
||||
IFX(X_OF) {
|
||||
Bcond(cVC, +8);
|
||||
ORRw_mask(xFlags, xFlags, 0b010101, 0); // mask=0x800
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s5, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP32 instruction, from cmp s1 , 0, using s3 and s4 as scratch
|
||||
void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV64xw(s4, 0);
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s4, xEmu, offsetof(x64emu_t, op2));
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
SET_DF(s4, rex.w?d_cmp64:d_cmp32);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
SUBSxw_U12(s3, s1, 0); // res = s1 - 0
|
||||
// and now the tricky ones (and mostly unused), PF and AF
|
||||
// bc = (res & (~d | s)) | (~d & s) => is 0 here...
|
||||
IFX(X_ZF|X_CF|X_OF|X_AF) {
|
||||
MOV32w(s4, (1<<F_ZF)|(1<<F_CF)|(1<<F_OF)|(1<<F_AF));
|
||||
BICw(xFlags, xFlags, s4);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
Bcond(cNE, +8);
|
||||
ORRw_mask(xFlags, xFlags, 0b011010, 0); // mask=0x40
|
||||
}
|
||||
IFX(X_CF) {
|
||||
// inverted carry
|
||||
Bcond(cCS, +8);
|
||||
ORRw_mask(xFlags, xFlags, 0, 0); // mask=0x01
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP16 instruction, from cmp s1 , s2, using s3 and s4 as scratch
|
||||
void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_cmp16);
|
||||
} else {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
SUBw_REG(s5, s1, s2); // res = s1 - s2
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTw_mask(s5, 0, 15); //mask=0xffff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s4, s5, 15);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s)
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
MVNw_REG(s4, s1); // s4 = ~d
|
||||
ORRw_REG(s4, s4, s2); // s4 = ~d | s
|
||||
ANDw_REG(s4, s4, s5); // s4 = res & (~d | s)
|
||||
BICw_REG(s3, s2, s1); // s3 = s & ~d
|
||||
ORRw_REG(s3, s4, s3); // s3 = (res & (~d | s)) | (s & ~d)
|
||||
IFX(X_CF) {
|
||||
LSRw(s4, s3, 15);
|
||||
BFIw(xFlags, s4, F_CF, 1); // CF : bc & 0x8000
|
||||
}
|
||||
IFX(X_AF) {
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_OF) {
|
||||
LSRw(s4, s3, 14);
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP16 instruction, from cmp s1 , #0, using s3 and s4 as scratch
|
||||
void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, 0);
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
SET_DF(s3, d_cmp16);
|
||||
} else {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s) = 0
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 15); //mask=0xffff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s4, s1, 15);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
// emit CMP8 instruction, from cmp s1 , s2, using s3 and s4 as scratch
|
||||
void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_cmp8);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
SUBSw_REG(s5, s1, s2); // res = s1 - s2
|
||||
} else {
|
||||
SUBw_REG(s5, s1, s2); // res = s1 - s2
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s5, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s)
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
ORNw_REG(s4, s2, s1); // s4 = ~d | s
|
||||
ANDw_REG(s4, s4, s5); // s4 = res & (~d | s)
|
||||
BICw_REG(s3, s2, s1); // s3 = s & ~d
|
||||
ORRw_REG(s3, s4, s3); // s3 = (res & (~d | s)) | (s & ~d)
|
||||
IFX(X_CF) {
|
||||
LSRw(s4, s3, 7);
|
||||
BFIw(xFlags, s4, F_CF, 1); // CF : bc & 0x80
|
||||
}
|
||||
IFX(X_AF) {
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_OF) {
|
||||
LSRw(s4, s3, 6);
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s3, s4);
|
||||
}
|
||||
}
|
||||
// emit CMP8 instruction, from cmp s1 , 0, using s3 and s4 as scratch
|
||||
void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
MOV32w(s4, 0);
|
||||
STRB_U12(s4, xEmu, offsetof(x64emu_t, op2));
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
SET_DF(s3, d_cmp8);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s) = 0
|
||||
IFX(X_CF | X_AF | X_ZF | X_OF) {
|
||||
MOV32w(s3, (1<<F_ZF)|(1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 0b000111); //mask=000000ff
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST32 instruction, from test s1 , s2, using s3 and s4 as scratch
|
||||
void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, rex.w?d_tst64:d_tst32);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
ANDSxw_REG(s3, s1, s2); // res = s1 & s2
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s3, rex.w?63:31);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x64emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
ANDw_mask(s3, s3, 0b011011, 000010); // 0xE0
|
||||
LSRw(s3, s3, 5);
|
||||
MOV64x(s4, (uintptr_t)GetParityTab());
|
||||
LDRw_REG_LSL2(s4, s4, s3);
|
||||
ANDw_mask(s3, s1, 0, 0b000100); // 0x1f
|
||||
LSRw_REG(s4, s4, s3);
|
||||
MVNx_REG(s4, s4);
|
||||
BFIw(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST16 instruction, from test s1 , s2, using s3 and s4 as scratch
|
||||
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, d_tst16);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFCw(xFlags, F_CF, 1);
|
||||
}
|
||||
ANDSw_REG(s5, s1, s2); // res = s1 & s2
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s4, s5, 15);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x64emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST8 instruction, from test s1 , s2, using s3 and s4 as scratch
|
||||
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, d_tst8);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFCw(xFlags, F_CF, 1);
|
||||
}
|
||||
ANDSw_REG(s5, s1, s2); // res = s1 & s2
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s4, s5, 7);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x64emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s3, s4);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,379 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
int32_t j32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb2, gb1, gb2;
|
||||
int64_t i64;
|
||||
int fixedaddress;
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(j32);
|
||||
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
// REX prefix before the F0 are ignored
|
||||
rex.rex = 0;
|
||||
while(opcode>=0x40 && opcode<=0x4f) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
case 0x00:
|
||||
INST_NAME("LOCK ADD Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGB(x2);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(rex.rex) {
|
||||
wback = xRAX + (nextop&7) + (rex.b<<3);
|
||||
wb2 = 0;
|
||||
} else {
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
wback = xRAX+(wback&3);
|
||||
}
|
||||
UBFXw(x1, wback, wb2*8, 8);
|
||||
emit_add8(dyn, ninst, x1, x2, x4, x3);
|
||||
BFIx(wback, x1, wb2*8, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRB(x1, wback);
|
||||
emit_add8(dyn, ninst, x1, x2, x4, x3);
|
||||
STLXRB(x4, x1, wback);
|
||||
CBNZx_MARKLOCK(x4);
|
||||
}
|
||||
break;
|
||||
case 0x01:
|
||||
INST_NAME("LOCK ADD Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
emit_add32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_add32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0F:
|
||||
nextop = F8;
|
||||
switch(nextop) {
|
||||
|
||||
case 0xB1:
|
||||
INST_NAME("LOCK CMPXCHG Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = 0;
|
||||
UFLAG_IF {emit_cmp32(dyn, ninst, rex, xRAX, ed, x3, x4, x5);}
|
||||
MOVxw_REG(x1, ed); // save value
|
||||
CMPSxw_REG(xRAX, x1);
|
||||
B_MARK2(cNE);
|
||||
MOVxw_REG(ed, gd);
|
||||
MARK2;
|
||||
MOVxw_REG(xRAX, x1);
|
||||
B_NEXT_nocond;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK3(cNE);
|
||||
// Aligned version
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
ed = x1;
|
||||
CMPSxw_REG(xRAX, ed);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
STLXRxw(x4, gd, wback);
|
||||
CBNZx_MARKLOCK(x4);
|
||||
// done
|
||||
B_MARK_nocond;
|
||||
// Unaligned version
|
||||
MARK3;
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x3, wback); // dummy read, to arm the write...
|
||||
ed = x1;
|
||||
CMPSxw_REG(xRAX, ed);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
STLXRB(x4, gd, wback);
|
||||
CBNZx_MARK3(x4);
|
||||
STRxw_U12(gd, wback, 0);
|
||||
B_MARK_nocond;
|
||||
MARK;
|
||||
// Common part (and fallback for EAX != Ed)
|
||||
UFLAG_IF {emit_cmp32(dyn, ninst, rex, xRAX, ed, x3, x4, x5);}
|
||||
MOVxw_REG(xRAX, ed);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC1:
|
||||
INST_NAME("LOCK XADD Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOVxw_REG(x1, ed);
|
||||
MOVxw_REG(ed, gd);
|
||||
MOVxw_REG(gd, x1);
|
||||
emit_add32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, 0);
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE); // unaligned
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
ADDxw_REG(x4, x1, gd);
|
||||
STLXRxw(x3, x4, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
B_MARK2_nocond;
|
||||
MARK;
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIxw(x1, x4, 0, 8);
|
||||
ADDxw_REG(x4, x1, gd);
|
||||
STLXRB(x3, x4, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRxw_U12(x4, wback, 0);
|
||||
MARK2;
|
||||
IFX(X_ALL|X_PEND) {
|
||||
MOVxw_REG(x2, x1);
|
||||
emit_add32(dyn, ninst, rex, x2, gd, x3, x4);
|
||||
}
|
||||
MOVxw_REG(gd, x1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //ADD
|
||||
if(opcode==0x81) {
|
||||
INST_NAME("LOCK ADD Ed, Id");
|
||||
} else {
|
||||
INST_NAME("LOCK ADD Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV64xw(x5, i64);
|
||||
emit_add32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_add32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
B_NEXT_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIxw(x1, x4, 0, 8); // re-inject
|
||||
emit_add32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRxw_U12(x1, wback, 0); // put the whole value
|
||||
}
|
||||
break;
|
||||
case 1: //OR
|
||||
if(opcode==0x81) {INST_NAME("LOCK OR Ed, Id");} else {INST_NAME("LOCK OR Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV64xw(x5, i64);
|
||||
emit_or32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_or32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
break;
|
||||
case 2: //ADC
|
||||
if(opcode==0x81) {INST_NAME("LOCK ADC Ed, Id");} else {INST_NAME("LOCK ADC Ed, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV64xw(x5, i64);
|
||||
emit_adc32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_adc32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
break;
|
||||
case 3: //SBB
|
||||
if(opcode==0x81) {INST_NAME("LOCK SBB Ed, Id");} else {INST_NAME("LOCK SBB Ed, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV64xw(x5, i64);
|
||||
emit_sbb32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_sbb32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
break;
|
||||
case 4: //AND
|
||||
if(opcode==0x81) {INST_NAME("LOCK AND Ed, Id");} else {INST_NAME("LOCK AND Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV64xw(x5, i64);
|
||||
emit_and32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_and32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
break;
|
||||
case 5: //SUB
|
||||
if(opcode==0x81) {INST_NAME("LOCK SUB Ed, Id");} else {INST_NAME("LOCK SUB Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV64xw(x5, i64);
|
||||
emit_sub32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
|
||||
B_MARK(cNE);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_sub32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
B_NEXT_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIxw(x1, x4, 0, 8); // re-inject
|
||||
emit_sub32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRxw_U12(x1, wback, 0); // put the whole value
|
||||
}
|
||||
break;
|
||||
case 6: //XOR
|
||||
if(opcode==0x81) {INST_NAME("LOCK XOR Ed, Id");} else {INST_NAME("LOCK XOR Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV64xw(x5, i64);
|
||||
emit_xor32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_xor32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
break;
|
||||
case 7: //CMP
|
||||
if(opcode==0x81) {INST_NAME("(LOCK) CMP Ed, Id");} else {INST_NAME("(LOCK) CMP Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETED(0);
|
||||
// No need to LOCK, this is readonly
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
if(i64) {
|
||||
MOV64xw(x5, i64);
|
||||
emit_cmp32(dyn, ninst, rex, ed, x5, x3, x4, x6);
|
||||
} else {
|
||||
emit_cmp32_0(dyn, ninst, rex, ed, x3, x4);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
Executable
+239
@@ -0,0 +1,239 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
// Get Ex as a double, not a quad (warning, x2 get used)
|
||||
#define GETEX(a, D) \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3)); \
|
||||
} else { \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, D); \
|
||||
VLDR64_U12(a, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
#define GETG gd = ((nextop&0x38)>>3)+(rex.r<<3)
|
||||
|
||||
#define GETGX(a) gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd)
|
||||
|
||||
uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback;
|
||||
int v0, v1;
|
||||
int q0;
|
||||
int d0, d1;
|
||||
int fixedaddress;
|
||||
|
||||
#ifdef PRECISE_CVT
|
||||
int j32;
|
||||
MAYUSE(j32);
|
||||
#endif
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(v0);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x10:
|
||||
INST_NAME("MOVSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+ (rex.b<<3);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
d0 = sse_get_reg(dyn, ninst, x1, ed);
|
||||
VMOV(v0, d0);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress); // upper part reseted
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("MOVSD Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+ (rex.b<<3);
|
||||
d0 = sse_get_reg(dyn, ninst, x1, ed);
|
||||
VMOV(d0, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VSTR64_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x2A:
|
||||
INST_NAME("CVTSI2SD Gx, Ed");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETED(0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if(rex.w) {
|
||||
SCVTFDx(d1, ed);
|
||||
} else {
|
||||
SCVTFDw(d1, ed);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
break;
|
||||
|
||||
case 0x2C:
|
||||
INST_NAME("CVTTSD2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEX(q0, 0);
|
||||
FCVTZSxwD(gd, q0);
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("CVTSD2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEX(q0, 0);
|
||||
#ifdef PRECISE_CVT
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
UBFXx(x1, x1, 13, 2); // extract round requested
|
||||
LSLx_REG(x1, x1, 3);
|
||||
ADDx_U12(x1, x1, 8); // add the actual add+jump opcodes
|
||||
// Construct a "switch case", with each case 2 instructions, so 8 bytes
|
||||
BL(+4); // Branch with Link to next, so LR gets next PC address
|
||||
ADDx_REG(xLR, xLR, x1);
|
||||
B(xLR); // could use RET, but it's not really one
|
||||
FCVTNSxwD(gd, q0); // 0: Nearest (even)
|
||||
B_NEXT_nocond;
|
||||
FCVTMSxwD(gd, q0); // 1: Toward -inf
|
||||
B_NEXT_nocond;
|
||||
FCVTPSxwD(gd, q0); // 2: Toward +inf
|
||||
B_NEXT_nocond;
|
||||
FCVTZSxwD(gd, q0); // 3: Toward 0
|
||||
#else
|
||||
FCVTNSxwD(gd, q0);
|
||||
#endif
|
||||
break;
|
||||
|
||||
|
||||
case 0x51:
|
||||
INST_NAME("SQRTSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0);
|
||||
FSQRTD(d1, d0);
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
break;
|
||||
|
||||
case 0x58:
|
||||
INST_NAME("ADDSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0);
|
||||
FADDD(d1, v0, d0); // the high part of the vector is erased...
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0);
|
||||
FMULD(d1, v0, d0);
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTSD2SS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(d0, 0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FCVT_S_D(d1, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
|
||||
case 0x5C:
|
||||
INST_NAME("SUBSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0);
|
||||
FSUBD(d1, v0, d0);
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINSD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(v1, 0);
|
||||
// MINSD: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FMINNMD(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
|
||||
VMOVeD(v0, 0, d0, 0); // to not erase uper part
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0);
|
||||
FDIVD(d1, v0, d0);
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXSD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(v1, 0);
|
||||
// MAXSD: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FMAXNMD(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
|
||||
VMOVeD(v0, 0, d0, 0); // to not erase uper part
|
||||
break;
|
||||
|
||||
case 0x7C:
|
||||
INST_NAME("HADDPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VLDR128_U12(v1, ed, fixedaddress);
|
||||
}
|
||||
VFADDPQS(v0, v0, v1);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
Executable
+290
@@ -0,0 +1,290 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
// Get Ex as a single, not a quad (warning, x2 get used)
|
||||
#define GETEX(a, D) \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3)); \
|
||||
} else { \
|
||||
a = fpu_get_scratch(dyn); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, D); \
|
||||
VLDR32_U12(a, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
#define GETG gd = ((nextop&0x38)>>3)+(rex.r<<3)
|
||||
|
||||
#define GETGX(a) gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd)
|
||||
|
||||
#define GETGX_empty(a) gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg_empty(dyn, ninst, x1, gd)
|
||||
|
||||
uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback;
|
||||
int v0, v1;
|
||||
int q0, q1;
|
||||
int d0, d1;
|
||||
int fixedaddress;
|
||||
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(v0);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x10:
|
||||
INST_NAME("MOVSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
VMOVeS(v0, 0, q0, 0);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VLDR32_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("MOVSS Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
VMOVeS(q0, 0, v0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
|
||||
VSTR32_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
INST_NAME("MOVSLDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VLDR128_U12(q1, ed, fixedaddress);
|
||||
}
|
||||
GETGX_empty(q0);
|
||||
VTRNQ1_32(q0, q1, q1);
|
||||
break;
|
||||
|
||||
case 0x16:
|
||||
INST_NAME("MOVSHDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VLDR128_U12(q1, ed, fixedaddress);
|
||||
}
|
||||
GETGX_empty(q0);
|
||||
VTRNQ2_32(q0, q1, q1);
|
||||
break;
|
||||
|
||||
case 0x2A:
|
||||
INST_NAME("CVTSI2SS Gx, Ed");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETED(0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if(rex.w) {
|
||||
SCVTFSx(d1, ed);
|
||||
} else {
|
||||
SCVTFSw(d1, ed);
|
||||
}
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
|
||||
case 0x2C:
|
||||
INST_NAME("CVTTSS2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEX(d0, 0);
|
||||
FCVTZSxwS(gd, d0);
|
||||
break;
|
||||
|
||||
case 0x51:
|
||||
INST_NAME("SQRTSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0);
|
||||
FSQRTS(d1, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
|
||||
case 0x58:
|
||||
INST_NAME("ADDSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0);
|
||||
FADDS(d1, v0, d0); // the high part of the vector is erased...
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0);
|
||||
FMULS(d1, v0, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTSS2SD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(v1, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FCVT_D_S(d0, v1);
|
||||
VMOVeD(v0, 0, d0, 0);
|
||||
break;
|
||||
|
||||
case 0x5C:
|
||||
INST_NAME("SUBSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0);
|
||||
FSUBS(d1, v0, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(v1, 0);
|
||||
// MINSS: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FMINNMS(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
|
||||
VMOVeS(v0, 0, d0, 0); // to not erase uper part
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEX(d0, 0);
|
||||
FDIVS(d1, v0, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(v1, 0);
|
||||
// MAXSS: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FMAXNMS(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
|
||||
VMOVeS(v0, 0, d0, 0); // to not erase uper part
|
||||
break;
|
||||
|
||||
case 0x6F:
|
||||
INST_NAME("MOVDQU Gx,Ex");// no alignment constraint on NEON here, so same as MOVDQA
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7E:
|
||||
INST_NAME("MOVQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
FMOVD(v0, v1);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
|
||||
VLDR64_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x7F:
|
||||
INST_NAME("MOVDQU Ex,Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC2:
|
||||
INST_NAME("CMPSS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(v1, 1);
|
||||
u8 = F8;
|
||||
if((u8&7)==6){
|
||||
FCMPS(v1, v0);
|
||||
} else {
|
||||
FCMPS(v0, v1);
|
||||
}
|
||||
switch(u8&7) {
|
||||
case 0: CSETMw(x2, cEQ); break; // Equal
|
||||
case 1: CSETMw(x2, cMI); break; // Less than
|
||||
case 2: //CSETMw(x2, cLE); break; // Less or equal (or unordered on ARM64, not on x86...)
|
||||
CSETMw(x2, cPL); CSINVw(x2, xZR, x2, cEQ); break; // so use a 2 step here, but 1st test inverted because 2nd step invert again
|
||||
case 3: CSETMw(x2, cVS); break; // NaN
|
||||
case 4: CSETMw(x2, cNE); break; // Not Equal (or unordered on ARM, not on X86...)
|
||||
case 5: CSETMw(x2, cCS); break; // Greater or equal or unordered
|
||||
case 6: CSETMw(x2, cLT); break; // Greater or unordered, test inverted, N!=V so unordereded or less than (inverted)
|
||||
case 7: CSETMw(x2, cVC); break; // not NaN
|
||||
}
|
||||
VMOVQSfrom(v0, 0, x2);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
Executable
+335
@@ -0,0 +1,335 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "tools/bridge_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "signals.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
void arm_fstp(x64emu_t* emu, void* p)
|
||||
{
|
||||
if(ST0.q!=STld(0).ref)
|
||||
D2LD(&ST0.d, p);
|
||||
else
|
||||
memcpy(p, &STld(0).ld, 10);
|
||||
}
|
||||
|
||||
void arm_print_armreg(x64emu_t* emu, uintptr_t reg, uintptr_t n)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "R%ld=0x%lx (%ld)\n", n, reg, reg);
|
||||
}
|
||||
|
||||
void arm_f2xm1(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = exp2(ST0.d) - 1.0;
|
||||
}
|
||||
void arm_fyl2x(x64emu_t* emu)
|
||||
{
|
||||
ST(1).d = log2(ST0.d)*ST(1).d;
|
||||
}
|
||||
void arm_ftan(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = tan(ST0.d);
|
||||
}
|
||||
void arm_fpatan(x64emu_t* emu)
|
||||
{
|
||||
ST1.d = atan2(ST1.d, ST0.d);
|
||||
}
|
||||
void arm_fxtract(x64emu_t* emu)
|
||||
{
|
||||
int32_t tmp32s = (ST1.q&0x7ff0000000000000LL)>>52;
|
||||
tmp32s -= 1023;
|
||||
ST1.d /= exp2(tmp32s);
|
||||
ST0.d = tmp32s;
|
||||
}
|
||||
void arm_fprem(x64emu_t* emu)
|
||||
{
|
||||
int32_t tmp32s = ST0.d / ST1.d;
|
||||
ST0.d -= ST1.d * tmp32s;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C0 = (tmp32s&1);
|
||||
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
|
||||
emu->sw.f.F87_C1 = ((tmp32s>>2)&1);
|
||||
}
|
||||
void arm_fyl2xp1(x64emu_t* emu)
|
||||
{
|
||||
ST(1).d = log2(ST0.d + 1.0)*ST(1).d;
|
||||
}
|
||||
void arm_fsincos(x64emu_t* emu)
|
||||
{
|
||||
sincos(ST1.d, &ST1.d, &ST0.d);
|
||||
}
|
||||
void arm_frndint(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = fpu_round(emu, ST0.d);
|
||||
}
|
||||
void arm_fscale(x64emu_t* emu)
|
||||
{
|
||||
ST0.d *= exp2(trunc(ST1.d));
|
||||
}
|
||||
void arm_fsin(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = sin(ST0.d);
|
||||
}
|
||||
void arm_fcos(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = cos(ST0.d);
|
||||
}
|
||||
|
||||
void arm_fbld(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_fbld(emu, ed);
|
||||
}
|
||||
|
||||
void arm_fild64(x64emu_t* emu, int64_t* ed)
|
||||
{
|
||||
int64_t tmp;
|
||||
memcpy(&tmp, ed, sizeof(tmp));
|
||||
ST0.d = tmp;
|
||||
STll(0).ll = tmp;
|
||||
STll(0).ref = ST0.q;
|
||||
}
|
||||
|
||||
void arm_fbstp(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_fbst(emu, ed);
|
||||
}
|
||||
|
||||
void arm_fistp64(x64emu_t* emu, int64_t* ed)
|
||||
{
|
||||
// used of memcpy to avoid aligments issues
|
||||
if(STll(0).ref==ST(0).q) {
|
||||
memcpy(ed, &STll(0).ll, sizeof(int64_t));
|
||||
} else {
|
||||
int64_t tmp;
|
||||
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, (double)(int64_t)0x8000000000000000LL) || !isfinite(ST0.d))
|
||||
tmp = 0x8000000000000000LL;
|
||||
else
|
||||
tmp = fpu_round(emu, ST0.d);
|
||||
memcpy(ed, &tmp, sizeof(tmp));
|
||||
}
|
||||
}
|
||||
|
||||
void arm_fistt64(x64emu_t* emu, int64_t* ed)
|
||||
{
|
||||
// used of memcpy to avoid aligments issues
|
||||
int64_t tmp = ST0.d;
|
||||
memcpy(ed, &tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
void arm_fld(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
memcpy(&STld(0).ld, ed, 10);
|
||||
LD2D(&STld(0), &ST(0).d);
|
||||
STld(0).ref = ST0.q;
|
||||
}
|
||||
|
||||
void arm_ud(x64emu_t* emu)
|
||||
{
|
||||
emit_signal(emu, SIGILL, (void*)R_RIP, 0);
|
||||
}
|
||||
|
||||
void arm_fsave(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_savenv(emu, (char*)ed, 0);
|
||||
|
||||
uint8_t* p = ed;
|
||||
p += 28;
|
||||
for (int i=0; i<8; ++i) {
|
||||
LD2D(p, &ST(i).d);
|
||||
p+=10;
|
||||
}
|
||||
}
|
||||
void arm_frstor(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_loadenv(emu, (char*)ed, 0);
|
||||
|
||||
uint8_t* p = ed;
|
||||
p += 28;
|
||||
for (int i=0; i<8; ++i) {
|
||||
D2LD(&ST(i).d, p);
|
||||
p+=10;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void arm_fprem1(x64emu_t* emu)
|
||||
{
|
||||
// simplified version
|
||||
int32_t tmp32s = round(ST0.d / ST1.d);
|
||||
ST0.d -= ST1.d*tmp32s;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C0 = (tmp32s&1);
|
||||
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
|
||||
emu->sw.f.F87_C1 = ((tmp32s>>2)&1);
|
||||
}
|
||||
#define XMM0 0
|
||||
#define XMM8 16
|
||||
#define X870 8
|
||||
#define EMM0 8
|
||||
#define SCRATCH0 24
|
||||
|
||||
// Get a FPU scratch reg
|
||||
int fpu_get_scratch(dynarec_arm_t* dyn)
|
||||
{
|
||||
return SCRATCH0 + dyn->fpu_scratch++; // return an Sx
|
||||
}
|
||||
// Reset scratch regs counter
|
||||
void fpu_reset_scratch(dynarec_arm_t* dyn)
|
||||
{
|
||||
dyn->fpu_scratch = 0;
|
||||
}
|
||||
// Get a x87 double reg
|
||||
int fpu_get_reg_x87(dynarec_arm_t* dyn)
|
||||
{
|
||||
int i=X870;
|
||||
while (dyn->fpuused[i]) ++i;
|
||||
dyn->fpuused[i] = 1;
|
||||
return i; // return a Dx
|
||||
}
|
||||
// Free a FPU double reg
|
||||
void fpu_free_reg(dynarec_arm_t* dyn, int reg)
|
||||
{
|
||||
// TODO: check upper limit?
|
||||
dyn->fpuused[reg] = 0;
|
||||
}
|
||||
// Get an MMX double reg
|
||||
int fpu_get_reg_emm(dynarec_arm_t* dyn, int emm)
|
||||
{
|
||||
dyn->fpuused[EMM0 + emm] = 1;
|
||||
return EMM0 + emm;
|
||||
}
|
||||
// Get an XMM quad reg
|
||||
int fpu_get_reg_xmm(dynarec_arm_t* dyn, int xmm)
|
||||
{
|
||||
if(xmm>7) {
|
||||
dyn->fpuused[XMM8 + xmm - 8] = 1;
|
||||
return XMM8 + xmm - 8;
|
||||
} else {
|
||||
dyn->fpuused[XMM0 + xmm] = 1;
|
||||
return XMM0 + xmm;
|
||||
}
|
||||
}
|
||||
// Reset fpu regs counter
|
||||
void fpu_reset_reg(dynarec_arm_t* dyn)
|
||||
{
|
||||
dyn->fpu_reg = 0;
|
||||
for (int i=0; i<32; ++i)
|
||||
dyn->fpuused[i]=0;
|
||||
}
|
||||
|
||||
#define F8 *(uint8_t*)(addr++)
|
||||
#define F32 *(uint32_t*)(addr+=4, addr-4)
|
||||
#define F32S64 (uint64_t)(int64_t)*(int32_t*)(addr+=4, addr-4)
|
||||
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity, int delta)
|
||||
{
|
||||
|
||||
uint32_t tested = (1<<parity)-1;
|
||||
if((nextop&0xC0)==0xC0)
|
||||
return 0; // direct register, no parity...
|
||||
if(!(nextop&0xC0)) {
|
||||
if((nextop&7)==4) {
|
||||
uint8_t sib = F8;
|
||||
int sib_reg = (sib>>3)&7;
|
||||
if((sib&0x7)==5) {
|
||||
uint64_t tmp = F32S64;
|
||||
if (sib_reg!=4) {
|
||||
// if XXXXXX+reg<<N then check parity of XXXXX and N should be enough
|
||||
return ((tmp&tested)==0 && (sib>>6)>=parity)?1:0;
|
||||
} else {
|
||||
// just a constant...
|
||||
return (tmp&tested)?0:1;
|
||||
}
|
||||
} else {
|
||||
if(sib_reg==4 && parity<3)
|
||||
return 0; // simple [reg]
|
||||
// don't try [reg1 + reg2<<N], unless reg1 is ESP
|
||||
return ((sib&0x7)==4 && (sib>>6)>=parity)?1:0;
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
uint64_t tmp = F32S64;
|
||||
tmp+=addr+delta;
|
||||
return (tmp&tested)?0:1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0; //Form [reg1 + reg2<<N + XXXXXX]
|
||||
}
|
||||
}
|
||||
|
||||
// Do the GETED, but don't emit anything...
|
||||
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop)
|
||||
{
|
||||
if((nextop&0xC0)==0xC0)
|
||||
return addr;
|
||||
if(!(nextop&0xC0)) {
|
||||
if((nextop&7)==4) {
|
||||
uint8_t sib = F8;
|
||||
if((sib&0x7)==5) {
|
||||
addr+=4;
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
addr+=4;
|
||||
}
|
||||
} else {
|
||||
if((nextop&7)==4) {
|
||||
++addr;
|
||||
}
|
||||
if(nextop&0x80) {
|
||||
addr+=4;
|
||||
} else {
|
||||
++addr;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
#undef F8
|
||||
#undef F32
|
||||
|
||||
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn)
|
||||
{
|
||||
#define PK(a) *(uint8_t*)(addr+a)
|
||||
#define PK32(a) *(int32_t*)(addr+a)
|
||||
|
||||
if(!addr)
|
||||
return 0;
|
||||
if(PK(0)==0xff && PK(1)==0x25) { // "absolute" jump, maybe the GOT (well, RIP relative in fact)
|
||||
uintptr_t a1 = addr + 6 + (PK32(2)); // need to add a check to see if the address is from the GOT !
|
||||
addr = *(uintptr_t*)a1;
|
||||
}
|
||||
if(addr<0x10000) // too low, that is suspicious
|
||||
return 0;
|
||||
onebridge_t *b = (onebridge_t*)(addr);
|
||||
if(b->CC==0xCC && b->S=='S' && b->C=='C' && b->w!=(wrapper_t)0 && b->f!=(uintptr_t)PltResolver) {
|
||||
// found !
|
||||
if(retn) *retn = (b->C3==0xC2)?b->N:0;
|
||||
if(calladdress) *calladdress = addr+1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
#undef PK32
|
||||
#undef PK
|
||||
}
|
||||
|
||||
Executable
+57
@@ -0,0 +1,57 @@
|
||||
#ifndef __DYNAREC_ARM_FUNCTIONS_H__
|
||||
#define __DYNAREC_ARM_FUNCTIONS_H__
|
||||
|
||||
typedef struct x64emu_s x64emu_t;
|
||||
|
||||
void arm_fstp(x64emu_t* emu, void* p);
|
||||
|
||||
void arm_print_armreg(x64emu_t* emu, uintptr_t reg, uintptr_t n);
|
||||
|
||||
void arm_f2xm1(x64emu_t* emu);
|
||||
void arm_fyl2x(x64emu_t* emu);
|
||||
void arm_ftan(x64emu_t* emu);
|
||||
void arm_fpatan(x64emu_t* emu);
|
||||
void arm_fxtract(x64emu_t* emu);
|
||||
void arm_fprem(x64emu_t* emu);
|
||||
void arm_fyl2xp1(x64emu_t* emu);
|
||||
void arm_fsincos(x64emu_t* emu);
|
||||
void arm_frndint(x64emu_t* emu);
|
||||
void arm_fscale(x64emu_t* emu);
|
||||
void arm_fsin(x64emu_t* emu);
|
||||
void arm_fcos(x64emu_t* emu);
|
||||
void arm_fbld(x64emu_t* emu, uint8_t* ed);
|
||||
void arm_fild64(x64emu_t* emu, int64_t* ed);
|
||||
void arm_fbstp(x64emu_t* emu, uint8_t* ed);
|
||||
void arm_fistp64(x64emu_t* emu, int64_t* ed);
|
||||
void arm_fistt64(x64emu_t* emu, int64_t* ed);
|
||||
void arm_fld(x64emu_t* emu, uint8_t* ed);
|
||||
void arm_fsave(x64emu_t* emu, uint8_t* ed);
|
||||
void arm_frstor(x64emu_t* emu, uint8_t* ed);
|
||||
void arm_fprem1(x64emu_t* emu);
|
||||
|
||||
void arm_ud(x64emu_t* emu);
|
||||
|
||||
// Get an FPU scratch reg
|
||||
int fpu_get_scratch(dynarec_arm_t* dyn);
|
||||
// Reset scratch regs counter
|
||||
void fpu_reset_scratch(dynarec_arm_t* dyn);
|
||||
// Get an x87 double reg
|
||||
int fpu_get_reg_x87(dynarec_arm_t* dyn);
|
||||
// Get an MMX double reg
|
||||
int fpu_get_reg_emm(dynarec_arm_t* dyn, int emm);
|
||||
// Get an XMM quad reg
|
||||
int fpu_get_reg_xmm(dynarec_arm_t* dyn, int xmm);
|
||||
// Free a FPU/MMX/XMM reg
|
||||
void fpu_free_reg(dynarec_arm_t* dyn, int reg);
|
||||
// Reset fpu regs counter
|
||||
void fpu_reset_reg(dynarec_arm_t* dyn);
|
||||
|
||||
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity, int delta);
|
||||
// Do the GETED, but don't emit anything...
|
||||
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
|
||||
|
||||
// Is what pointed at addr a native call? And if yes, to what function?
|
||||
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn);
|
||||
|
||||
#endif //__DYNAREC_ARM_FUNCTIONS_H__
|
||||
Executable
+989
@@ -0,0 +1,989 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynablock_private.h"
|
||||
#include "arm64_printer.h"
|
||||
#include "../tools/bridge_private.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
|
||||
/* setup r2 to address pointed by ED, also fixaddress is an optionnal delta in the range [-absmax, +absmax], with delta&mask==0 to be added to ed for LDR/STR */
|
||||
uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixaddress, int absmax, uint32_t mask, rex_t rex, int s, int delta)
|
||||
{
|
||||
uint8_t ret = x2;
|
||||
uint8_t scratch = x2;
|
||||
*fixaddress = 0;
|
||||
if(hint>0) ret = hint;
|
||||
if(hint>0 && hint<xRAX) scratch = hint;
|
||||
int absmin = 0;
|
||||
if(s) absmin=-absmax;
|
||||
MAYUSE(scratch);
|
||||
if(!(nextop&0xC0)) {
|
||||
if((nextop&7)==4) {
|
||||
uint8_t sib = F8;
|
||||
int sib_reg = ((sib>>3)&7)+(rex.x<<3);
|
||||
if((sib&0x7)==5) {
|
||||
uint64_t tmp = F32S64;
|
||||
if (sib_reg!=4) {
|
||||
if(tmp && ((tmp<absmin) || (tmp>absmax) || (tmp&mask))) {
|
||||
MOV64x(scratch, tmp);
|
||||
ADDx_REG_LSL(ret, scratch, xRAX+sib_reg, (sib>>6));
|
||||
} else {
|
||||
LSLx(ret, xRAX+sib_reg, (sib>>6));
|
||||
*fixaddress = tmp;
|
||||
}
|
||||
} else {
|
||||
MOV64x(ret, tmp);
|
||||
}
|
||||
} else {
|
||||
if (sib_reg!=4) {
|
||||
ADDx_REG_LSL(ret, xRAX+(sib&0x7)+(rex.b<<3), xRAX+sib_reg, (sib>>6));
|
||||
} else {
|
||||
ret = xRAX+(sib&0x7)+(rex.b<<3);
|
||||
}
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
uint64_t tmp = F32S64;
|
||||
MOV64x(ret, tmp);
|
||||
GETIP(addr+delta);
|
||||
ADDx_REG(ret, ret, xRIP);
|
||||
} else {
|
||||
ret = xRAX+(nextop&7)+(rex.b<<3);
|
||||
}
|
||||
} else {
|
||||
int64_t i64;
|
||||
uint8_t sib = 0;
|
||||
int sib_reg = 0;
|
||||
if((nextop&7)==4) {
|
||||
sib = F8;
|
||||
sib_reg = ((sib>>3)&7)+(rex.x<<3);
|
||||
}
|
||||
if(nextop&0x80)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
if(i64==0 || ((i64>=absmin) && (i64<=absmax) && !(i64&mask))) {
|
||||
*fixaddress = i64;
|
||||
if((nextop&7)==4) {
|
||||
if (sib_reg!=4) {
|
||||
ADDx_REG_LSL(ret, xRAX+(sib&0x07)+(rex.b<<3), xRAX+sib_reg, (sib>>6));
|
||||
} else {
|
||||
ret = xRAX+(sib&0x07)+(rex.b<<3);
|
||||
}
|
||||
} else
|
||||
ret = xRAX+(nextop&0x07)+(rex.b<<3);
|
||||
} else {
|
||||
int64_t sub = (i64<0)?1:0;
|
||||
if(sub) i64 = -i64;
|
||||
if(i64<0x1000) {
|
||||
if((nextop&7)==4) {
|
||||
if (sib_reg!=4) {
|
||||
ADDx_REG_LSL(scratch, xRAX+(sib&0x07)+(rex.b<<3), xRAX+sib_reg, (sib>>6));
|
||||
} else {
|
||||
scratch = xRAX+(sib&0x07)+(rex.b<<3);
|
||||
}
|
||||
} else
|
||||
scratch = xRAX+(nextop&0x07)+(rex.b<<3);
|
||||
if(sub) {
|
||||
SUBx_U12(ret, scratch, i64);
|
||||
} else {
|
||||
ADDx_U12(ret, scratch, i64);
|
||||
}
|
||||
} else {
|
||||
MOV64x(scratch, i64);
|
||||
if((nextop&7)==4) {
|
||||
if (sib_reg!=4) {
|
||||
if(sub) {
|
||||
SUBx_REG(scratch, xRAX+(sib&0x07)+(rex.b<<3), scratch);
|
||||
} else {
|
||||
ADDx_REG(scratch, scratch, xRAX+(sib&0x07)+(rex.b<<3));
|
||||
}
|
||||
ADDx_REG_LSL(ret, scratch, xRAX+sib_reg, (sib>>6));
|
||||
} else {
|
||||
PASS3(int tmp = xRAX+(sib&0x07)+(rex.b<<3));
|
||||
if(sub) {
|
||||
SUBx_REG(ret, tmp, scratch);
|
||||
} else {
|
||||
ADDx_REG(ret, tmp, scratch);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PASS3(int tmp = xRAX+(nextop&0x07)+(rex.b<<3));
|
||||
if(sub) {
|
||||
SUBx_REG(ret, tmp, scratch);
|
||||
} else {
|
||||
ADDx_REG(ret, tmp, scratch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*ed = ret;
|
||||
return addr;
|
||||
}
|
||||
|
||||
/* setup r2 to address pointed by ED, r3 as scratch also fixaddress is an optionnal delta in the range [-absmax, +absmax], with delta&mask==0 to be added to ed for LDR/STR */
|
||||
uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixaddress, int absmax, uint32_t mask, int s)
|
||||
{
|
||||
uint8_t ret = x2;
|
||||
uint8_t scratch = x3;
|
||||
*fixaddress = 0;
|
||||
if(hint>0) ret = hint;
|
||||
if(scratch==ret) scratch = x2;
|
||||
MAYUSE(scratch);
|
||||
uint32_t m = nextop&0xC7;
|
||||
uint32_t n = (m>>6)&3;
|
||||
int32_t offset = 0;
|
||||
int absmin = 0;
|
||||
if(s) absmin = -absmax;
|
||||
if(!n && m==6) {
|
||||
offset = F16;
|
||||
MOVZw(ret, offset);
|
||||
} else {
|
||||
switch(n) {
|
||||
case 0: offset = 0; break;
|
||||
case 1: offset = F8S; break;
|
||||
case 2: offset = F16S; break;
|
||||
}
|
||||
if(offset && (offset>absmax || offset<absmin || (offset&mask))) {
|
||||
*fixaddress = offset;
|
||||
offset = 0;
|
||||
}
|
||||
switch(m&7) {
|
||||
case 0: //R_BX + R_SI
|
||||
UXTHx(ret, xRBX);
|
||||
UXTHx(scratch, xRSI);
|
||||
ADDx_REG(ret, ret, scratch);
|
||||
break;
|
||||
case 1: //R_BX + R_DI
|
||||
UXTHx(ret, xRBX);
|
||||
UXTHx(scratch, xRDI);
|
||||
ADDx_REG(ret, ret, scratch);
|
||||
break;
|
||||
case 2: //R_BP + R_SI
|
||||
UXTHx(ret, xRBP);
|
||||
UXTHx(scratch, xRSI);
|
||||
ADDx_REG(ret, ret, scratch);
|
||||
break;
|
||||
case 3: //R_BP + R_DI
|
||||
UXTHx(ret, xRBP);
|
||||
UXTHx(scratch, xRDI);
|
||||
ADDx_REG(ret, ret, scratch);
|
||||
break;
|
||||
case 4: //R_SI
|
||||
UXTHx(ret, xRSI);
|
||||
break;
|
||||
case 5: //R_DI
|
||||
UXTHx(ret, xRDI);
|
||||
break;
|
||||
case 6: //R_BP
|
||||
UXTHx(ret, xRBP);
|
||||
break;
|
||||
case 7: //R_BX
|
||||
UXTHx(ret, xRBX);
|
||||
break;
|
||||
}
|
||||
if(offset) {
|
||||
if(offset<0 && offset>-0x1000) {
|
||||
SUBx_U12(ret, ret, -offset);
|
||||
} else if(offset>0 && offset<0x1000) {
|
||||
ADDx_U12(ret, ret, offset);
|
||||
} else {
|
||||
MOV64x(scratch, offset);
|
||||
ADDx_REG(ret, ret, scratch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*ed = ret;
|
||||
return addr;
|
||||
}
|
||||
|
||||
void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
{
|
||||
MESSAGE(LOG_DUMP, "Jump to epilog\n");
|
||||
if(reg) {
|
||||
if(reg!=xRIP) {
|
||||
MOVx_REG(xRIP, reg);
|
||||
}
|
||||
} else {
|
||||
GETIP_(ip);
|
||||
}
|
||||
TABLE64(x2, (uintptr_t)arm64_epilog);
|
||||
BR(x2);
|
||||
}
|
||||
|
||||
void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
{
|
||||
MESSAGE(LOG_DUMP, "Jump to next\n");
|
||||
|
||||
if(reg) {
|
||||
if(reg!=xRIP) {
|
||||
MOVx_REG(xRIP, reg);
|
||||
}
|
||||
uintptr_t tbl = getJumpTable64();
|
||||
MAYUSE(tbl);
|
||||
TABLE64(x2, tbl);
|
||||
UBFXx(x3, xRIP, 48, JMPTABL_SHIFT);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, 32, JMPTABL_SHIFT);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, 16, JMPTABL_SHIFT);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, 0, JMPTABL_SHIFT);
|
||||
LDRx_REG_LSL3(x3, x2, x3);
|
||||
} else {
|
||||
uintptr_t p = getJumpTableAddress64(ip);
|
||||
MAYUSE(p);
|
||||
TABLE64(x2, p);
|
||||
GETIP_(ip);
|
||||
LDRx_U12(x3, x2, 0);
|
||||
}
|
||||
if(reg!=x1) {
|
||||
MOVx_REG(x1, xRIP);
|
||||
}
|
||||
#ifdef HAVE_TRACE
|
||||
//MOVx(x2, 15); no access to PC reg
|
||||
#endif
|
||||
BR(x3);
|
||||
}
|
||||
|
||||
void ret_to_epilog(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
MESSAGE(LOG_DUMP, "Ret next\n");
|
||||
POP1(xRIP);
|
||||
uintptr_t tbl = getJumpTable64();
|
||||
MOV64x(x2, tbl);
|
||||
UBFXx(x3, xRIP, 48, JMPTABL_SHIFT);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, 32, JMPTABL_SHIFT);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, 16, JMPTABL_SHIFT);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, 0, JMPTABL_SHIFT);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
MOVx_REG(x1, xRIP);
|
||||
BR(x2);
|
||||
}
|
||||
|
||||
void retn_to_epilog(dynarec_arm_t* dyn, int ninst, int n)
|
||||
{
|
||||
MESSAGE(LOG_DUMP, "Retn epilog\n");
|
||||
POP1(xRIP);
|
||||
if(n>0xfff) {
|
||||
MOV32w(w1, n);
|
||||
ADDx_REG(xRSP, xRSP, x1);
|
||||
} else {
|
||||
ADDx_U12(xRSP, xRSP, n);
|
||||
}
|
||||
uintptr_t tbl = getJumpTable64();
|
||||
MOV64x(x2, tbl);
|
||||
UBFXx(x3, xRIP, 48, JMPTABL_SHIFT);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, 32, JMPTABL_SHIFT);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, 16, JMPTABL_SHIFT);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, 0, JMPTABL_SHIFT);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
MOVx_REG(x1, xRIP);
|
||||
BR(x2);
|
||||
}
|
||||
|
||||
void iret_to_epilog(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
MESSAGE(LOG_DUMP, "IRet epilog\n");
|
||||
// POP IP
|
||||
POP1(xRIP);
|
||||
// POP CS
|
||||
POP1(x2);
|
||||
STRH_U12(x2, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
MOVZw(x1, 0);
|
||||
STRx_U12(x1, xEmu, offsetof(x64emu_t, segs_serial[_CS]));
|
||||
// POP EFLAGS
|
||||
POP1(xFlags);
|
||||
MOV32w(x1, 0x3F7FD7);
|
||||
ANDx_REG(xFlags, xFlags, x1);
|
||||
ORRx_mask(xFlags, xFlags, 1, 0b111111, 0);
|
||||
SET_DFNONE(x1);
|
||||
// Ret....
|
||||
MOV64x(x2, (uintptr_t)arm64_epilog); // epilog on purpose, CS might have changed!
|
||||
BR(x2);
|
||||
}
|
||||
|
||||
void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int savereg)
|
||||
{
|
||||
if(savereg==0)
|
||||
savereg = 7;
|
||||
if(saveflags) {
|
||||
STRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
|
||||
}
|
||||
fpu_pushcache(dyn, ninst, reg);
|
||||
if(ret!=-2) {
|
||||
STPx_S7_preindex(xEmu, savereg, xSP, -16); // ARM64 stack needs to be 16byte aligned
|
||||
STPx_S7_offset(xRAX, xRCX, xEmu, offsetof(x64emu_t, regs[_AX])); // x9..x15, x16,x17,x18 those needs to be saved by caller
|
||||
STPx_S7_offset(xRDX, xRBX, xEmu, offsetof(x64emu_t, regs[_DX])); // but x18 is R8 wich is lost, so it's fine to not save it?
|
||||
STPx_S7_offset(xRSP, xRBP, xEmu, offsetof(x64emu_t, regs[_SP]));
|
||||
STPx_S7_offset(xRSI, xRDI, xEmu, offsetof(x64emu_t, regs[_SI]));
|
||||
STPx_S7_offset(xR8, xR9, xEmu, offsetof(x64emu_t, regs[_R8]));
|
||||
}
|
||||
TABLE64(reg, (uintptr_t)fnc);
|
||||
BLR(reg);
|
||||
if(ret>=0) {
|
||||
MOVx_REG(ret, xEmu);
|
||||
}
|
||||
if(ret!=-2) {
|
||||
LDPx_S7_postindex(xEmu, savereg, xSP, 16);
|
||||
#define GO(A, B) if(ret==x##A) { \
|
||||
LDRx_U12(x##B, xEmu, offsetof(x64emu_t, regs[_##B])); \
|
||||
} else if(ret==x##B) { \
|
||||
LDRx_U12(x##A, xEmu, offsetof(x64emu_t, regs[_##A])); \
|
||||
} else { \
|
||||
LDPx_S7_offset(x##A, x##B, xEmu, offsetof(x64emu_t, regs[_##A])); \
|
||||
}
|
||||
GO(RAX, RCX);
|
||||
GO(RDX, RBX);
|
||||
GO(RSP, RBP);
|
||||
GO(RSI, RDI);
|
||||
GO(R8, R9);
|
||||
#undef GO
|
||||
}
|
||||
fpu_popcache(dyn, ninst, reg);
|
||||
if(saveflags) {
|
||||
LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
|
||||
}
|
||||
SET_NODF();
|
||||
}
|
||||
|
||||
void grab_segdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg, int segment)
|
||||
{
|
||||
int32_t j32;
|
||||
MAYUSE(j32);
|
||||
MESSAGE(LOG_DUMP, "Get %s Offset\n", (segment==_FS)?"FS":"GS");
|
||||
int t1 = x1, t2 = x4;
|
||||
if(reg==t1) ++t1;
|
||||
if(reg==t2) ++t2;
|
||||
LDRw_U12(t2, xEmu, offsetof(x64emu_t, segs_serial[segment]));
|
||||
LDRx_U12(reg, xEmu, offsetof(x64emu_t, segs_offs[segment]));
|
||||
if(segment==_GS) {
|
||||
CBNZw_MARKSEG(t2); // fast check
|
||||
} else {
|
||||
LDRx_U12(t1, xEmu, offsetof(x64emu_t, context));
|
||||
LDRw_U12(t1, t1, offsetof(box64context_t, sel_serial));
|
||||
SUBw_REG(t1, t1, t2);
|
||||
CBZw_MARKSEG(t1);
|
||||
}
|
||||
MOVZw(x1, segment);
|
||||
call_c(dyn, ninst, GetSegmentBaseEmu, t2, reg, 1, 0);
|
||||
MARKSEG;
|
||||
MESSAGE(LOG_DUMP, "----%s Offset\n", (segment==_FS)?"FS":"GS");
|
||||
}
|
||||
|
||||
// x87 stuffs
|
||||
static void x87_reset(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
#if STEP > 1
|
||||
for (int i=0; i<8; ++i)
|
||||
dyn->x87cache[i] = -1;
|
||||
dyn->x87stack = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void x87_stackcount(dynarec_arm_t* dyn, int ninst, int scratch)
|
||||
{
|
||||
#if STEP > 1
|
||||
if(!dyn->x87stack)
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tSynch x87 Stackcount (%d)\n", dyn->x87stack);
|
||||
int a = dyn->x87stack;
|
||||
// Add x87stack to emu fpu_stack
|
||||
LDRx_U12(scratch, xEmu, offsetof(x64emu_t, fpu_stack));
|
||||
if(a>0) {
|
||||
ADDx_U12(scratch, scratch, a);
|
||||
} else {
|
||||
SUBx_U12(scratch, scratch, -a);
|
||||
}
|
||||
STRx_U12(scratch, xEmu, offsetof(x64emu_t, fpu_stack));
|
||||
// Sub x87stack to top, with and 7
|
||||
LDRx_U12(scratch, xEmu, offsetof(x64emu_t, top));
|
||||
if(a>0) {
|
||||
SUBx_U12(scratch, scratch, a);
|
||||
} else {
|
||||
ADDx_U12(scratch, scratch, -a);
|
||||
}
|
||||
ADDx_U12(scratch, scratch, 7);
|
||||
STRx_U12(scratch, xEmu, offsetof(x64emu_t, top));
|
||||
// reset x87stack
|
||||
dyn->x87stack = 0;
|
||||
MESSAGE(LOG_DUMP, "\t------x87 Stackcount\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
int x87_do_push(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
#if STEP > 1
|
||||
dyn->x87stack+=1;
|
||||
// move all regs in cache, and find a free one
|
||||
int ret = -1;
|
||||
for(int i=0; i<8; ++i)
|
||||
if(dyn->x87cache[i]!=-1)
|
||||
++dyn->x87cache[i];
|
||||
else if(ret==-1) {
|
||||
dyn->x87cache[i] = 0;
|
||||
ret=dyn->x87reg[i]=fpu_get_reg_x87(dyn);
|
||||
}
|
||||
return ret;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
void x87_do_push_empty(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
#if STEP > 1
|
||||
dyn->x87stack+=1;
|
||||
// move all regs in cache
|
||||
for(int i=0; i<8; ++i)
|
||||
if(dyn->x87cache[i]!=-1)
|
||||
++dyn->x87cache[i];
|
||||
if(s1)
|
||||
x87_stackcount(dyn, ninst, s1);
|
||||
#endif
|
||||
}
|
||||
void x87_do_pop(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
#if STEP > 1
|
||||
dyn->x87stack-=1;
|
||||
// move all regs in cache, poping ST0
|
||||
for(int i=0; i<8; ++i)
|
||||
if(dyn->x87cache[i]!=-1) {
|
||||
--dyn->x87cache[i];
|
||||
if(dyn->x87cache[i]==-1) {
|
||||
fpu_free_reg(dyn, dyn->x87reg[i]);
|
||||
dyn->x87reg[i] = -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void x87_purgecache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
#if STEP > 1
|
||||
int ret = 0;
|
||||
for (int i=0; i<8 && !ret; ++i)
|
||||
if(dyn->x87cache[i] != -1)
|
||||
ret = 1;
|
||||
if(!ret && !dyn->x87stack) // nothing to do
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tPurge x87 Cache and Synch Stackcount (%+d)\n", dyn->x87stack);
|
||||
int a = dyn->x87stack;
|
||||
if(a!=0) {
|
||||
// reset x87stack
|
||||
dyn->x87stack = 0;
|
||||
// Add x87stack to emu fpu_stack
|
||||
LDRx_U12(s2, xEmu, offsetof(x64emu_t, fpu_stack));
|
||||
if(a>0) {
|
||||
ADDx_U12(s2, s2, a);
|
||||
} else {
|
||||
SUBx_U12(s2, s2, -a);
|
||||
}
|
||||
STRx_U12(s2, xEmu, offsetof(x64emu_t, fpu_stack));
|
||||
// Sub x87stack to top, with and 7
|
||||
LDRx_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
// update tags (and top at the same time)
|
||||
if(a>0) {
|
||||
// new tag to fulls
|
||||
MOVZw(s3, 0);
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, p_regs));
|
||||
for (int i=0; i<a; ++i) {
|
||||
SUBw_U12(s2, s2, 1);
|
||||
ANDw_mask(s2, s2, 0b011111, 1); // (emu->top + st)&7
|
||||
STRw_REG_LSL2(s3, s1, s2);
|
||||
}
|
||||
} else {
|
||||
// empty tags
|
||||
MOVZw(s3, 0b11);
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, p_regs));
|
||||
for (int i=0; i<-a; ++i) {
|
||||
STRw_REG_LSL2(s3, s1, s2);
|
||||
ADDw_U12(s2, s2, 1);
|
||||
ANDw_mask(s2, s2, 0b011111, 1); // (emu->top + st)&7
|
||||
}
|
||||
}
|
||||
STRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
} else {
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
}
|
||||
if(ret!=0) {
|
||||
// --- set values
|
||||
// prepare offset to fpu => s1
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, mmx87));
|
||||
// Get top
|
||||
// loop all cache entries
|
||||
for (int i=0; i<8; ++i)
|
||||
if(dyn->x87cache[i]!=-1) {
|
||||
ADDw_U12(s3, s2, dyn->x87cache[i]);
|
||||
ANDw_mask(s3, s3, 0b011111, 1); // (emu->top + st)&7
|
||||
VSTR64_REG_LSL3(dyn->x87reg[i], s1, s3);
|
||||
fpu_free_reg(dyn, dyn->x87reg[i]);
|
||||
dyn->x87reg[i] = -1;
|
||||
dyn->x87cache[i] = -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_TRACE
|
||||
static void x87_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
#if STEP > 1
|
||||
x87_stackcount(dyn, ninst, s1);
|
||||
int ret = 0;
|
||||
for (int i=0; (i<8) && (!ret); ++i)
|
||||
if(dyn->x87cache[i] != -1)
|
||||
ret = 1;
|
||||
if(!ret) // nothing to do
|
||||
return;
|
||||
// prepare offset to fpu => s1
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, mmx87));
|
||||
// Get top
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
// loop all cache entries
|
||||
for (int i=0; i<8; ++i)
|
||||
if(dyn->x87cache[i]!=-1) {
|
||||
ADDw_U12(s3, s2, dyn->x87cache[i]);
|
||||
ANDw_mask(s3, s3, 0b011111, 1); // (emu->top + i)&7
|
||||
VLDR64_REG_LSL3(dyn->x87reg[i], s1, s3);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int x87_get_cache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
{
|
||||
#if STEP > 1
|
||||
// search in cache first
|
||||
for (int i=0; i<8; ++i)
|
||||
if(dyn->x87cache[i]==st)
|
||||
return i;
|
||||
MESSAGE(LOG_DUMP, "\tCreate x87 Cache for ST%d\n", st);
|
||||
// get a free spot
|
||||
int ret = -1;
|
||||
for (int i=0; (i<8) && (ret==-1); ++i)
|
||||
if(dyn->x87cache[i]==-1)
|
||||
ret = i;
|
||||
// found, setup and grab the value
|
||||
dyn->x87cache[ret] = st;
|
||||
dyn->x87reg[ret] = fpu_get_reg_x87(dyn);
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, mmx87));
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
int a = st - dyn->x87stack;
|
||||
if(a) {
|
||||
if(a<0) {
|
||||
SUBw_U12(s2, s2, -a);
|
||||
} else {
|
||||
ADDw_U12(s2, s2, a);
|
||||
}
|
||||
ANDw_mask(s2, s2, 0b011111, 1);
|
||||
}
|
||||
VLDR64_REG_LSL3(dyn->x87reg[ret], s1, s2);
|
||||
MESSAGE(LOG_DUMP, "\t-------x87 Cache for ST%d\n", st);
|
||||
|
||||
return ret;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int x87_get_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a)
|
||||
{
|
||||
#if STEP > 1
|
||||
return dyn->x87reg[x87_get_cache(dyn, ninst, s1, s2, a)];
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void x87_refresh(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
{
|
||||
#if STEP > 1
|
||||
x87_stackcount(dyn, ninst, s1);
|
||||
int ret = -1;
|
||||
for (int i=0; (i<8) && (ret==-1); ++i)
|
||||
if(dyn->x87cache[i] == st)
|
||||
ret = i;
|
||||
if(ret==-1) // nothing to do
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tRefresh x87 Cache for ST%d\n", st);
|
||||
// prepare offset to fpu => s1
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, mmx87));
|
||||
// Get top
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
// Update
|
||||
if(st) {
|
||||
ADDw_U12(s2, s2, st);
|
||||
ANDw_mask(s2, s2, 0b011111, 1); // (emu->top + i)&7
|
||||
}
|
||||
VLDR64_REG_LSL3(dyn->x87reg[ret], s1, s2);
|
||||
MESSAGE(LOG_DUMP, "\t--------x87 Cache for ST%d\n", st);
|
||||
#endif
|
||||
}
|
||||
|
||||
void x87_forget(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
{
|
||||
#if STEP > 1
|
||||
x87_stackcount(dyn, ninst, s1);
|
||||
int ret = -1;
|
||||
for (int i=0; (i<8) && (ret==-1); ++i)
|
||||
if(dyn->x87cache[i] == st)
|
||||
ret = i;
|
||||
if(ret==-1) // nothing to do
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tForget x87 Cache for ST%d\n", st);
|
||||
// prepare offset to fpu => s1
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, mmx87));
|
||||
// Get top
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
// Update
|
||||
if(st) {
|
||||
ADDw_U12(s2, s2, st);
|
||||
ANDw_mask(s2, s2, 0b011111, 1); // (emu->top + i)&7
|
||||
}
|
||||
VLDR64_REG_LSL3(dyn->x87reg[ret], s1, s2);
|
||||
MESSAGE(LOG_DUMP, "\t--------x87 Cache for ST%d\n", st);
|
||||
// and forget that cache
|
||||
fpu_free_reg(dyn, dyn->x87reg[ret]);
|
||||
dyn->x87cache[ret] = -1;
|
||||
dyn->x87reg[ret] = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
{
|
||||
#if STEP > 1
|
||||
// search in cache first
|
||||
for (int i=0; i<8; ++i)
|
||||
if(dyn->x87cache[i]==st) {
|
||||
// refresh the value
|
||||
MESSAGE(LOG_DUMP, "\tRefresh x87 Cache for ST%d\n", st);
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, mmx87));
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
int a = st - dyn->x87stack;
|
||||
if(a<0) {
|
||||
SUBw_U12(s2, s2, -a);
|
||||
} else {
|
||||
ADDw_U12(s2, s2, a);
|
||||
}
|
||||
ANDw_mask(s2, s2, 0b011111, 1); // (emu->top + i)&7
|
||||
VLDR64_REG_LSL3(dyn->x87reg[i], s1, s2);
|
||||
MESSAGE(LOG_DUMP, "\t-------x87 Cache for ST%d\n", st);
|
||||
// ok
|
||||
return;
|
||||
}
|
||||
// Was not in the cache? creating it....
|
||||
MESSAGE(LOG_DUMP, "\tCreate x87 Cache for ST%d\n", st);
|
||||
// get a free spot
|
||||
int ret = -1;
|
||||
for (int i=0; (i<8) && (ret==-1); ++i)
|
||||
if(dyn->x87cache[i]==-1)
|
||||
ret = i;
|
||||
// found, setup and grab the value
|
||||
dyn->x87cache[ret] = st;
|
||||
dyn->x87reg[ret] = fpu_get_reg_x87(dyn);
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, mmx87));
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
int a = st - dyn->x87stack;
|
||||
if(a<0) {
|
||||
SUBw_U12(s2, s2, -a);
|
||||
} else {
|
||||
ADDw_U12(s2, s2, a);
|
||||
}
|
||||
ANDw_mask(s2, s2, 0b011111, 1); // (emu->top + i)&7
|
||||
VLDR64_REG_LSL3(dyn->x87reg[ret], s1, s2);
|
||||
MESSAGE(LOG_DUMP, "\t-------x87 Cache for ST%d\n", st);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int round_map[] = {0, 2, 1, 3}; // map x64 -> arm round flag
|
||||
|
||||
// Set rounding according to cw flags, return reg to restore flags
|
||||
int x87_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
LDRH_U12(s1, xEmu, offsetof(x64emu_t, cw));
|
||||
UBFXx(s2, s1, 10, 2); // extract round...
|
||||
MOV64x(s1, (uintptr_t)round_map);
|
||||
LDRw_REG_LSL2(s2, s1, s2);
|
||||
VMRS(s1); // get fpscr
|
||||
MOVx_REG(s3, s1);
|
||||
BFIx(s1, s2, 22, 2); // inject new round
|
||||
VMSR(s1); // put new fpscr
|
||||
return s3;
|
||||
}
|
||||
|
||||
// Set rounding according to mxcsr flags, return reg to restore flags
|
||||
int sse_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
LDRH_U12(s1, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
UBFXx(s2, s1, 13, 2); // extract round...
|
||||
MOV64x(s1, (uintptr_t)round_map);
|
||||
LDRw_REG_LSL2(s2, s1, s2);
|
||||
VMRS(s1); // get fpscr
|
||||
MOVx_REG(s3, s1);
|
||||
BFIx(s1, s2, 22, 2); // inject new round
|
||||
VMSR(s1); // put new fpscr
|
||||
return s3;
|
||||
}
|
||||
|
||||
// Restore round flag
|
||||
void x87_restoreround(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
VMSR(s1); // put back fpscr
|
||||
}
|
||||
|
||||
// MMX helpers
|
||||
static void mmx_reset(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
#if STEP > 1
|
||||
for (int i=0; i<8; ++i)
|
||||
dyn->mmxcache[i] = -1;
|
||||
#endif
|
||||
}
|
||||
// get neon register for a MMX reg, create the entry if needed
|
||||
int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a)
|
||||
{
|
||||
#if STEP > 1
|
||||
if(dyn->mmxcache[a]!=-1)
|
||||
return dyn->mmxcache[a];
|
||||
int ret = dyn->mmxcache[a] = fpu_get_reg_emm(dyn, a);
|
||||
VLDR64_U12(ret, xEmu, offsetof(x64emu_t, mmx87[a]));
|
||||
return ret;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
// get neon register for a MMX reg, but don't try to synch it if it needed to be created
|
||||
int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a)
|
||||
{
|
||||
#if STEP > 1
|
||||
if(dyn->mmxcache[a]!=-1)
|
||||
return dyn->mmxcache[a];
|
||||
int ret = dyn->mmxcache[a] = fpu_get_reg_emm(dyn, a);
|
||||
return ret;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
// purge the MMX cache only(needs 3 scratch registers)
|
||||
static void mmx_purgecache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
#if STEP > 1
|
||||
int old = -1;
|
||||
for (int i=0; i<8; ++i)
|
||||
if(dyn->mmxcache[i]!=-1) {
|
||||
if (old==-1) {
|
||||
MESSAGE(LOG_DUMP, "\tPurge MMX Cache ------\n");
|
||||
++old;
|
||||
}
|
||||
VSTR64_U12(dyn->mmxcache[i], xEmu, offsetof(x64emu_t, mmx87[i]));
|
||||
fpu_free_reg(dyn, dyn->mmxcache[i]);
|
||||
dyn->mmxcache[i] = -1;
|
||||
}
|
||||
if(old!=-1) {
|
||||
MESSAGE(LOG_DUMP, "\t------ Purge MMX Cache\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_TRACE
|
||||
static void mmx_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
#if STEP > 1
|
||||
for (int i=0; i<8; ++i)
|
||||
if(dyn->mmxcache[i]!=-1) {
|
||||
VLDR64_U12(dyn->mmxcache[i], xEmu, offsetof(x64emu_t, mmx87[i]));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// SSE / SSE2 helpers
|
||||
static void sse_reset(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
#if STEP > 1
|
||||
for (int i=0; i<16; ++i)
|
||||
dyn->ssecache[i] = -1;
|
||||
#endif
|
||||
}
|
||||
// get neon register for a SSE reg, create the entry if needed
|
||||
int sse_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a)
|
||||
{
|
||||
#if STEP > 1
|
||||
if(dyn->ssecache[a]!=-1)
|
||||
return dyn->ssecache[a];
|
||||
int ret = dyn->ssecache[a] = fpu_get_reg_xmm(dyn, a);
|
||||
VLDR128_U12(ret, xEmu, offsetof(x64emu_t, xmm[a]));
|
||||
return ret;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
// get neon register for a SSE reg, but don't try to synch it if it needed to be created
|
||||
int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a)
|
||||
{
|
||||
#if STEP > 1
|
||||
if(dyn->ssecache[a]!=-1)
|
||||
return dyn->ssecache[a];
|
||||
int ret = dyn->ssecache[a] = fpu_get_reg_xmm(dyn, a);
|
||||
return ret;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
// purge the SSE cache for XMM0..XMM7 (to use before function native call)
|
||||
void sse_purge07cache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
#if STEP > 1
|
||||
int old = -1;
|
||||
for (int i=0; i<8; ++i)
|
||||
if(dyn->ssecache[i]!=-1) {
|
||||
if (old==-1) {
|
||||
MESSAGE(LOG_DUMP, "\tPurge XMM0..7 Cache ------\n");
|
||||
++old;
|
||||
}
|
||||
VSTR128_U12(dyn->ssecache[i], xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
fpu_free_reg(dyn, dyn->ssecache[i]);
|
||||
dyn->ssecache[i] = -1;
|
||||
}
|
||||
if(old!=-1) {
|
||||
MESSAGE(LOG_DUMP, "\t------ Purge XMM0..7 Cache\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// purge the SSE cache only
|
||||
static void sse_purgecache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
#if STEP > 1
|
||||
int old = -1;
|
||||
for (int i=0; i<16; ++i)
|
||||
if(dyn->ssecache[i]!=-1) {
|
||||
if (old==-1) {
|
||||
MESSAGE(LOG_DUMP, "\tPurge SSE Cache ------\n");
|
||||
++old;
|
||||
}
|
||||
VSTR128_U12(dyn->ssecache[i], xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
fpu_free_reg(dyn, dyn->ssecache[i]);
|
||||
dyn->ssecache[i] = -1;
|
||||
}
|
||||
if(old!=-1) {
|
||||
MESSAGE(LOG_DUMP, "\t------ Purge SSE Cache\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_TRACE
|
||||
static void sse_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
#if STEP > 1
|
||||
for (int i=0; i<16; ++i)
|
||||
if(dyn->ssecache[i]!=-1) {
|
||||
VSTR128_U12(dyn->ssecache[i], xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void fpu_pushcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
#if STEP > 1
|
||||
// only SSE regs needs to be push back to xEmu
|
||||
int n=0;
|
||||
for (int i=0; i<16; i++)
|
||||
if(dyn->ssecache[i]!=-1)
|
||||
++n;
|
||||
if(!n)
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tPush XMM Cache (%d)------\n", n);
|
||||
for (int i=0; i<16; ++i)
|
||||
if(dyn->ssecache[i]!=-1) {
|
||||
VSTR128_U12(dyn->ssecache[i], xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t------- Push XMM Cache (%d)\n", n);
|
||||
#endif
|
||||
}
|
||||
|
||||
void fpu_popcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
#if STEP > 1
|
||||
// only SSE regs needs to be pop back from xEmu
|
||||
int n=0;
|
||||
for (int i=0; i<16; i++)
|
||||
if(dyn->ssecache[i]!=-1)
|
||||
++n;
|
||||
if(!n)
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tPop XMM Cache (%d)------\n", n);
|
||||
for (int i=0; i<16; ++i)
|
||||
if(dyn->ssecache[i]!=-1) {
|
||||
VLDR128_U12(dyn->ssecache[i], xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t------- Pop XMM Cache (%d)\n", n);
|
||||
#endif
|
||||
}
|
||||
|
||||
void fpu_purgecache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
x87_purgecache(dyn, ninst, s1, s2, s3);
|
||||
mmx_purgecache(dyn, ninst, s1);
|
||||
sse_purgecache(dyn, ninst, s1);
|
||||
fpu_reset_reg(dyn);
|
||||
}
|
||||
|
||||
#ifdef HAVE_TRACE
|
||||
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
x87_reflectcache(dyn, ninst, s1, s2, s3);
|
||||
if(trace_emm)
|
||||
mmx_reflectcache(dyn, ninst, s1);
|
||||
if(trace_xmm)
|
||||
sse_reflectcache(dyn, ninst, s1);
|
||||
}
|
||||
#endif
|
||||
|
||||
void fpu_reset(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
x87_reset(dyn, ninst);
|
||||
mmx_reset(dyn, ninst);
|
||||
sse_reset(dyn, ninst);
|
||||
fpu_reset_reg(dyn);
|
||||
}
|
||||
|
||||
void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
// PF: (((emu->x64emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
ANDw_mask(s3, s1, 0b011011, 0b000010); // mask=0xE0
|
||||
LSRw(s3, s3, 5);
|
||||
MOV64x(s4, (uintptr_t)GetParityTab());
|
||||
LDRw_REG_LSL2(s4, s4, s3);
|
||||
ANDw_mask(s3, s1, 0, 0b000100); //0x1f
|
||||
LSRw_REG(s4, s4, s3);
|
||||
MVNw_REG(s4, s4);
|
||||
BFIw(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
Executable
+944
@@ -0,0 +1,944 @@
|
||||
#ifndef __DYNAREC_ARM64_HELPER_H__
|
||||
#define __DYNAREC_ARM64_HELPER_H__
|
||||
|
||||
// undef to get Close to SSE Float->int conversions
|
||||
//#define PRECISE_CVT
|
||||
|
||||
#if STEP == 0
|
||||
#include "dynarec_arm64_pass0.h"
|
||||
#elif STEP == 1
|
||||
#include "dynarec_arm64_pass1.h"
|
||||
#elif STEP == 2
|
||||
#include "dynarec_arm64_pass2.h"
|
||||
#elif STEP == 3
|
||||
#include "dynarec_arm64_pass3.h"
|
||||
#endif
|
||||
|
||||
#include "debug.h"
|
||||
#include "arm64_emitter.h"
|
||||
#include "../emu/x64primop.h"
|
||||
|
||||
#define F8 *(uint8_t*)(addr++)
|
||||
#define F8S *(int8_t*)(addr++)
|
||||
#define F16 *(uint16_t*)(addr+=2, addr-2)
|
||||
#define F16S *(int16_t*)(addr+=2, addr-2)
|
||||
#define F32 *(uint32_t*)(addr+=4, addr-4)
|
||||
#define F32S *(int32_t*)(addr+=4, addr-4)
|
||||
#define F32S64 (uint64_t)(int64_t)F32S
|
||||
#define F64 *(uint64_t*)(addr+=8, addr-8)
|
||||
#define PK(a) *(uint8_t*)(addr+a)
|
||||
#define PK16(a) *(uint16_t*)(addr+a)
|
||||
#define PK32(a) *(uint32_t*)(addr+a)
|
||||
#define PK64(a) *(uint64_t*)(addr+a)
|
||||
#define PKip(a) *(uint8_t*)(ip+a)
|
||||
|
||||
// GETGD get x64 register in gd
|
||||
#define GETGD gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3)
|
||||
//GETED can use r1 for ed, and r2 for wback. wback is 0 if ed is xEAX..xEDI
|
||||
#define GETED(D) if(MODREG) { \
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, D); \
|
||||
LDRxw_U12(x1, wback, fixedaddress); \
|
||||
ed = x1; \
|
||||
}
|
||||
#define GETEDx(D) if(MODREG) { \
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<3, 3, rex, 0, D); \
|
||||
LDRx_U12(x1, wback, fixedaddress); \
|
||||
ed = x1; \
|
||||
}
|
||||
#define GETEDw(D) if((nextop&0xC0)==0xC0) { \
|
||||
ed = xEAX+(nextop&7)+(rex.b<<3); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<2, 2, rex, 0, D); \
|
||||
LDRw_U12(x1, wback, fixedaddress); \
|
||||
ed = x1; \
|
||||
}
|
||||
//GETEDH can use hint for ed, and r1 or r2 for wback (depending on hint). wback is 0 if ed is xEAX..xEDI
|
||||
#define GETEDH(hint, D) if(MODREG) { \
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, (hint==x2)?x1:x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, D); \
|
||||
LDRxw_U12(hint, wback, fixedaddress); \
|
||||
ed = hint; \
|
||||
}
|
||||
//GETEDW can use hint for wback and ret for ed. wback is 0 if ed is xEAX..xEDI
|
||||
#define GETEDW(hint, ret, D) if(MODREG) { \
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
MOVxw_REG(ret, ed); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, hint, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, D); \
|
||||
ed = ret; \
|
||||
LDRxw_U12(ed, wback, fixedaddress); \
|
||||
}
|
||||
// Write back ed in wback (if wback not 0)
|
||||
#define WBACK if(wback) {STRxw_U12(ed, wback, fixedaddress);}
|
||||
// Write back ed in wback (if wback not 0)
|
||||
#define WBACKx if(wback) {STRx_U12(ed, wback, fixedaddress);}
|
||||
// Write back ed in wback (if wback not 0)
|
||||
#define WBACKw if(wback) {STRw_U12(ed, wback, fixedaddress);}
|
||||
// Send back wb to either ed or wback
|
||||
#define SBACK(wb) if(wback) {STRxw(wb, wback, fixedaddress);} else {MOVxw_REG(ed, wb);}
|
||||
//GETEDO can use r1 for ed, and r2 for wback. wback is 0 if ed is xEAX..xEDI
|
||||
#define GETEDO(O, D) if(MODREG) { \
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, D); \
|
||||
LDRxw_REG(x1, wback, O); \
|
||||
ed = x1; \
|
||||
}
|
||||
#define WBACKO(O) if(wback) {STRxw_REG(ed, wback, O);}
|
||||
//FAKEELike GETED, but doesn't get anything
|
||||
#define FAKEED if(!MODREG) { \
|
||||
addr = fakeed(dyn, addr, ninst, nextop); \
|
||||
}
|
||||
// GETGW extract x64 register in gd, that is i
|
||||
#define GETGW(i) gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3); UXTHw(i, gd); gd = i;
|
||||
// GETGW extract x64 register in gd, that is i, Signed extented
|
||||
#define GETSGW(i) gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3); SXTHw(i, gd); gd = i;
|
||||
//GETEWW will use i for ed, and can use w for wback.
|
||||
#define GETEWW(w, i, D) if(MODREG) { \
|
||||
wback = xRAX+(nextop&7)+(rex.b<<3);\
|
||||
UXTHw(i, wback); \
|
||||
ed = i; \
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, w, &fixedaddress, 0xfff<<1, (1<<1)-1, rex, 0, D); \
|
||||
LDRH_U12(i, wback, fixedaddress); \
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
}
|
||||
//GETEW will use i for ed, and can use r3 for wback.
|
||||
#define GETEW(i, D) if(MODREG) { \
|
||||
wback = xRAX+(nextop&7)+(rex.b<<3);\
|
||||
UXTHw(i, wback); \
|
||||
ed = i; \
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, (1<<1)-1, rex, 0, D); \
|
||||
LDRH_U12(i, wback, fixedaddress); \
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
}
|
||||
//GETSEW will use i for ed, and can use r3 for wback. This is the Signed version
|
||||
#define GETSEW(i, D) if(MODREG) { \
|
||||
wback = xRAX+(nextop&7)+(rex.b<<3);\
|
||||
SXTHw(i, wback); \
|
||||
ed = i; \
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, (1<<1)-1, rex, 0, D); \
|
||||
LDRSHx_U12(i, wback, fixedaddress);\
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
}
|
||||
// Write ed back to original register / memory
|
||||
#define EWBACK if(wb1) {STRH_U12(ed, wback, fixedaddress);} else {BFIx(wback, ed, 0, 16);}
|
||||
// Write w back to original register / memory
|
||||
#define EWBACKW(w) if(wb1) {STRH_U12(w, wback, fixedaddress);} else {BFIx(wback, w, 0, 16);}
|
||||
// Write back gd in correct register
|
||||
#define GWBACK BFIx((xRAX+((nextop&0x38)>>3)+(rex.r<<3)), gd, 0, 16);
|
||||
//GETEB will use i for ed, and can use r3 for wback.
|
||||
#define GETEB(i, D) if(MODREG) { \
|
||||
if(rex.rex) { \
|
||||
wback = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
wb2 = 0; \
|
||||
} else { \
|
||||
wback = (nextop&7); \
|
||||
wb2 = (wback>>2)*8; \
|
||||
wback = xRAX+(wback&3); \
|
||||
} \
|
||||
UBFXx(i, wback, wb2, 8); \
|
||||
wb1 = 0; \
|
||||
ed = i; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff, 0, rex, 0, D); \
|
||||
LDRB_U12(i, wback, fixedaddress); \
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
}
|
||||
//GETEBO will use i for ed, i is also Offset, and can use r3 for wback.
|
||||
#define GETEBO(i) if((nextop&0xC0)==0xC0) { \
|
||||
wback = (nextop&7); \
|
||||
wb2 = (wback>>2); \
|
||||
wback = xEAX+(wback&3); \
|
||||
UBFXx(i, wback, wb2, 8);\
|
||||
wb1 = 0; \
|
||||
ed = i; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0); \
|
||||
ADD_REG_LSL_IMM5(wback, wback, i, 0); \
|
||||
LDRB_IMM9(i, wback, fixedaddress); \
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
}
|
||||
//GETSEB sign extend EB, will use i for ed, and can use r3 for wback.
|
||||
#define GETSEB(i, D) if(MODREG) { \
|
||||
if(rex.rex) { \
|
||||
wback = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
wb2 = 0; \
|
||||
} else { \
|
||||
wback = (nextop&7); \
|
||||
wb2 = (wback>>2)*8; \
|
||||
wback = xRAX+(wback&3); \
|
||||
} \
|
||||
SBFXx(i, wback, wb2, 8); \
|
||||
wb1 = 0; \
|
||||
ed = i; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff, 0, rex, 0, D); \
|
||||
LDRSBx_U12(i, wback, fixedaddress); \
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
}
|
||||
// Write eb (ed) back to original register / memory
|
||||
#define EBBACK if(wb1) {STRB_U12(ed, wback, fixedaddress);} else {BFIx(wback, ed, wb2, 8);}
|
||||
//GETGB will use i for gd
|
||||
#define GETGB(i) if(rex.rex) { \
|
||||
gb1 = xRAX+((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
gb2 = 0; \
|
||||
} else { \
|
||||
gd = (nextop&0x38)>>3; \
|
||||
gb2 = ((gd&4)>>2); \
|
||||
gb1 = xRAX+(gd&3); \
|
||||
} \
|
||||
gd = i; \
|
||||
UBFXx(gd, gb1, gb2, 8);
|
||||
//GETSGB signe extend GB, will use i for gd
|
||||
#define GETSGB(i) if(rex.rex) { \
|
||||
gb1 = xRAX+((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
gb2 = 0; \
|
||||
} else { \
|
||||
gd = (nextop&0x38)>>3; \
|
||||
gb2 = ((gd&4)>>2); \
|
||||
gb1 = xRAX+(gd&3); \
|
||||
} \
|
||||
gd = i; \
|
||||
SBFXx(gd, gb1, gb2, 8);
|
||||
// Write gb (gd) back to original register / memory
|
||||
#define GBBACK BFIx(gb1, gd, gb2, 8);
|
||||
|
||||
// Get Direction with size Z and based of F_DF flag, on register r ready for LDR/STR fetching
|
||||
// F_DF is 1<<10, so 1 ROR 11*2 (so F_OF)
|
||||
#define GETDIR(r, A) \
|
||||
MOV32w(r, A); /* mask=1<<10 */ \
|
||||
TSTw_mask(xFlags, 0b010110, 0); \
|
||||
CNEGx(r, r, cNE)
|
||||
|
||||
// CALL will use x7 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// R0 will not be pushed/popd if ret is -2
|
||||
#define CALL(F, ret) call_c(dyn, ninst, F, x7, ret, 1, 0)
|
||||
// CALL_ will use x7 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// R0 will not be pushed/popd if ret is -2
|
||||
#define CALL_(F, ret, reg) call_c(dyn, ninst, F, x7, ret, 1, reg)
|
||||
// CALL_S will use x7 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// R0 will not be pushed/popd if ret is -2. Flags are not save/restored
|
||||
#define CALL_S(F, ret) call_c(dyn, ninst, F, x7, ret, 0, 0)
|
||||
|
||||
#define MARK if(dyn->insts) {dyn->insts[ninst].mark = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARK ((dyn->insts)?dyn->insts[ninst].mark:(dyn->arm_size+4))
|
||||
#define MARK2 if(dyn->insts) {dyn->insts[ninst].mark2 = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARK2 ((dyn->insts)?dyn->insts[ninst].mark2:(dyn->arm_size+4))
|
||||
#define MARK3 if(dyn->insts) {dyn->insts[ninst].mark3 = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARK3 ((dyn->insts)?dyn->insts[ninst].mark3:(dyn->arm_size+4))
|
||||
#define MARKF if(dyn->insts) {dyn->insts[ninst].markf = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARKF ((dyn->insts)?dyn->insts[ninst].markf:(dyn->arm_size+4))
|
||||
#define MARKSEG if(dyn->insts) {dyn->insts[ninst].markseg = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARKSEG ((dyn->insts)?dyn->insts[ninst].markseg:(dyn->arm_size+4))
|
||||
#define MARKLOCK if(dyn->insts) {dyn->insts[ninst].marklock = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARKLOCK ((dyn->insts)?dyn->insts[ninst].marklock:(dyn->arm_size+4))
|
||||
|
||||
// Branch to MARK if cond (use j32)
|
||||
#define B_MARK(cond) \
|
||||
j32 = GETMARK-(dyn->arm_size); \
|
||||
Bcond(cond, j32)
|
||||
// Branch to MARK unconditionnal (use j32)
|
||||
#define B_MARK_nocond \
|
||||
j32 = GETMARK-(dyn->arm_size); \
|
||||
B(j32)
|
||||
// Branch to MARK if reg is not 0 (use j32)
|
||||
#define CBNZx_MARK(reg) \
|
||||
j32 = GETMARK-(dyn->arm_size); \
|
||||
CBNZx(reg, j32)
|
||||
// Branch to MARK if reg is not 0 (use j32)
|
||||
#define CBNZw_MARK(reg) \
|
||||
j32 = GETMARK-(dyn->arm_size); \
|
||||
CBNZw(reg, j32)
|
||||
// Branch to MARK2 if cond (use j32)
|
||||
#define B_MARK2(cond) \
|
||||
j32 = GETMARK2-(dyn->arm_size); \
|
||||
Bcond(cond, j32)
|
||||
// Branch to MARK2 unconditionnal (use j32)
|
||||
#define B_MARK2_nocond \
|
||||
j32 = GETMARK2-(dyn->arm_size); \
|
||||
B(j32)
|
||||
// Branch to MARK2 if reg is not 0 (use j32)
|
||||
#define CBNZx_MARK2(reg) \
|
||||
j32 = GETMARK2-(dyn->arm_size); \
|
||||
CBNZx(reg, j32)
|
||||
// Test bit N of A and branch to MARK2 if set
|
||||
#define TBNZ_MARK2(A, N) \
|
||||
j32 = GETMARK2-(dyn->arm_size); \
|
||||
TBNZ(A, N, j32)
|
||||
// Branch to MARK3 if cond (use j32)
|
||||
#define B_MARK3(cond) \
|
||||
j32 = GETMARK3-(dyn->arm_size); \
|
||||
Bcond(cond, j32)
|
||||
// Branch to MARK3 unconditionnal (use j32)
|
||||
#define B_MARK3_nocond \
|
||||
j32 = GETMARK3-(dyn->arm_size); \
|
||||
B(j32)
|
||||
// Branch to MARK3 if reg is not 0 (use j32)
|
||||
#define CBNZx_MARK3(reg) \
|
||||
j32 = GETMARK3-(dyn->arm_size); \
|
||||
CBNZx(reg, j32)
|
||||
// Test bit N of A and branch to MARK3 if set
|
||||
#define TBNZ_MARK3(A, N) \
|
||||
j32 = GETMARK3-(dyn->arm_size); \
|
||||
TBNZ(A, N, j32)
|
||||
// Test bit N of A and branch to MARK3 if not set
|
||||
#define TBZ_MARK3(A, N) \
|
||||
j32 = GETMARK3-(dyn->arm_size); \
|
||||
TBZ(A, N, j32)
|
||||
// Branch to next instruction if cond (use j32)
|
||||
#define B_NEXT(cond) \
|
||||
j32 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->arm_size)):0; \
|
||||
Bcond(cond, j32)
|
||||
// Branch to next instruction unconditionnal (use j32)
|
||||
#define B_NEXT_nocond \
|
||||
j32 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->arm_size)):0;\
|
||||
B(j32)
|
||||
// Branch to next instruction if reg is 0 (use j32)
|
||||
#define CBZw_NEXT(reg) \
|
||||
j32 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->arm_size)):0; \
|
||||
CBZw(reg, j32)
|
||||
// Branch to next instruction if reg is 0 (use j32)
|
||||
#define CBZx_NEXT(reg) \
|
||||
j32 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->arm_size)):0; \
|
||||
CBZx(reg, j32)
|
||||
// Branch to MARKSEG if cond (use j32)
|
||||
#define B_MARKSEG(cond) \
|
||||
j32 = GETMARKSEG-(dyn->arm_size); \
|
||||
Bcond(cond, j32)
|
||||
// Branch to MARKSEG if reg is 0 (use j32)
|
||||
#define CBZw_MARKSEG(reg) \
|
||||
j32 = GETMARKSEG-(dyn->arm_size); \
|
||||
CBZw(reg, j32)
|
||||
// Branch to MARKSEG if reg is not 0 (use j32)
|
||||
#define CBNZw_MARKSEG(reg) \
|
||||
j32 = GETMARKSEG-(dyn->arm_size); \
|
||||
CBNZw(reg, j32)
|
||||
// Branch to MARKLOCK if cond (use j32)
|
||||
#define B_MARKLOCK(cond) \
|
||||
j32 = GETMARKLOCK-(dyn->arm_size); \
|
||||
Bcond(cond, j32)
|
||||
// Branch to MARKLOCK if reg is not 0 (use j32)
|
||||
#define CBNZx_MARKLOCK(reg) \
|
||||
j32 = GETMARKLOCK-(dyn->arm_size); \
|
||||
CBNZx(reg, j32)
|
||||
|
||||
#define IFX(A) if(dyn->insts && (dyn->insts[ninst].x64.need_flags&(A)))
|
||||
#define IFXX(A) if(dyn->insts && (dyn->insts[ninst].x64.need_flags==(A)))
|
||||
#define IFX2X(A, B) if(dyn->insts && (dyn->insts[ninst].x64.need_flags==(A) || dyn->insts[ninst].x64.need_flags==(B) || dyn->insts[ninst].x64.need_flags==((A)|(B))))
|
||||
#define IFXN(A, B) if(dyn->insts && (dyn->insts[ninst].x64.need_flags&(A) && !(dyn->insts[ninst].x64.need_flags&(B))))
|
||||
|
||||
// Generate FCOM with s1 and s2 scratch regs (the VCMP is already done)
|
||||
#define FCOM(s1, s2, s3) \
|
||||
LDRH_U12(s3, xEmu, offsetof(x64emu_t, sw)); /*offset is 8bits right?*/\
|
||||
MOV32w(s1, 0b01000111); \
|
||||
BICw_REG_LSL(s3, s3, s1, 8); \
|
||||
CSETw(s1, cMI); /* 1 if less than, 0 else */ \
|
||||
MOV32w(s2, 0b01000101); /* unordered */ \
|
||||
CSELw(s1, s2, s1, cVS); \
|
||||
MOV32w(s2, 0b01000000); /* zero */ \
|
||||
CSELw(s1, s2, s1, cEQ); \
|
||||
/* greater than leave 0 */ \
|
||||
ORRw_REG_LSL(s3, s3, s1, 8); \
|
||||
STRH_U12(s3, xEmu, offsetof(x64emu_t, sw))
|
||||
|
||||
// Generate FCOMI with s1 and s2 scratch regs (the VCMP is already done)
|
||||
#define FCOMI(s1, s2) \
|
||||
IFX(X_CF|X_PF|X_ZF|X_PEND) { \
|
||||
MOV32w(s2, 0b01000101); \
|
||||
BICw_REG(xFlags, xFlags, s2); \
|
||||
CSETw(s1, cMI); /* 1 if less than, 0 else */ \
|
||||
/*s2 already set */ /* unordered */ \
|
||||
CSELw(s1, s2, s1, cVS); \
|
||||
MOV32w(s2, 0b01000000); /* zero */ \
|
||||
CSELw(s1, s2, s1, cEQ); \
|
||||
/* greater than leave 0 */ \
|
||||
ORRw_REG(xFlags, xFlags, s1); \
|
||||
} \
|
||||
SET_DFNONE(s1); \
|
||||
IFX(X_OF|X_PEND) { \
|
||||
BFCw(xFlags, F_OF, 1); \
|
||||
} \
|
||||
IFX(X_AF|X_PEND) { \
|
||||
BFCw(xFlags, F_AF, 1); \
|
||||
} \
|
||||
IFX(X_SF|X_PEND) { \
|
||||
BFCw(xFlags, F_SF, 1); \
|
||||
} \
|
||||
|
||||
|
||||
#define STORE_REG(A) STRx_U12(x##A, xEmu, offsetof(x64emu_t, regs[_##A]))
|
||||
#define STORE_XEMU_REGS(A) \
|
||||
STORE_REG(RAX); \
|
||||
STORE_REG(RCX); \
|
||||
STORE_REG(RDX); \
|
||||
STORE_REG(RBX); \
|
||||
STORE_REG(RSP); \
|
||||
STORE_REG(RBP); \
|
||||
STORE_REG(RSI); \
|
||||
STORE_REG(RDI); \
|
||||
STORE_REG(R8); \
|
||||
STORE_REG(R9); \
|
||||
STORE_REG(R10); \
|
||||
STORE_REG(R11); \
|
||||
STORE_REG(R12); \
|
||||
STORE_REG(R13); \
|
||||
STORE_REG(R14); \
|
||||
STORE_REG(R15); \
|
||||
STRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags)); \
|
||||
if(A) {STRx_U12(A, xEmu, offsetof(x64emu_t, ip));}
|
||||
|
||||
#define LOAD_REG(A) LDRx_U12(x##A, xEmu, offsetof(x64emu_t, regs[_##A]))
|
||||
#define LOAD_XEMU_REGS(A) \
|
||||
LOAD_REG(RAX); \
|
||||
LOAD_REG(RCX); \
|
||||
LOAD_REG(RDX); \
|
||||
LOAD_REG(RBX); \
|
||||
LOAD_REG(RSP); \
|
||||
LOAD_REG(RBP); \
|
||||
LOAD_REG(RSI); \
|
||||
LOAD_REG(RDI); \
|
||||
LOAD_REG(R8); \
|
||||
LOAD_REG(R9); \
|
||||
LOAD_REG(R10); \
|
||||
LOAD_REG(R11); \
|
||||
LOAD_REG(R12); \
|
||||
LOAD_REG(R13); \
|
||||
LOAD_REG(R14); \
|
||||
LOAD_REG(R15); \
|
||||
LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags)); \
|
||||
if(A) {LDRx_U12(A, xEmu, offsetof(x64emu_t, ip));}
|
||||
|
||||
#define STORE_XEMU_MINIMUM(A) \
|
||||
STORE_REG(RAX); \
|
||||
STORE_REG(RCX); \
|
||||
STORE_REG(RDX); \
|
||||
STORE_REG(RBX); \
|
||||
STORE_REG(RSP); \
|
||||
STORE_REG(RBP); \
|
||||
STORE_REG(RSI); \
|
||||
STORE_REG(RDI); \
|
||||
STORE_REG(R8); \
|
||||
STORE_REG(R9); \
|
||||
STRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags)); \
|
||||
if(A) {STRx_U12(A, xEmu, offsetof(x64emu_t, ip));}
|
||||
|
||||
#define STORE_XEMU_CALL(A) \
|
||||
if(A) {STPx_S7_offset(xFlags, A, xEmu, offsetof(x64emu_t, eflags));} \
|
||||
else {STRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));}
|
||||
|
||||
#define LOAD_XEMU_CALL(A) \
|
||||
if(A) {LDPx_S7_offset(xFlags, A, xEmu, offsetof(x64emu_t, eflags));} \
|
||||
else {LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));}; \
|
||||
if(A==xRIP) dyn->last_ip = 0
|
||||
|
||||
#define SET_DFNONE(S) if(!dyn->dfnone) {MOVZw(S, d_none); STRw_U12(S, xEmu, offsetof(x64emu_t, df)); dyn->dfnone=1;}
|
||||
#define SET_DF(S, N) if((N)!=d_none) {MOVZw(S, (N)); STRw_U12(S, xEmu, offsetof(x64emu_t, df)); dyn->dfnone=0;} else SET_DFNONE(S)
|
||||
#define SET_NODF() dyn->dfnone = 0
|
||||
#define SET_DFOK() dyn->dfnone = 1
|
||||
|
||||
#ifndef READFLAGS
|
||||
#define READFLAGS(A) \
|
||||
if(((A)!=X_PEND) && dyn->state_flags!=SF_SET) { \
|
||||
if(dyn->state_flags!=SF_PENDING) { \
|
||||
LDRw_U12(x3, xEmu, offsetof(x64emu_t, df)); \
|
||||
j32 = (GETMARKF)-(dyn->arm_size); \
|
||||
CBZw(x3, j32); \
|
||||
} \
|
||||
CALL_(UpdateFlags, -1, 0); \
|
||||
MARKF; \
|
||||
dyn->state_flags = SF_SET; \
|
||||
SET_DFOK(); \
|
||||
}
|
||||
#endif
|
||||
#ifndef SETFLAGS
|
||||
#define SETFLAGS(A, B) \
|
||||
if(dyn->state_flags!=SF_SET && B==SF_SUBSET && (dyn->insts[ninst].x64.need_flags&(~((A)|X_PEND)))) \
|
||||
READFLAGS(dyn->insts[ninst].x64.need_flags&(~(A))); \
|
||||
dyn->state_flags = (B==SF_SUBSET)?SF_SET:B
|
||||
#endif
|
||||
#ifndef JUMP
|
||||
#define JUMP(A)
|
||||
#endif
|
||||
#ifndef BARRIER
|
||||
#define BARRIER(A)
|
||||
#endif
|
||||
#ifndef BARRIER_NEXT
|
||||
#define BARRIER_NEXT(A)
|
||||
#endif
|
||||
#define UFLAG_OP1(A) if(dyn->insts && dyn->insts[ninst].x64.need_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, op1));}
|
||||
#define UFLAG_OP2(A) if(dyn->insts && dyn->insts[ninst].x64.need_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, op2));}
|
||||
#define UFLAG_OP12(A1, A2) if(dyn->insts && dyn->insts[ninst].x64.need_flags) {STRxw_U12(A1, xEmu, offsetof(x64emu_t, op1));STRxw_U12(A2, 0, offsetof(x64emu_t, op2));}
|
||||
#define UFLAG_RES(A) if(dyn->insts && dyn->insts[ninst].x64.need_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, res));}
|
||||
#define UFLAG_DF(r, A) if(dyn->insts && dyn->insts[ninst].x64.need_flags) {SET_DF(r, A)}
|
||||
#define UFLAG_IF if(dyn->insts && dyn->insts[ninst].x64.need_flags)
|
||||
#ifndef DEFAULT
|
||||
#define DEFAULT *ok = -1; BARRIER(2)
|
||||
#endif
|
||||
#ifndef NEW_BARRIER_INST
|
||||
#define NEW_BARRIER_INST
|
||||
#endif
|
||||
#ifndef TABLE64
|
||||
#define TABLE64(A, V)
|
||||
#endif
|
||||
|
||||
#if STEP < 2
|
||||
#define GETIP(A)
|
||||
#define GETIP_(A)
|
||||
#else
|
||||
// put value in the Table64 even if not using it for now to avoid difference between Step2 and Step3. Needs to be optimized later...
|
||||
#define GETIP(A) \
|
||||
if(dyn->last_ip && ((A)-dyn->last_ip)<0x1000) { \
|
||||
uint64_t _delta_ip = (A)-dyn->last_ip; \
|
||||
dyn->last_ip += _delta_ip; \
|
||||
if(_delta_ip) { \
|
||||
ADDx_U12(xRIP, xRIP, _delta_ip); \
|
||||
} \
|
||||
} else { \
|
||||
dyn->last_ip = (A); \
|
||||
TABLE64(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 { \
|
||||
TABLE64(xRIP, (A)); \
|
||||
}
|
||||
#endif
|
||||
|
||||
#if STEP < 2
|
||||
#define PASS2IF(A, B) if(A)
|
||||
#elif STEP == 2
|
||||
#define PASS2IF(A, B) if(A) dyn->insts[ninst].pass2choice = B; if(dyn->insts[ninst].pass2choice == B)
|
||||
#else
|
||||
#define PASS2IF(A, B) if(dyn->insts[ninst].pass2choice == B)
|
||||
#endif
|
||||
|
||||
#define MODREG ((nextop&0xC0)==0xC0)
|
||||
|
||||
void arm64_epilog();
|
||||
void* arm64_next(x64emu_t* emu, uintptr_t addr);
|
||||
|
||||
#ifndef STEPNAME
|
||||
#define STEPNAME3(N,M) N##M
|
||||
#define STEPNAME2(N,M) STEPNAME3(N,M)
|
||||
#define STEPNAME(N) STEPNAME2(N, STEP)
|
||||
#endif
|
||||
|
||||
#define arm_pass STEPNAME(arm_pass)
|
||||
|
||||
#define dynarec64_00 STEPNAME(dynarec64_00)
|
||||
#define dynarec64_0F STEPNAME(dynarec64_0F)
|
||||
#define dynarec64_64 STEPNAME(dynarec64_64)
|
||||
#define dynarec64_65 STEPNAME(dynarec64_65)
|
||||
#define dynarec64_66 STEPNAME(dynarec64_66)
|
||||
#define dynarec64_67 STEPNAME(dynarec64_67)
|
||||
#define dynarec64_D8 STEPNAME(dynarec64_D8)
|
||||
#define dynarec64_D9 STEPNAME(dynarec64_D9)
|
||||
#define dynarec64_DA STEPNAME(dynarec64_DA)
|
||||
#define dynarec64_DB STEPNAME(dynarec64_DB)
|
||||
#define dynarec64_DC STEPNAME(dynarec64_DC)
|
||||
#define dynarec64_DD STEPNAME(dynarec64_DD)
|
||||
#define dynarec64_DE STEPNAME(dynarec64_DE)
|
||||
#define dynarec64_DF STEPNAME(dynarec64_DF)
|
||||
#define dynarec64_F0 STEPNAME(dynarec64_F0)
|
||||
#define dynarec64_660F STEPNAME(dynarec64_660F)
|
||||
#define dynarec64_F20F STEPNAME(dynarec64_F20F)
|
||||
#define dynarec64_F30F STEPNAME(dynarec64_F30F)
|
||||
|
||||
#define geted STEPNAME(geted_)
|
||||
#define geted16 STEPNAME(geted16_)
|
||||
#define jump_to_epilog STEPNAME(jump_to_epilog_)
|
||||
#define jump_to_next STEPNAME(jump_to_next_)
|
||||
#define ret_to_epilog STEPNAME(ret_to_epilog_)
|
||||
#define retn_to_epilog STEPNAME(retn_to_epilog_)
|
||||
#define iret_to_epilog STEPNAME(iret_to_epilog_)
|
||||
#define call_c STEPNAME(call_c_)
|
||||
#define grab_segdata STEPNAME(grab_segdata_)
|
||||
#define emit_cmp8 STEPNAME(emit_cmp8)
|
||||
#define emit_cmp16 STEPNAME(emit_cmp16)
|
||||
#define emit_cmp32 STEPNAME(emit_cmp32)
|
||||
#define emit_cmp8_0 STEPNAME(emit_cmp8_0)
|
||||
#define emit_cmp16_0 STEPNAME(emit_cmp16_0)
|
||||
#define emit_cmp32_0 STEPNAME(emit_cmp32_0)
|
||||
#define emit_test8 STEPNAME(emit_test8)
|
||||
#define emit_test16 STEPNAME(emit_test16)
|
||||
#define emit_test32 STEPNAME(emit_test32)
|
||||
#define emit_add32 STEPNAME(emit_add32)
|
||||
#define emit_add32c STEPNAME(emit_add32c)
|
||||
#define emit_add8 STEPNAME(emit_add8)
|
||||
#define emit_add8c STEPNAME(emit_add8c)
|
||||
#define emit_sub32 STEPNAME(emit_sub32)
|
||||
#define emit_sub32c STEPNAME(emit_sub32c)
|
||||
#define emit_sub8 STEPNAME(emit_sub8)
|
||||
#define emit_sub8c STEPNAME(emit_sub8c)
|
||||
#define emit_or32 STEPNAME(emit_or32)
|
||||
#define emit_or32c STEPNAME(emit_or32c)
|
||||
#define emit_xor32 STEPNAME(emit_xor32)
|
||||
#define emit_xor32c STEPNAME(emit_xor32c)
|
||||
#define emit_and32 STEPNAME(emit_and32)
|
||||
#define emit_and32c STEPNAME(emit_and32c)
|
||||
#define emit_or8 STEPNAME(emit_or8)
|
||||
#define emit_or8c STEPNAME(emit_or8c)
|
||||
#define emit_xor8 STEPNAME(emit_xor8)
|
||||
#define emit_xor8c STEPNAME(emit_xor8c)
|
||||
#define emit_and8 STEPNAME(emit_and8)
|
||||
#define emit_and8c STEPNAME(emit_and8c)
|
||||
#define emit_add16 STEPNAME(emit_add16)
|
||||
#define emit_add16c STEPNAME(emit_add16c)
|
||||
#define emit_sub16 STEPNAME(emit_sub16)
|
||||
#define emit_sub16c STEPNAME(emit_sub16c)
|
||||
#define emit_or16 STEPNAME(emit_or16)
|
||||
#define emit_or16c STEPNAME(emit_or16c)
|
||||
#define emit_xor16 STEPNAME(emit_xor16)
|
||||
#define emit_xor16c STEPNAME(emit_xor16c)
|
||||
#define emit_and16 STEPNAME(emit_and16)
|
||||
#define emit_and16c STEPNAME(emit_and16c)
|
||||
#define emit_inc32 STEPNAME(emit_inc32)
|
||||
#define emit_inc16 STEPNAME(emit_inc16)
|
||||
#define emit_inc8 STEPNAME(emit_inc8)
|
||||
#define emit_dec32 STEPNAME(emit_dec32)
|
||||
#define emit_dec16 STEPNAME(emit_dec16)
|
||||
#define emit_dec8 STEPNAME(emit_dec8)
|
||||
#define emit_adc32 STEPNAME(emit_adc32)
|
||||
#define emit_adc32c STEPNAME(emit_adc32c)
|
||||
#define emit_adc8 STEPNAME(emit_adc8)
|
||||
#define emit_adc8c STEPNAME(emit_adc8c)
|
||||
#define emit_adc16 STEPNAME(emit_adc16)
|
||||
#define emit_adc16c STEPNAME(emit_adc16c)
|
||||
#define emit_sbb32 STEPNAME(emit_sbb32)
|
||||
#define emit_sbb32c STEPNAME(emit_sbb32c)
|
||||
#define emit_sbb8 STEPNAME(emit_sbb8)
|
||||
#define emit_sbb8c STEPNAME(emit_sbb8c)
|
||||
#define emit_sbb16 STEPNAME(emit_sbb16)
|
||||
#define emit_sbb16c STEPNAME(emit_sbb16c)
|
||||
#define emit_neg32 STEPNAME(emit_neg32)
|
||||
#define emit_neg16 STEPNAME(emit_neg16)
|
||||
#define emit_neg8 STEPNAME(emit_neg8)
|
||||
#define emit_shl32 STEPNAME(emit_shl32)
|
||||
#define emit_shl32c STEPNAME(emit_shl32c)
|
||||
#define emit_shr32 STEPNAME(emit_shr32)
|
||||
#define emit_shr32c STEPNAME(emit_shr32c)
|
||||
#define emit_sar32c STEPNAME(emit_sar32c)
|
||||
#define emit_rol32c STEPNAME(emit_rol32c)
|
||||
#define emit_ror32c STEPNAME(emit_ror32c)
|
||||
#define emit_shrd32c STEPNAME(emit_shrd32c)
|
||||
#define emit_shld32c STEPNAME(emit_shld32c)
|
||||
|
||||
#define emit_pf STEPNAME(emit_pf)
|
||||
|
||||
#define x87_do_push STEPNAME(x87_do_push)
|
||||
#define x87_do_push_empty STEPNAME(x87_do_push_empty)
|
||||
#define x87_do_pop STEPNAME(x87_do_pop)
|
||||
#define x87_get_cache STEPNAME(x87_get_cache)
|
||||
#define x87_get_st STEPNAME(x87_get_st)
|
||||
#define x87_refresh STEPNAME(x87_refresh)
|
||||
#define x87_forget STEPNAME(x87_forget)
|
||||
#define x87_reget_st STEPNAME(x87_reget_st)
|
||||
#define x87_stackcount STEPNAME(x87_stackcount)
|
||||
#define x87_setround STEPNAME(x87_setround)
|
||||
#define x87_restoreround STEPNAME(x87_restoreround)
|
||||
#define sse_setround STEPNAME(sse_setround)
|
||||
#define mmx_get_reg STEPNAME(mmx_get_reg)
|
||||
#define mmx_get_reg_empty STEPNAME(mmx_get_reg_empty)
|
||||
#define sse_get_reg STEPNAME(sse_get_reg)
|
||||
#define sse_get_reg_empty STEPNAME(sse_get_reg_empty)
|
||||
#define sse_purge07cache STEPNAME(sse_purge07cache)
|
||||
|
||||
#define fpu_pushcache STEPNAME(fpu_pushcache)
|
||||
#define fpu_popcache STEPNAME(fpu_popcache)
|
||||
#define fpu_reset STEPNAME(fpu_reset)
|
||||
#define fpu_purgecache STEPNAME(fpu_purgecache)
|
||||
#ifdef HAVE_TRACE
|
||||
#define fpu_reflectcache STEPNAME(fpu_reflectcache)
|
||||
#endif
|
||||
|
||||
/* setup r2 to address pointed by */
|
||||
uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixaddress, int absmax, uint32_t mask, rex_t rex, int s, int delta);
|
||||
|
||||
/* setup r2 to address pointed by */
|
||||
uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixaddress, int absmax, uint32_t mask, int s);
|
||||
|
||||
|
||||
// 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);
|
||||
void ret_to_epilog(dynarec_arm_t* dyn, int ninst);
|
||||
void retn_to_epilog(dynarec_arm_t* dyn, int ninst, int n);
|
||||
void iret_to_epilog(dynarec_arm_t* dyn, int ninst);
|
||||
void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int save_reg);
|
||||
void grab_segdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg, int segment);
|
||||
void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_cmp32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4);
|
||||
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
void emit_add32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
void emit_add32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5);
|
||||
void emit_add8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_add8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_sub32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
void emit_sub32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5);
|
||||
void emit_sub8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_sub8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4, int s5);
|
||||
void emit_or32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
void emit_or32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4);
|
||||
void emit_xor32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
void emit_xor32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4);
|
||||
void emit_and32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
void emit_and32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4);
|
||||
void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_add16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
//void emit_add16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_sub16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
//void emit_sub16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
//void emit_or16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
//void emit_xor16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
//void emit_and16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_inc32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4);
|
||||
void emit_inc16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_inc8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_dec32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4);
|
||||
void emit_dec16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_dec8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_adc32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
//void emit_adc32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_adc8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_adc8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4, int s5);
|
||||
void emit_adc16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
//void emit_adc16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_sbb32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
//void emit_sbb32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_sbb8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_sbb8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4, int s5);
|
||||
void emit_sbb16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
//void emit_sbb16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_neg32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4);
|
||||
void emit_neg16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_neg8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_shl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
void emit_shl32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, int s3, int s4);
|
||||
void emit_shr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
void emit_shr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, int s3, int s4);
|
||||
void emit_sar32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, int s3, int s4);
|
||||
void emit_rol32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, int s3, int s4);
|
||||
void emit_ror32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int32_t c, int s3, int s4);
|
||||
//void emit_shrd32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4);
|
||||
//void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4);
|
||||
|
||||
void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
|
||||
// x87 helper
|
||||
// cache of the local stack counter, to avoid upadte at every call
|
||||
void x87_stackcount(dynarec_arm_t* dyn, int ninst, int scratch);
|
||||
// fpu push. Return the Dd value to be used
|
||||
int x87_do_push(dynarec_arm_t* dyn, int ninst);
|
||||
// fpu push. Do not allocate a cache register. Needs a scratch register to do x87stack synch (or 0 to not do it)
|
||||
void x87_do_push_empty(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
// fpu pop. All previous returned Dd should be considered invalid
|
||||
void x87_do_pop(dynarec_arm_t* dyn, int ninst);
|
||||
// get cache index for a x87 reg, create the entry if needed
|
||||
int x87_get_cache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a);
|
||||
// get vfpu register for a x87 reg, create the entry if needed
|
||||
int x87_get_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a);
|
||||
// refresh a value from the cache ->emu (nothing done if value is not cached)
|
||||
void x87_refresh(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st);
|
||||
// refresh a value from the cache ->emu and then forget the cache (nothing done if value is not cached)
|
||||
void x87_forget(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st);
|
||||
// refresh the cache value from emu
|
||||
void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st);
|
||||
// Set rounding according to cw flags, return reg to restore flags
|
||||
int x87_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
// Restore round flag
|
||||
void x87_restoreround(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
// Set rounding according to mxcsr flags, return reg to restore flags
|
||||
int sse_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
|
||||
//MMX helpers
|
||||
// get neon register for a MMX reg, create the entry if needed
|
||||
int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a);
|
||||
// get neon register for a MMX reg, but don't try to synch it if it needed to be created
|
||||
int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a);
|
||||
|
||||
//SSE/SSE2 helpers
|
||||
// get neon register for a SSE reg, create the entry if needed
|
||||
int sse_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a);
|
||||
// get neon register for a SSE reg, but don't try to synch it if it needed to be created
|
||||
int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a);
|
||||
// purge the XMM0..XMM7 cache (before function call)
|
||||
void sse_purge07cache(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
|
||||
// common coproc helpers
|
||||
// reset the cache
|
||||
void fpu_reset(dynarec_arm_t* dyn, int ninst);
|
||||
// purge the FPU cache (needs 3 scratch registers)
|
||||
void fpu_purgecache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
#ifdef HAVE_TRACE
|
||||
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
#endif
|
||||
void fpu_pushcache(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
void fpu_popcache(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
|
||||
uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep,int* ok, int* need_epilog);
|
||||
//uintptr_t dynarec64_65(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep,int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
//uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
//uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
//uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
//uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
//uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
//uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
//uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
//uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
|
||||
|
||||
#if STEP < 2
|
||||
#define PASS2(A)
|
||||
#else
|
||||
#define PASS2(A) A
|
||||
#endif
|
||||
|
||||
#if STEP < 3
|
||||
#define PASS3(A)
|
||||
#else
|
||||
#define PASS3(A) A
|
||||
#endif
|
||||
|
||||
#if STEP < 3
|
||||
#define MAYUSE(A) (void)A
|
||||
#else
|
||||
#define MAYUSE(A)
|
||||
#endif
|
||||
|
||||
#define GOCOND(B, T1, T2) \
|
||||
case B+0x0: \
|
||||
INST_NAME(T1 "O " T2); \
|
||||
GO( TSTw_mask(xFlags, 0b010101, 0) \
|
||||
, cEQ, cNE, X_OF) \
|
||||
break; \
|
||||
case B+0x1: \
|
||||
INST_NAME(T1 "NO " T2); \
|
||||
GO( TSTw_mask(xFlags, 0b010101, 0) \
|
||||
, cNE, cEQ, X_OF) \
|
||||
break; \
|
||||
case B+0x2: \
|
||||
INST_NAME(T1 "C " T2); \
|
||||
GO( TSTw_mask(xFlags, 0, 0) \
|
||||
, cEQ, cNE, X_CF) \
|
||||
break; \
|
||||
case B+0x3: \
|
||||
INST_NAME(T1 "NC " T2); \
|
||||
GO( TSTw_mask(xFlags, 0, 0) \
|
||||
, cNE, cEQ, X_CF) \
|
||||
break; \
|
||||
case B+0x4: \
|
||||
INST_NAME(T1 "Z " T2); \
|
||||
GO( TSTw_mask(xFlags, 0b011010, 0) \
|
||||
, cEQ, cNE, X_ZF) \
|
||||
break; \
|
||||
case B+0x5: \
|
||||
INST_NAME(T1 "NZ " T2); \
|
||||
GO( TSTw_mask(xFlags, 0b011010, 0) \
|
||||
, cNE, cEQ, X_ZF) \
|
||||
break; \
|
||||
case B+0x6: \
|
||||
INST_NAME(T1 "BE " T2); \
|
||||
GO( MOV32w(x1, (1<<F_CF)|(1<<F_ZF)); \
|
||||
TSTw_REG(xFlags, x1) \
|
||||
, cEQ, cNE, X_CF|X_ZF) \
|
||||
break; \
|
||||
case B+0x7: \
|
||||
INST_NAME(T1 "NBE " T2); \
|
||||
GO( MOV32w(x1, (1<<F_CF)|(1<<F_ZF)); \
|
||||
TSTw_REG(xFlags, x1) \
|
||||
, cNE, cEQ, X_CF|X_ZF) \
|
||||
break; \
|
||||
case B+0x8: \
|
||||
INST_NAME(T1 "S " T2); \
|
||||
GO( TSTw_mask(xFlags, 0b011001, 0) \
|
||||
, cEQ, cNE, X_SF) \
|
||||
break; \
|
||||
case B+0x9: \
|
||||
INST_NAME(T1 "NS " T2); \
|
||||
GO( TSTw_mask(xFlags, 0b011001, 0) \
|
||||
, cNE, cEQ, X_SF) \
|
||||
break; \
|
||||
case B+0xA: \
|
||||
INST_NAME(T1 "P " T2); \
|
||||
GO( TSTw_mask(xFlags, 0b011110, 0) \
|
||||
, cEQ, cNE, X_PF) \
|
||||
break; \
|
||||
case B+0xB: \
|
||||
INST_NAME(T1 "NP " T2); \
|
||||
GO( TSTw_mask(xFlags, 0b011110, 0) \
|
||||
, cNE, cEQ, X_PF) \
|
||||
break; \
|
||||
case B+0xC: \
|
||||
INST_NAME(T1 "L " T2); \
|
||||
GO( EORw_REG_LSL(x1, xFlags, xFlags, F_OF-F_SF); \
|
||||
TSTw_mask(x1, 0b010101, 0) \
|
||||
, cEQ, cNE, X_SF|X_OF) \
|
||||
break; \
|
||||
case B+0xD: \
|
||||
INST_NAME(T1 "GE " T2); \
|
||||
GO( EORw_REG_LSL(x1, xFlags, xFlags, F_OF-F_SF); \
|
||||
TSTw_mask(x1, 0b010101, 0) \
|
||||
, cNE, cEQ, X_SF|X_OF) \
|
||||
break; \
|
||||
case B+0xE: \
|
||||
INST_NAME(T1 "LE " T2); \
|
||||
GO( EORw_REG_LSL(x1, xFlags, xFlags, F_OF-F_SF); \
|
||||
ORRw_REG_LSL(x1, x1, xFlags, F_OF-F_ZF); \
|
||||
TSTw_mask(x1, 0b010101, 0) \
|
||||
, cEQ, cNE, X_SF|X_OF|X_ZF) \
|
||||
break; \
|
||||
case B+0xF: \
|
||||
INST_NAME(T1 "G " T2); \
|
||||
GO( EORw_REG_LSL(x1, xFlags, xFlags, F_OF-F_SF); \
|
||||
ORRw_REG_LSL(x1, x1, xFlags, F_OF-F_ZF); \
|
||||
TSTw_mask(x1, 0b010101, 0) \
|
||||
, cNE, cEQ, X_SF|X_OF|X_ZF) \
|
||||
break
|
||||
|
||||
#endif //__DYNAREC_ARM64_HELPER_H__
|
||||
Executable
+104
@@ -0,0 +1,104 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_arm64.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#ifndef STEP
|
||||
#error No STEP defined
|
||||
#endif
|
||||
|
||||
void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
{
|
||||
int ok = 1;
|
||||
int ninst = 0;
|
||||
uintptr_t ip = addr;
|
||||
int need_epilog = 1;
|
||||
dyn->sons_size = 0;
|
||||
// Clean up (because there are multiple passes)
|
||||
dyn->state_flags = 0;
|
||||
dyn->dfnone = 0;
|
||||
dyn->last_ip = ip; // RIP is always set at start of block!
|
||||
fpu_reset(dyn, ninst);
|
||||
// ok, go now
|
||||
INIT;
|
||||
while(ok) {
|
||||
if(dyn->insts && (ninst>dyn->size)) {dynarec_log(LOG_NONE, "Warning, too many inst treated (%d / %d)\n",ninst, dyn->size);}
|
||||
ip = addr;
|
||||
if(dyn->insts && (dyn->insts[ninst].x64.barrier==1)) {
|
||||
dyn->last_ip = 0;
|
||||
NEW_BARRIER_INST;
|
||||
}
|
||||
NEW_INST;
|
||||
fpu_reset_scratch(dyn);
|
||||
#ifdef HAVE_TRACE
|
||||
if(my_context->dec && box64_dynarec_trace) {
|
||||
if((trace_end == 0)
|
||||
|| ((ip >= trace_start) && (ip < trace_end))) {
|
||||
MESSAGE(LOG_DUMP, "TRACE ----\n");
|
||||
fpu_reflectcache(dyn, ninst, x1, x2, x3);
|
||||
GETIP(ip);
|
||||
MOVx_REG(x1, xRIP);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
MOV32w(x2, 1);
|
||||
CALL(PrintTrace, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
MESSAGE(LOG_DUMP, "----------\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
addr = dynarec64_00(dyn, addr, ip, ninst, &ok, &need_epilog);
|
||||
|
||||
INST_EPILOG;
|
||||
|
||||
if(dyn->insts && dyn->insts[ninst+1].x64.barrier) {
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3);
|
||||
if(dyn->insts[ninst+1].x64.barrier!=2) {
|
||||
dyn->state_flags = 0;
|
||||
dyn->dfnone = 0;
|
||||
}
|
||||
}
|
||||
if(!ok && !need_epilog && dyn->insts && (addr < (dyn->start+dyn->isize))) {
|
||||
ok = 1;
|
||||
}
|
||||
if(!ok && !need_epilog && !dyn->insts && getProtection(addr+3))
|
||||
if(*(uint32_t*)addr!=0) { // check if need to continue (but is next 4 bytes are 0, stop)
|
||||
uintptr_t next = get_closest_next(dyn, addr);
|
||||
if(next && (
|
||||
(((next-addr)<15) && is_nops(dyn, addr, next-addr))
|
||||
||(((next-addr)<30) && is_instructions(dyn, addr, next-addr)) ))
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "Extend block %p, %p -> %p (ninst=%d)\n", dyn, (void*)addr, (void*)next, ninst);
|
||||
ok = 1;
|
||||
} else if(next && (next-addr)<30) {
|
||||
dynarec_log(LOG_DEBUG, "Cannot extend block %p -> %p (%02X %02X %02X %02X %02X %02X %02X %02x)\n", (void*)addr, (void*)next, PK(0), PK(1), PK(2), PK(3), PK(4), PK(5), PK(6), PK(7));
|
||||
}
|
||||
}
|
||||
if(ok<0) {ok = 0; need_epilog=1;}
|
||||
++ninst;
|
||||
}
|
||||
if(need_epilog) {
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3);
|
||||
jump_to_epilog(dyn, ip, 0, ninst); // no linker here, it's an unknow instruction
|
||||
}
|
||||
FINI;
|
||||
MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d, %d sons)\n", dyn->size, dyn->sons_size);
|
||||
}
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
|
||||
#define INIT uintptr_t sav_addr=addr
|
||||
#define FINI dyn->isize = addr-sav_addr
|
||||
#define MESSAGE(A, ...)
|
||||
#define SETFLAGS(A, B)
|
||||
#define READFLAGS(A)
|
||||
#define EMIT(A)
|
||||
#define JUMP(A) add_next(dyn, (uintptr_t)A)
|
||||
#define NEW_INST ++dyn->size
|
||||
#define INST_EPILOG
|
||||
#define INST_NAME(name)
|
||||
#define DEFAULT \
|
||||
--dyn->size; \
|
||||
*ok = -1; \
|
||||
if(box64_dynarec_log>=LOG_INFO) {\
|
||||
dynarec_log(LOG_NONE, "%p: Dynarec stopped because of Opcode %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", \
|
||||
(void*)ip, PKip(0), \
|
||||
PKip(1), PKip(2), PKip(3), \
|
||||
PKip(4), PKip(5), PKip(6), \
|
||||
PKip(7), PKip(8), PKip(9), \
|
||||
PKip(10),PKip(11),PKip(12), \
|
||||
PKip(13),PKip(14)); \
|
||||
printFunctionAddr(ip, " => "); \
|
||||
dynarec_log(LOG_NONE, "\n"); \
|
||||
}
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
#define INIT
|
||||
#define FINI \
|
||||
dyn->insts[ninst].x64.addr = addr; \
|
||||
if(ninst) dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr;
|
||||
#define MESSAGE(A, ...)
|
||||
#define EMIT(A)
|
||||
#define READFLAGS(A) dyn->insts[ninst].x64.use_flags = A
|
||||
#define SETFLAGS(A,B) {dyn->insts[ninst].x64.set_flags = A; dyn->insts[ninst].x64.state_flags = B;}
|
||||
#define JUMP(A) dyn->insts[ninst].x64.jmp = A
|
||||
#define BARRIER(A) dyn->insts[ninst].x64.barrier = A
|
||||
#define BARRIER_NEXT(A) if(ninst<dyn->size) dyn->insts[ninst+1].x64.barrier = A
|
||||
|
||||
#define NEW_INST \
|
||||
dyn->insts[ninst].x64.addr = ip; \
|
||||
if(ninst) dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr;
|
||||
#define INST_EPILOG
|
||||
#define INST_NAME(name)
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
#define INIT dyn->arm_size = 0
|
||||
#define FINI if(ninst) {dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size);}
|
||||
|
||||
#define MESSAGE(A, ...)
|
||||
#define EMIT(A) dyn->insts[ninst].size+=4; dyn->arm_size+=4
|
||||
#define NEW_INST if(ninst) {dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size);}
|
||||
#define INST_EPILOG dyn->insts[ninst].epilog = dyn->arm_size;
|
||||
#define INST_NAME(name)
|
||||
#define NEW_BARRIER_INST if(ninst) ++dyn->sons_size
|
||||
#define TABLE64(A, V) if((V)>0xffffffffLL) {Table64(dyn, (V)); EMIT(0);} else {MOV64x(A, V);}
|
||||
Executable
+35
@@ -0,0 +1,35 @@
|
||||
#define INIT
|
||||
#define FINI
|
||||
#define EMIT(A) \
|
||||
if(box64_dynarec_dump) {dynarec_log(LOG_NONE, "\t%08x\t%s\n", (uint32_t)(A), arm64_print(A, (uintptr_t)dyn->block));} \
|
||||
*(uint32_t*)(dyn->block) = (uint32_t)(A); \
|
||||
dyn->block += 4; dyn->arm_size += 4;\
|
||||
dyn->insts[ninst].size2 += 4
|
||||
|
||||
#define MESSAGE(A, ...) if(box64_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__)
|
||||
#define NEW_INST
|
||||
#define INST_EPILOG
|
||||
#define INST_NAME(name) \
|
||||
if(box64_dynarec_dump) {\
|
||||
printf_x64_instruction(my_context->dec, &dyn->insts[ninst].x64, name); \
|
||||
dynarec_log(LOG_NONE, "%s%p: %d emited opcodes, state=%d/%d, set=%X, use=%X, need=%X%s\n", \
|
||||
(box64_dynarec_dump>1)?"\e[32m":"", \
|
||||
(void*)(dyn->arm_start+dyn->insts[ninst].address), \
|
||||
dyn->insts[ninst].size/4, \
|
||||
dyn->insts[ninst].x64.state_flags, \
|
||||
dyn->state_flags, \
|
||||
dyn->insts[ninst].x64.set_flags, \
|
||||
dyn->insts[ninst].x64.use_flags, \
|
||||
dyn->insts[ninst].x64.need_flags, \
|
||||
(box64_dynarec_dump>1)?"\e[m":""); \
|
||||
}
|
||||
|
||||
#define NEW_BARRIER_INST \
|
||||
if(ninst) { \
|
||||
dyn->sons_x64[dyn->sons_size] = (uintptr_t)ip; \
|
||||
dyn->sons_arm[dyn->sons_size] = dyn->block; \
|
||||
MESSAGE(LOG_DUMP, "----> potential Son here\n");\
|
||||
++dyn->sons_size; \
|
||||
}
|
||||
|
||||
#define TABLE64(A, V) if((V)>0xffffffffLL) {int val64offset = Table64(dyn, (V)); MESSAGE(LOG_DUMP, " Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset);} else {MOV64x(A, V);}
|
||||
Executable
+61
@@ -0,0 +1,61 @@
|
||||
#ifndef __DYNAREC_ARM_PRIVATE_H_
|
||||
#define __DYNAREC_ARM_PRIVATE_H_
|
||||
|
||||
#include "dynarec_private.h"
|
||||
|
||||
typedef struct x64emu_s x64emu_t;
|
||||
|
||||
typedef struct instruction_arm_s {
|
||||
instruction_x64_t x64;
|
||||
uintptr_t address; // (start) address of the arm emited instruction
|
||||
uintptr_t epilog; // epilog of current instruction (can be start of next, of barrier stuff)
|
||||
int size; // size of the arm emited instruction
|
||||
int size2; // size of the arm emited instrucion after pass2
|
||||
uintptr_t mark, mark2, mark3;
|
||||
uintptr_t markf;
|
||||
uintptr_t markseg;
|
||||
uintptr_t marklock;
|
||||
int pass2choice;// value for choices that are fixed on pass2 for pass3
|
||||
uintptr_t natcall;
|
||||
int retn;
|
||||
} instruction_arm64_t;
|
||||
|
||||
typedef struct dynarec_arm_s {
|
||||
instruction_arm64_t *insts;
|
||||
int32_t size;
|
||||
int32_t cap;
|
||||
uintptr_t start; // start of the block
|
||||
uint32_t isize; // size in byte of x64 instructions included
|
||||
void* block; // memory pointer where next instruction is emited
|
||||
uintptr_t arm_start; // start of the arm code
|
||||
int arm_size; // size of emitted arm code
|
||||
int state_flags;// actual state for on-demand flags
|
||||
uintptr_t last_ip; // last set IP in RIP (or NULL if unclean state)
|
||||
int8_t x87cache[8];// cache status for the 8 x87 register behind the fpu stack
|
||||
int8_t x87reg[8]; // reg used for x87cache entry
|
||||
int8_t mmxcache[8];// cache status for the 8 MMX registers
|
||||
int8_t ssecache[16];// cache status for the 16 SSE(2) registers
|
||||
int8_t fpuused[32];// all 8..31 Q reg from fpu, used by x87, sse and mmx
|
||||
int x87stack; // cache stack counter
|
||||
int fpu_scratch;// scratch counter
|
||||
int fpu_reg; // x87/sse/mmx reg counter
|
||||
int dfnone; // if defered flags is already set to df_none
|
||||
uint64_t *table64; // table of 64bits value
|
||||
int table64size;// size of table (will be appended at end of executable code)
|
||||
uintptr_t tablestart;
|
||||
uintptr_t* next; // variable array of "next" jump address
|
||||
int next_sz;
|
||||
int next_cap;
|
||||
uintptr_t* sons_x64; // the x64 address of potential dynablock sons
|
||||
void** sons_arm; // the arm address of potential dynablock sons
|
||||
int sons_size; // number of potential dynablock sons
|
||||
} dynarec_arm_t;
|
||||
|
||||
void add_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
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 Table64(dynarec_arm_t *dyn, uint64_t val); // add a value to etable64 (if needed) and gives back the imm19 to use in LDR_literal
|
||||
|
||||
#endif //__DYNAREC_ARM_PRIVATE_H_
|
||||
Executable
+35
@@ -0,0 +1,35 @@
|
||||
#ifndef __DYNAREC_PRIVATE_H_
|
||||
#define __DYNAREC_PRIVATE_H_
|
||||
|
||||
// all flags for the use_flags field
|
||||
#define X_CF (1<<0)
|
||||
#define X_PF (1<<1)
|
||||
#define X_AF (1<<2)
|
||||
#define X_ZF (1<<3)
|
||||
#define X_SF (1<<4)
|
||||
#define X_OF (1<<5)
|
||||
#define X_ALL ((1<<6)-1)
|
||||
#define X_PEND (0x1000)
|
||||
|
||||
// all state flags
|
||||
#define SF_UNKNOWN 0
|
||||
#define SF_SET 1
|
||||
#define SF_PENDING 2
|
||||
#define SF_MAYSET 3
|
||||
#define SF_SUBSET 4
|
||||
|
||||
typedef struct instruction_x64_s {
|
||||
uintptr_t addr; //address of the instruction
|
||||
int32_t size; // size of the instruction
|
||||
int barrier; // next instruction is a jump point, so no optim allowed
|
||||
uintptr_t jmp; // offset to jump to, even if conditionnal (0 if not), no relative offset here
|
||||
int jmp_insts; // instuction to jump to (-1 if out of the block)
|
||||
uint32_t use_flags; // 0 or combination of X_?F
|
||||
uint32_t set_flags; // 0 or combination of X_?F
|
||||
uint32_t need_flags; // calculated
|
||||
int state_flags; // One of SF_XXX state
|
||||
} instruction_x64_t;
|
||||
|
||||
void printf_x64_instruction(zydis_dec_t* dec, instruction_x64_t* inst, const char* name);
|
||||
|
||||
#endif //__DYNAREC_PRIVATE_H_
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
//#include "dynarec.h"
|
||||
#include "box64stack.h"
|
||||
#include "custommem.h"
|
||||
#include "wine_tools.h"
|
||||
@@ -293,7 +292,7 @@ int LoadElfMemory(FILE* f, box64context_t* context, elfheader_t* head)
|
||||
}
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
if(e->p_flags & PF_X) {
|
||||
if(box64_dynarec && (e->p_flags & PF_X)) {
|
||||
dynarec_log(LOG_DEBUG, "Add ELF eXecutable Memory %p:%p\n", dest, (void*)e->p_memsz);
|
||||
addDBFromAddressRange((uintptr_t)dest, e->p_memsz);
|
||||
}
|
||||
@@ -334,7 +333,8 @@ int ReloadElfMemory(FILE* f, box64context_t* context, elfheader_t* head)
|
||||
if(e->p_filesz) {
|
||||
ssize_t r = -1;
|
||||
#ifdef DYNAREC
|
||||
unprotectDB((uintptr_t)dest, e->p_memsz);
|
||||
if(box64_dynarec)
|
||||
unprotectDB((uintptr_t)dest, e->p_memsz);
|
||||
#endif
|
||||
if((r=fread(dest, e->p_filesz, 1, f))!=1) {
|
||||
printf_log(LOG_NONE, "Fail to (re)read PT_LOAD part #%d (dest=%p, size=%ld, return=%ld, feof=%d/ferror=%d/%s)\n", i, dest, e->p_filesz, r, feof(f), ferror(f), strerror(ferror(f)));
|
||||
@@ -577,7 +577,7 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int c
|
||||
if(offs) {
|
||||
// add r_addend to p?
|
||||
printf_log(LOG_DUMP, "Apply R_X86_64_COPY @%p with sym=%s, @%p size=%ld\n", p, symname, (void*)offs, sym->st_size);
|
||||
memcpy(p, (void*)(offs+rela[i].r_addend), sym->st_size);
|
||||
memmove(p, (void*)(offs+rela[i].r_addend), sym->st_size);
|
||||
} else {
|
||||
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply RELA R_X86_64_COPY @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
|
||||
}
|
||||
|
||||
+5
-2
@@ -62,7 +62,7 @@ static void internalX64Setup(x64emu_t* emu, box64context_t *context, uintptr_t s
|
||||
emu->sbiidx[i] = &emu->regs[i];
|
||||
emu->sbiidx[4] = &emu->zero;
|
||||
emu->x64emu_parity_tab = x86emu_parity_tab;
|
||||
emu->eflags.x32 = 0x202; // default flags?
|
||||
emu->eflags.x64 = 0x202; // default flags?
|
||||
// own stack?
|
||||
emu->stack2free = (ownstack)?(void*)stack:NULL;
|
||||
emu->init_stack = (void*)stack;
|
||||
@@ -368,7 +368,10 @@ const char* DumpCPURegs(x64emu_t* emu, uintptr_t ip)
|
||||
if (i%5==4) {
|
||||
if(i==4) {
|
||||
if(emu->df) {
|
||||
strcat(buff, "FLAGS=??????\n");
|
||||
#define FLAG_CHAR(f) (ACCESS_FLAG(F_##f##F)) ? #f : "?"
|
||||
sprintf(tmp, "flags=%s%s%s%s%s%s\n", FLAG_CHAR(O), FLAG_CHAR(C), FLAG_CHAR(P), FLAG_CHAR(A), FLAG_CHAR(Z), FLAG_CHAR(S));
|
||||
strcat(buff, tmp);
|
||||
#undef FLAG_CHAR
|
||||
} else {
|
||||
#define FLAG_CHAR(f) (ACCESS_FLAG(F_##f##F)) ? #f : "-"
|
||||
sprintf(tmp, "FLAGS=%s%s%s%s%s%s\n", FLAG_CHAR(O), FLAG_CHAR(C), FLAG_CHAR(P), FLAG_CHAR(A), FLAG_CHAR(Z), FLAG_CHAR(S));
|
||||
|
||||
+18
-15
@@ -10,11 +10,6 @@ typedef struct x64_ucontext_s x64_ucontext_t;
|
||||
#define ERR_DIVBY0 2
|
||||
#define ERR_ILLEGAL 4
|
||||
|
||||
#ifdef DYNAREC
|
||||
#define CSTACK 32
|
||||
#define CSTACKMASK 31
|
||||
#endif
|
||||
|
||||
typedef struct forkpty_s {
|
||||
void* amaster;
|
||||
void* name;
|
||||
@@ -23,6 +18,13 @@ typedef struct forkpty_s {
|
||||
void* f; // forkpty function
|
||||
} forkpty_t;
|
||||
|
||||
typedef union multiuint_s {
|
||||
uint8_t u8;
|
||||
uint16_t u16;
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
} multiuint_t;
|
||||
|
||||
typedef struct x64emu_s {
|
||||
// cpu
|
||||
reg64_t regs[16];
|
||||
@@ -35,18 +37,19 @@ typedef struct x64emu_s {
|
||||
x87flags_t sw;
|
||||
uint32_t top; // top is part of sw, but it's faster to have it separatly
|
||||
int fpu_stack;
|
||||
uint32_t mxcsr;
|
||||
fpu_round_t round;
|
||||
fpu_ld_t fpu_ld[8]; // for long double emulation / 80bits fld fst
|
||||
fpu_ll_t fpu_ll[8]; // for 64bits fild / fist sequence
|
||||
fpu_p_reg_t p_regs[8];
|
||||
// sse
|
||||
sse_regs_t xmm[16];
|
||||
uint32_t mxcsr;
|
||||
// defered flags
|
||||
int dummy1; // to align on 64bits with df
|
||||
defered_flags_t df;
|
||||
uint64_t op1;
|
||||
uint64_t op2;
|
||||
uint64_t res;
|
||||
multiuint_t op1;
|
||||
multiuint_t op2;
|
||||
multiuint_t res;
|
||||
uint32_t *x64emu_parity_tab; // helper
|
||||
#ifdef HAVE_TRACE
|
||||
uintptr_t prev2_ip;
|
||||
@@ -54,7 +57,12 @@ typedef struct x64emu_s {
|
||||
// segments
|
||||
uint32_t segs[6]; // only 32bits value?
|
||||
uintptr_t segs_offs[6]; // computed offset associate with segment
|
||||
uint64_t segs_serial[6]; // are seg offset clean (not 0) or does they need to be re-computed (0)? For GS, serial need to be the same as context->sel_serial
|
||||
uint32_t segs_serial[6]; // are seg offset clean (not 0) or does they need to be re-computed (0)? For GS, serial need to be the same as context->sel_serial
|
||||
// parent context
|
||||
box64context_t *context;
|
||||
// cpu helpers
|
||||
reg64_t zero;
|
||||
reg64_t *sbiidx[16];
|
||||
// emu control
|
||||
int quit;
|
||||
int error;
|
||||
@@ -63,11 +71,6 @@ typedef struct x64emu_s {
|
||||
int exit;
|
||||
int quitonlongjmp; // quit if longjmp is called
|
||||
int longjmp; // if quit because of longjmp
|
||||
// parent context
|
||||
box64context_t *context;
|
||||
// cpu helpers
|
||||
reg64_t zero;
|
||||
reg64_t *sbiidx[16];
|
||||
// scratch stack, used for alignement of double and 64bits ints on arm. 200 elements should be enough
|
||||
uint64_t scratch[200];
|
||||
// local stack, do be deleted when emu is freed
|
||||
|
||||
+4
-4
@@ -1384,8 +1384,8 @@ void idiv32(x64emu_t *emu, uint32_t s)
|
||||
SET_FLAG(F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
|
||||
|
||||
R_EAX = (uint32_t)quot;
|
||||
R_EDX = (uint32_t)mod;
|
||||
R_RAX = (uint32_t)quot;
|
||||
R_RDX = (uint32_t)mod;
|
||||
}
|
||||
|
||||
void idiv64(x64emu_t *emu, uint64_t s)
|
||||
@@ -1485,8 +1485,8 @@ void div32(x64emu_t *emu, uint32_t s)
|
||||
SET_FLAG(F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
|
||||
|
||||
R_EAX = (uint32_t)div;
|
||||
R_EDX = (uint32_t)mod;
|
||||
R_RAX = (uint32_t)div;
|
||||
R_RDX = (uint32_t)mod;
|
||||
}
|
||||
|
||||
void div64(x64emu_t *emu, uint64_t s)
|
||||
|
||||
+167
-167
@@ -16,70 +16,70 @@ uint64_t adc64 (x64emu_t *emu, uint64_t d, uint64_t s);
|
||||
|
||||
static inline uint8_t add8(x64emu_t *emu, uint8_t d, uint8_t s)
|
||||
{
|
||||
emu->res = d + s;
|
||||
emu->op1 = d;
|
||||
emu->op2 = s;
|
||||
emu->res.u16 = d + s;
|
||||
emu->op1.u8 = d;
|
||||
emu->op2.u8 = s;
|
||||
emu->df = d_add8;
|
||||
return (uint8_t)emu->res;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
static inline uint16_t add16(x64emu_t *emu, uint16_t d, uint16_t s)
|
||||
{
|
||||
emu->res = d + s;
|
||||
emu->op1 = d;
|
||||
emu->op2 = s;
|
||||
emu->res.u32 = d + s;
|
||||
emu->op1.u16 = d;
|
||||
emu->op2.u16 = s;
|
||||
emu->df = d_add16;
|
||||
return (uint16_t)emu->res;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline uint32_t add32(x64emu_t *emu, uint32_t d, uint32_t s)
|
||||
{
|
||||
emu->res = (uint64_t)d + s;
|
||||
emu->op1 = d;
|
||||
emu->op2 = s;
|
||||
emu->res.u64 = (uint64_t)d + s;
|
||||
emu->op1.u32 = d;
|
||||
emu->op2.u32 = s;
|
||||
emu->df = d_add32;
|
||||
return emu->res;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t add64(x64emu_t *emu, uint64_t d, uint64_t s)
|
||||
{
|
||||
emu->res = d + s;
|
||||
emu->op1 = d;
|
||||
emu->op2 = s;
|
||||
emu->res.u64 = d + s;
|
||||
emu->op1.u64 = d;
|
||||
emu->op2.u64 = s;
|
||||
emu->df = d_add64;
|
||||
return emu->res;
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
static inline uint8_t and8(x64emu_t *emu, uint8_t d, uint8_t s)
|
||||
{
|
||||
emu->res = d & s;
|
||||
emu->res.u8 = d & s;
|
||||
emu->df = d_and8;
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
static inline uint16_t and16(x64emu_t *emu, uint16_t d, uint16_t s)
|
||||
{
|
||||
emu->res = d & s;
|
||||
emu->res.u16 = d & s;
|
||||
emu->df = d_and16;
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline uint32_t and32(x64emu_t *emu, uint32_t d, uint32_t s)
|
||||
{
|
||||
emu->res = d & s;
|
||||
emu->res.u32 = d & s;
|
||||
emu->df = d_and32;
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t and64(x64emu_t *emu, uint64_t d, uint64_t s)
|
||||
{
|
||||
emu->res = d & s;
|
||||
emu->res.u64 = d & s;
|
||||
emu->df = d_and64;
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
uint8_t cmp8 (x64emu_t *emu, uint8_t d, uint8_t s);
|
||||
@@ -91,146 +91,146 @@ uint8_t das8 (x64emu_t *emu, uint8_t d);
|
||||
|
||||
static inline uint8_t dec8(x64emu_t *emu, uint8_t d)
|
||||
{
|
||||
emu->res = d - 1;
|
||||
emu->op1 = d;
|
||||
emu->res.u8 = d - 1;
|
||||
emu->op1.u8 = d;
|
||||
emu->df = d_dec8;
|
||||
return (uint8_t)emu->res;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
static inline uint16_t dec16(x64emu_t *emu, uint16_t d)
|
||||
{
|
||||
emu->res = d - 1;
|
||||
emu->op1 = d;
|
||||
emu->res.u16 = d - 1;
|
||||
emu->op1.u16 = d;
|
||||
emu->df = d_dec16;
|
||||
return (uint16_t)emu->res;
|
||||
return emu->res.u16;
|
||||
|
||||
}
|
||||
|
||||
static inline uint32_t dec32(x64emu_t *emu, uint32_t d)
|
||||
{
|
||||
emu->res = d - 1;
|
||||
emu->op1 = d;
|
||||
emu->res.u32 = d - 1;
|
||||
emu->op1.u32 = d;
|
||||
emu->df = d_dec32;
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t dec64(x64emu_t *emu, uint64_t d)
|
||||
{
|
||||
emu->res = d - 1;
|
||||
emu->op1 = d;
|
||||
emu->res.u64 = d - 1;
|
||||
emu->op1.u64 = d;
|
||||
emu->df = d_dec64;
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
static inline uint8_t inc8(x64emu_t *emu, uint8_t d)
|
||||
{
|
||||
emu->res = d + 1;
|
||||
emu->op1 = d;
|
||||
emu->res.u8 = d + 1;
|
||||
emu->op1.u8 = d;
|
||||
emu->df = d_inc8;
|
||||
return (uint8_t)emu->res;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
static inline uint16_t inc16(x64emu_t *emu, uint16_t d)
|
||||
{
|
||||
emu->res = d + 1;
|
||||
emu->op1 = d;
|
||||
emu->res.u16 = d + 1;
|
||||
emu->op1.u16 = d;
|
||||
emu->df = d_inc16;
|
||||
return (uint16_t)emu->res;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline uint32_t inc32(x64emu_t *emu, uint32_t d)
|
||||
{
|
||||
if(emu->df == d_shr32) {
|
||||
// workaround for some wine trickery
|
||||
uint32_t cnt = emu->op2;
|
||||
uint32_t cnt = emu->op2.u32;
|
||||
if (cnt > 0) {
|
||||
uint32_t cc = emu->op1 & (1 << (cnt - 1));
|
||||
uint32_t cc = emu->op1.u32 & (1 << (cnt - 1));
|
||||
CONDITIONAL_SET_FLAG(cc, F_CF);
|
||||
}
|
||||
}
|
||||
emu->res = d + 1;
|
||||
emu->op1 = d;
|
||||
emu->res.u32 = d + 1;
|
||||
emu->op1.u32 = d;
|
||||
emu->df = d_inc32;
|
||||
return emu->res;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t inc64(x64emu_t *emu, uint64_t d)
|
||||
{
|
||||
if(emu->df == d_shr64) {
|
||||
// workaround for some wine trickery
|
||||
uint64_t cnt = emu->op2;
|
||||
uint64_t cnt = emu->op2.u64;
|
||||
if (cnt > 0) {
|
||||
uint64_t cc = emu->op1 & (1L << (cnt - 1));
|
||||
uint64_t cc = emu->op1.u64 & (1LL << (cnt - 1));
|
||||
CONDITIONAL_SET_FLAG(cc, F_CF);
|
||||
}
|
||||
}
|
||||
emu->res = d + 1;
|
||||
emu->op1 = d;
|
||||
emu->res.u64 = d + 1;
|
||||
emu->op1.u64 = d;
|
||||
emu->df = d_inc64;
|
||||
return emu->res;
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
static inline uint8_t or8(x64emu_t *emu, uint8_t d, uint8_t s)
|
||||
{
|
||||
emu->res = d | s;
|
||||
emu->res.u8 = d | s;
|
||||
emu->df = d_or8;
|
||||
return emu->res;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
static inline uint16_t or16(x64emu_t *emu, uint16_t d, uint16_t s)
|
||||
{
|
||||
emu->res = d | s;
|
||||
emu->res.u16 = d | s;
|
||||
emu->df = d_or16;
|
||||
/* set the carry flag to be bit 8 */
|
||||
return emu->res;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline uint32_t or32(x64emu_t *emu, uint32_t d, uint32_t s)
|
||||
{
|
||||
emu->res = d | s;
|
||||
emu->res.u32 = d | s;
|
||||
emu->df = d_or32;
|
||||
return emu->res;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t or64(x64emu_t *emu, uint64_t d, uint64_t s)
|
||||
{
|
||||
emu->res = d | s;
|
||||
emu->res.u64 = d | s;
|
||||
emu->df = d_or64;
|
||||
return emu->res;
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
static inline uint8_t neg8(x64emu_t *emu, uint8_t s)
|
||||
{
|
||||
emu->res = (uint8_t)-s;
|
||||
emu->op1 = s;
|
||||
emu->res.u8 = (uint8_t)-s;
|
||||
emu->op1.u8 = s;
|
||||
emu->df = d_neg8;
|
||||
return emu->res;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
static inline uint16_t neg16(x64emu_t *emu, uint16_t s)
|
||||
{
|
||||
emu->res = (uint16_t)-s;
|
||||
emu->op1 = s;
|
||||
emu->res.u16 = (uint16_t)-s;
|
||||
emu->op1.u16 = s;
|
||||
emu->df = d_neg16;
|
||||
return emu->res;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline uint32_t neg32(x64emu_t *emu, uint32_t s)
|
||||
{
|
||||
emu->res = (uint32_t)-s;
|
||||
emu->op1 = s;
|
||||
emu->res.u32 = (uint32_t)-s;
|
||||
emu->op1.u32 = s;
|
||||
emu->df = d_neg32;
|
||||
return emu->res;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t neg64(x64emu_t *emu, uint64_t s)
|
||||
{
|
||||
emu->res = (uint64_t)-s;
|
||||
emu->op1 = s;
|
||||
emu->res.u64 = (uint64_t)-s;
|
||||
emu->op1.u64 = s;
|
||||
emu->df = d_neg64;
|
||||
return emu->res;
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
static inline uint8_t not8(x64emu_t *emu, uint8_t s)
|
||||
@@ -283,72 +283,72 @@ uint64_t sbb64 (x64emu_t *emu, uint64_t d, uint64_t s);
|
||||
static inline uint8_t shl8(x64emu_t *emu, uint8_t d, uint8_t s)
|
||||
{
|
||||
emu->df = d_shl8;
|
||||
emu->op1 = d;
|
||||
emu->op1.u8 = d;
|
||||
|
||||
s &= 0x1f;
|
||||
emu->op2 = s;
|
||||
emu->res = d << s;
|
||||
emu->op2.u8 = s;
|
||||
emu->res.u8 = d << s;
|
||||
|
||||
return (uint8_t)emu->res;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
static inline uint16_t shl16(x64emu_t *emu, uint16_t d, uint8_t s)
|
||||
{
|
||||
emu->df = d_shl16;
|
||||
emu->op1 = d;
|
||||
emu->op1.u16 = d;
|
||||
|
||||
s &= 0x1f;
|
||||
emu->op2 = s;
|
||||
emu->res = d << s;
|
||||
return (uint16_t)emu->res;
|
||||
emu->op2.u16 = s;
|
||||
emu->res.u16 = d << s;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline uint32_t shl32(x64emu_t *emu, uint32_t d, uint8_t s)
|
||||
{
|
||||
emu->df = d_shl32;
|
||||
emu->op1 = d;
|
||||
emu->op1.u32 = d;
|
||||
|
||||
s &= 0x1f;
|
||||
emu->op2 = s;
|
||||
emu->res = d << s;
|
||||
emu->op2.u32 = s;
|
||||
emu->res.u32 = d << s;
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t shl64(x64emu_t *emu, uint64_t d, uint8_t s)
|
||||
{
|
||||
emu->df = d_shl64;
|
||||
emu->op1 = d;
|
||||
emu->op1.u64 = d;
|
||||
|
||||
s &= 0x3f;
|
||||
emu->op2 = s;
|
||||
emu->res = d << s;
|
||||
emu->op2.u64 = s;
|
||||
emu->res.u64 = d << s;
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
static inline uint8_t shr8(x64emu_t *emu, uint8_t d, uint8_t s)
|
||||
{
|
||||
emu->df = d_shr8;
|
||||
emu->op1 = d;
|
||||
emu->op1.u8 = d;
|
||||
|
||||
s &= 0x1f;
|
||||
emu->op2 = s;
|
||||
emu->res = d >> s;
|
||||
emu->op2.u8 = s;
|
||||
emu->res.u8 = d >> s;
|
||||
|
||||
return (uint8_t)emu->res;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
static inline uint16_t shr16(x64emu_t *emu, uint16_t d, uint8_t s)
|
||||
{
|
||||
emu->df = d_shr16;
|
||||
emu->op1 = d;
|
||||
emu->op1.u16 = d;
|
||||
|
||||
s &= 0x1f;
|
||||
emu->op2 = s;
|
||||
emu->res = d >> s;
|
||||
emu->op2.u16 = s;
|
||||
emu->res.u16 = d >> s;
|
||||
|
||||
return (uint16_t)emu->res;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline uint32_t shr32(x64emu_t *emu, uint32_t d, uint8_t s)
|
||||
@@ -356,13 +356,13 @@ static inline uint32_t shr32(x64emu_t *emu, uint32_t d, uint8_t s)
|
||||
RESET_FLAGS(emu); // TODO: Defered this one?
|
||||
|
||||
emu->df = d_shr32;
|
||||
emu->op1 = d;
|
||||
emu->op1.u32 = d;
|
||||
|
||||
s &= 0x1f;
|
||||
emu->op2 = s;
|
||||
emu->res = d >> s;
|
||||
emu->op2.u32 = s;
|
||||
emu->res.u32 = d >> s;
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t shr64(x64emu_t *emu, uint64_t d, uint8_t s)
|
||||
@@ -370,97 +370,97 @@ static inline uint64_t shr64(x64emu_t *emu, uint64_t d, uint8_t s)
|
||||
RESET_FLAGS(emu); // TODO: Defered this one?
|
||||
|
||||
emu->df = d_shr64;
|
||||
emu->op1 = d;
|
||||
emu->op1.u64 = d;
|
||||
|
||||
s &= 0x3f;
|
||||
emu->op2 = s;
|
||||
emu->res = d >> s;
|
||||
emu->op2.u64 = s;
|
||||
emu->res.u64 = d >> s;
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
static inline uint8_t sar8(x64emu_t *emu, uint8_t d, uint8_t s)
|
||||
{
|
||||
emu->df = d_sar8;
|
||||
emu->op1 = d;
|
||||
emu->op1.u8 = d;
|
||||
|
||||
s &= 0x1f;
|
||||
emu->op2 = s;
|
||||
emu->res = (uint8_t)(((int8_t)d)>>s);
|
||||
emu->op2.u8 = s;
|
||||
emu->res.u8 = (uint8_t)(((int8_t)d)>>s);
|
||||
|
||||
return (uint8_t)emu->res;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
static inline uint16_t sar16(x64emu_t *emu, uint16_t d, uint8_t s)
|
||||
{
|
||||
emu->df = d_sar16;
|
||||
emu->op1 = d;
|
||||
emu->op1.u16 = d;
|
||||
|
||||
s &= 0x1f;
|
||||
emu->op2 = s;
|
||||
emu->res = (uint16_t)(((int16_t)d)>>s);
|
||||
emu->op2.u16 = s;
|
||||
emu->res.u16 = (uint16_t)(((int16_t)d)>>s);
|
||||
|
||||
return (uint16_t)emu->res;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline uint32_t sar32(x64emu_t *emu, uint32_t d, uint8_t s)
|
||||
{
|
||||
emu->df = d_sar32;
|
||||
emu->op1 = d;
|
||||
emu->op1.u32 = d;
|
||||
|
||||
s &= 0x1f;
|
||||
emu->op2 = s;
|
||||
emu->res = (uint32_t)(((int32_t)d)>>s);
|
||||
emu->op2.u32 = s;
|
||||
emu->res.u32 = (uint32_t)(((int32_t)d)>>s);
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t sar64(x64emu_t *emu, uint64_t d, uint8_t s)
|
||||
{
|
||||
emu->df = d_sar64;
|
||||
emu->op1 = d;
|
||||
emu->op1.u64 = d;
|
||||
|
||||
s &= 0x3f;
|
||||
emu->op2 = s;
|
||||
emu->res = (uint64_t)(((int64_t)d)>>s);
|
||||
emu->op2.u64 = s;
|
||||
emu->res.u64 = (uint64_t)(((int64_t)d)>>s);
|
||||
|
||||
return emu->res;
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
static inline uint8_t sub8(x64emu_t *emu, uint8_t d, uint8_t s)
|
||||
{
|
||||
emu->res = d - s;
|
||||
emu->op1 = d;
|
||||
emu->op2 = s;
|
||||
emu->res.u8 = d - s;
|
||||
emu->op1.u8 = d;
|
||||
emu->op2.u8 = s;
|
||||
emu->df = d_sub8;
|
||||
return (uint8_t)emu->res;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
static inline uint16_t sub16(x64emu_t *emu, uint16_t d, uint16_t s)
|
||||
{
|
||||
emu->res = d - s;
|
||||
emu->op1 = d;
|
||||
emu->op2 = s;
|
||||
emu->res.u16 = d - s;
|
||||
emu->op1.u16 = d;
|
||||
emu->op2.u16 = s;
|
||||
emu->df = d_sub16;
|
||||
return (uint16_t)emu->res;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline uint32_t sub32(x64emu_t *emu, uint32_t d, uint32_t s)
|
||||
{
|
||||
emu->res = d - s;
|
||||
emu->op1 = d;
|
||||
emu->op2 = s;
|
||||
emu->res.u32 = d - s;
|
||||
emu->op1.u32 = d;
|
||||
emu->op2.u32 = s;
|
||||
emu->df = d_sub32;
|
||||
return emu->res;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t sub64(x64emu_t *emu, uint64_t d, uint64_t s)
|
||||
{
|
||||
emu->res = d - s;
|
||||
emu->op1 = d;
|
||||
emu->op2 = s;
|
||||
emu->res.u64 = d - s;
|
||||
emu->op1.u64 = d;
|
||||
emu->op2.u64 = s;
|
||||
emu->df = d_sub64;
|
||||
return emu->res;
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
void test8 (x64emu_t *emu, uint8_t d, uint8_t s);
|
||||
@@ -470,52 +470,52 @@ void test64 (x64emu_t *emu, uint64_t d, uint64_t s);
|
||||
|
||||
static inline uint8_t xor8(x64emu_t *emu, uint8_t d, uint8_t s)
|
||||
{
|
||||
emu->res = d ^ s;
|
||||
emu->res.u8 = d ^ s;
|
||||
emu->df = d_xor8;
|
||||
return emu->res;
|
||||
return emu->res.u8;
|
||||
}
|
||||
|
||||
|
||||
static inline uint16_t xor16(x64emu_t *emu, uint16_t d, uint16_t s)
|
||||
{
|
||||
emu->res = d ^ s;
|
||||
emu->res.u16 = d ^ s;
|
||||
emu->df = d_xor16;
|
||||
return emu->res;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline uint32_t xor32(x64emu_t *emu, uint32_t d, uint32_t s)
|
||||
{
|
||||
emu->res = d ^ s;
|
||||
emu->res.u32 = d ^ s;
|
||||
emu->df = d_xor32;
|
||||
return emu->res;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline uint64_t xor64(x64emu_t *emu, uint64_t d, uint64_t s)
|
||||
{
|
||||
emu->res = d ^ s;
|
||||
emu->res.u64 = d ^ s;
|
||||
emu->df = d_xor64;
|
||||
return emu->res;
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
static inline void imul8(x64emu_t *emu, uint8_t s)
|
||||
{
|
||||
emu->df = d_imul8;
|
||||
R_AX = emu->res = (int16_t)(int8_t)R_AL * (int8_t)s;
|
||||
R_AX = emu->res.u16 = (int16_t)(int8_t)R_AL * (int8_t)s;
|
||||
}
|
||||
|
||||
static inline void imul16_eax(x64emu_t *emu, uint16_t s)
|
||||
{
|
||||
emu->df = d_imul16;
|
||||
emu->res = (int32_t)(int16_t)R_AX * (int16_t)s;
|
||||
R_AX = (uint16_t)emu->res;
|
||||
R_DX = (uint16_t)(emu->res >> 16);
|
||||
emu->res.u32 = (int32_t)(int16_t)R_AX * (int16_t)s;
|
||||
R_AX = (uint16_t)emu->res.u32;
|
||||
R_DX = (uint16_t)(emu->res.u32 >> 16);
|
||||
}
|
||||
|
||||
static inline uint16_t imul16(x64emu_t *emu, uint16_t op1, uint16_t op2)
|
||||
{
|
||||
emu->df = d_imul16;
|
||||
emu->res = (int32_t)(int16_t)op1 * (int16_t)op2;
|
||||
return (uint16_t)emu->res;
|
||||
emu->res.u32 = (int32_t)(int16_t)op1 * (int16_t)op2;
|
||||
return emu->res.u16;
|
||||
}
|
||||
|
||||
static inline void imul32_direct(uint32_t *res_lo, uint32_t* res_hi,uint32_t d, uint32_t s)
|
||||
@@ -531,17 +531,17 @@ static inline uint32_t imul32(x64emu_t *emu, uint32_t op1, uint32_t op2)
|
||||
emu->df = d_imul32;
|
||||
uint32_t _res, _op1;
|
||||
imul32_direct(&_res,&_op1,op1,op2);
|
||||
emu->res = _res;
|
||||
emu->op1 = _op1;
|
||||
return emu->res;
|
||||
emu->res.u32 = _res;
|
||||
emu->op1.u32 = _op1;
|
||||
return emu->res.u32;
|
||||
}
|
||||
|
||||
static inline void imul32_eax(x64emu_t *emu, uint32_t s)
|
||||
{
|
||||
emu->df = d_imul32;
|
||||
imul32_direct(&R_EAX,&R_EDX,R_EAX,s);
|
||||
emu->res = R_EAX;
|
||||
emu->op1 = R_EDX;
|
||||
emu->res.u32 = R_EAX;
|
||||
emu->op1.u32 = R_EDX;
|
||||
}
|
||||
|
||||
static inline void imul64_direct(uint64_t *res_lo, uint64_t* res_hi,uint64_t d, uint64_t s)
|
||||
@@ -555,46 +555,46 @@ static inline void imul64_direct(uint64_t *res_lo, uint64_t* res_hi,uint64_t d,
|
||||
static inline uint64_t imul64(x64emu_t *emu, uint64_t op1, uint64_t op2)
|
||||
{
|
||||
emu->df = d_imul64;
|
||||
imul64_direct(&emu->res,&emu->op1,op1,op2);
|
||||
return emu->res;
|
||||
imul64_direct(&emu->res.u64,&emu->op1.u64,op1,op2);
|
||||
return emu->res.u64;
|
||||
}
|
||||
|
||||
static inline void imul64_rax(x64emu_t *emu, uint64_t s)
|
||||
{
|
||||
emu->df = d_imul64;
|
||||
imul64_direct(&R_RAX,&R_RDX,R_RAX,s);
|
||||
emu->res = R_RAX;
|
||||
emu->op1 = R_RDX;
|
||||
emu->res.u64 = R_RAX;
|
||||
emu->op1.u64 = R_RDX;
|
||||
}
|
||||
|
||||
static inline void mul8(x64emu_t *emu, uint8_t s)
|
||||
{
|
||||
emu->df = d_mul8;
|
||||
R_AX = emu->res = (uint16_t)(R_AL) * s;
|
||||
R_AX = emu->res.u16 = (uint16_t)(R_AL) * s;
|
||||
}
|
||||
|
||||
static inline void mul16(x64emu_t *emu, uint16_t s)
|
||||
{
|
||||
emu->df = d_mul16;
|
||||
emu->res = (uint32_t)R_AX * s;
|
||||
R_AX = (uint16_t)emu->res;
|
||||
R_DX = (uint16_t)(emu->res >> 16);
|
||||
emu->res.u32 = (uint32_t)R_AX * s;
|
||||
R_AX = (uint16_t)emu->res.u32;
|
||||
R_DX = (uint16_t)(emu->res.u32 >> 16);
|
||||
}
|
||||
|
||||
static inline void mul32_eax(x64emu_t *emu, uint32_t s)
|
||||
{
|
||||
emu->df = d_mul32;
|
||||
uint64_t res = (uint64_t)R_EAX * s;
|
||||
emu->res = R_EAX = (uint32_t)res;
|
||||
emu->op1 = R_EDX = (uint32_t)(res >> 32);
|
||||
emu->res.u32 = R_EAX = (uint32_t)res;
|
||||
emu->op1.u32 = R_EDX = (uint32_t)(res >> 32);
|
||||
}
|
||||
|
||||
static inline void mul64_rax(x64emu_t *emu, uint64_t s)
|
||||
{
|
||||
emu->df = d_mul64;
|
||||
__int128 res = (__int128)R_RAX * s;
|
||||
emu->res = R_RAX = (uint64_t)res;
|
||||
emu->op1 = R_RDX = (uint64_t)(res >> 64);
|
||||
emu->res.u64 = R_RAX = (uint64_t)res;
|
||||
emu->op1.u64 = R_RDX = (uint64_t)(res >> 64);
|
||||
}
|
||||
|
||||
void idiv8 (x64emu_t *emu, uint8_t s);
|
||||
|
||||
+29
-18
@@ -21,7 +21,7 @@
|
||||
#include "bridge.h"
|
||||
#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#include "../dynarec/arm64_lock.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
@@ -381,15 +381,16 @@ x64emurun:
|
||||
case 0x86: /* XCHG Eb,Gb */
|
||||
nextop = F8;
|
||||
#ifdef DYNAREC
|
||||
GET_EB;
|
||||
GETEB(0);
|
||||
GETGB;
|
||||
if((nextop&0xC0)==0xC0) { // reg / reg: no lock
|
||||
tmp8u = GB;
|
||||
GB = EB->byte[0];
|
||||
EB->byte[0] = tmp8u;
|
||||
} else {
|
||||
do {
|
||||
tmp8u = arm_lock_read_b(EB);
|
||||
} while(arm_lock_write_b(EB, GB));
|
||||
tmp8u = arm64_lock_read_b(EB);
|
||||
} while(arm64_lock_write_b(EB, GB));
|
||||
GB = tmp8u;
|
||||
}
|
||||
// dynarec use need it's own mecanism
|
||||
@@ -408,21 +409,26 @@ x64emurun:
|
||||
case 0x87: /* XCHG Ed,Gd */
|
||||
nextop = F8;
|
||||
#ifdef DYNAREC
|
||||
GET_ED;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
tmp32u = GD.dword[0];
|
||||
GD.dword[0] = ED->dword[0];
|
||||
ED->dword[0] = tmp32u;
|
||||
} else {
|
||||
if(((uintptr_t)ED)&3)
|
||||
{
|
||||
// not aligned, dont't try to "LOCK"
|
||||
tmp32u = ED->dword[0];
|
||||
ED->dword[0] = GD.dword[0];
|
||||
GD.dword[0] = tmp32u;
|
||||
if(rex.w) {
|
||||
tmp64u = GD->q[0];
|
||||
GD->q[0] = ED->q[0];
|
||||
ED->q[0] = tmp64u;
|
||||
} else {
|
||||
// XCHG is supposed to automaticaly LOCK memory bus
|
||||
GD.dword[0] = arm_lock_xchg(ED, GD.dword[0]);
|
||||
tmp32u = GD->dword[0];
|
||||
GD->q[0] = ED->dword[0];
|
||||
ED->q[0] = tmp32u;
|
||||
}
|
||||
} else {
|
||||
if(rex.w) {
|
||||
GD->q[0] = arm64_lock_xchg(ED, GD->q[0]);
|
||||
} else {
|
||||
do {
|
||||
tmp32u = arm64_lock_read_d(ED);
|
||||
} while(arm64_lock_write_d(ED, GD->dword[0]));
|
||||
GD->q[0] = tmp32u;
|
||||
}
|
||||
}
|
||||
#else
|
||||
@@ -466,7 +472,12 @@ x64emurun:
|
||||
ED->dword[0] = GD->dword[0];
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8A: /* MOV Gb,Eb */
|
||||
nextop = F8;
|
||||
GETEB(0);
|
||||
GETGB;
|
||||
GB = EB->byte[0];
|
||||
break;
|
||||
case 0x8B: /* MOV Gd,Ed */
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@
|
||||
#include "bridge.h"
|
||||
#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#include "../dynarec/arm64_lock.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
@@ -19,10 +19,6 @@
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
+1
-2
@@ -19,9 +19,8 @@
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#include "../dynarec/arm64_lock.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
@@ -19,10 +19,6 @@
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
@@ -19,10 +19,6 @@
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
@@ -18,12 +18,7 @@
|
||||
#include "x64trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
//#include "my_cpuid.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
@@ -18,12 +18,7 @@
|
||||
#include "x64trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
//#include "my_cpuid.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
@@ -19,10 +19,6 @@
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
+345
-319
File diff suppressed because it is too large.
Load diff
@@ -19,9 +19,6 @@
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
@@ -18,12 +18,7 @@
|
||||
#include "x64trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
//#include "my_cpuid.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
@@ -19,9 +19,6 @@
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
@@ -18,12 +18,7 @@
|
||||
#include "x64trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
//#include "my_cpuid.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
@@ -19,9 +19,6 @@
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
@@ -18,12 +18,7 @@
|
||||
#include "x64trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
//#include "my_cpuid.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
+107
-69
@@ -20,9 +20,8 @@
|
||||
#include "box64context.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#include "../dynarec/arm64_lock.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
@@ -31,9 +30,11 @@ int RunF0(x64emu_t *emu, rex_t rex)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
uint32_t tmp32u;
|
||||
uint8_t tmp8u;
|
||||
int32_t tmp32s;
|
||||
uint32_t tmp32u, tmp32u2;
|
||||
int64_t tmp64s;
|
||||
uint64_t tmp64u;
|
||||
uint64_t tmp64u, tmp64u2;
|
||||
reg64_t *oped, *opgd;
|
||||
|
||||
opcode = F8;
|
||||
@@ -46,42 +47,57 @@ int RunF0(x64emu_t *emu, rex_t rex)
|
||||
|
||||
switch(opcode) {
|
||||
#ifdef DYNAREC
|
||||
#define GO(B, OP) \
|
||||
case B+0: \
|
||||
nextop = F8; \
|
||||
GETEB(0); \
|
||||
#define GO(B, OP) \
|
||||
case B+0: \
|
||||
nextop = F8; \
|
||||
GETEB(0); \
|
||||
GETGB; \
|
||||
do { \
|
||||
tmp8u = arm_lock_read_b(EB); \
|
||||
tmp8u = OP##8(emu, tmp8u, GB); \
|
||||
} while (arm_lock_write_b(EB, tmp8u)); \
|
||||
break; \
|
||||
case B+1: \
|
||||
nextop = F8; \
|
||||
GETED(0); \
|
||||
do { \
|
||||
tmp8u = arm64_lock_read_b(EB); \
|
||||
tmp8u = OP##8(emu, tmp8u, GB); \
|
||||
} while (arm64_lock_write_b(EB, tmp8u)); \
|
||||
break; \
|
||||
case B+1: \
|
||||
nextop = F8; \
|
||||
GETED(0); \
|
||||
GETGD; \
|
||||
do { \
|
||||
tmp32u = arm_lock_read_d(ED); \
|
||||
tmp32u = OP##32(emu, tmp32u, GD.dword[0]); \
|
||||
} while (arm_lock_write_d(ED, tmp32u)); \
|
||||
break; \
|
||||
case B+2: \
|
||||
nextop = F8; \
|
||||
GETEB(0); \
|
||||
if(rex.w) { \
|
||||
do { \
|
||||
tmp64u = arm64_lock_read_dd(ED); \
|
||||
tmp64u = OP##64(emu, tmp64u, GD->q[0]); \
|
||||
} while (arm64_lock_write_dd(ED, tmp64u)); \
|
||||
} else { \
|
||||
do { \
|
||||
tmp32u = arm64_lock_read_d(ED); \
|
||||
tmp32u = OP##32(emu, tmp32u, GD->dword[0]); \
|
||||
} while (arm64_lock_write_d(ED, tmp32u)); \
|
||||
if(MODREG) \
|
||||
ED->dword[1] = 0; \
|
||||
} \
|
||||
break; \
|
||||
case B+2: \
|
||||
nextop = F8; \
|
||||
GETEB(0); \
|
||||
GETGB; \
|
||||
GB = OP##8(emu, GB, EB->byte[0]); \
|
||||
break; \
|
||||
case B+3: \
|
||||
nextop = F8; \
|
||||
GETED(0); \
|
||||
GB = OP##8(emu, GB, EB->byte[0]); \
|
||||
break; \
|
||||
case B+3: \
|
||||
nextop = F8; \
|
||||
GETED(0); \
|
||||
GETGD; \
|
||||
GD.dword[0] = OP##32(emu, GD.dword[0], ED->dword[0]); \
|
||||
break; \
|
||||
case B+4: \
|
||||
R_AL = OP##8(emu, R_AL, F8); \
|
||||
break; \
|
||||
case B+5: \
|
||||
R_EAX = OP##32(emu, R_EAX, F32); \
|
||||
if(rex.w) \
|
||||
GD->q[0] = OP##64(emu, GD->q[0], ED->q[0]); \
|
||||
else \
|
||||
GD->q[0] = OP##32(emu, GD->dword[0], ED->dword[0]); \
|
||||
break; \
|
||||
case B+4: \
|
||||
R_AL = OP##8(emu, R_AL, F8); \
|
||||
break; \
|
||||
case B+5: \
|
||||
if(rex.w) \
|
||||
R_RAX = OP##64(emu, R_RAX, F32S64); \
|
||||
else \
|
||||
R_RAX = OP##32(emu, R_EAX, F32); \
|
||||
break;
|
||||
#else
|
||||
#define GO(B, OP) \
|
||||
@@ -157,32 +173,28 @@ int RunF0(x64emu_t *emu, rex_t rex)
|
||||
GETED(0);
|
||||
GETGD;
|
||||
#ifdef DYNAREC
|
||||
if(((uintptr_t)ED)&3) {
|
||||
if(rex.w)
|
||||
do {
|
||||
tmp32u = ED->dword[0] & ~0xff;
|
||||
tmp32u |= arm_lock_read_b(ED);
|
||||
cmp32(emu, R_EAX, tmp32u);
|
||||
tmp64u = arm64_lock_read_dd(ED);
|
||||
cmp64(emu, R_RAX, tmp64u);
|
||||
if(ACCESS_FLAG(F_ZF)) {
|
||||
tmp32s = arm_lock_write_b(ED, GD->dword[0] & 0xff);
|
||||
if(!tmp32s)
|
||||
ED->dword[0] = GD.dword[0];
|
||||
tmp32s = arm64_lock_write_dd(ED, GD->q[0]);
|
||||
} else {
|
||||
R_EAX = tmp32u;
|
||||
R_RAX = tmp64u;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
} else {
|
||||
else
|
||||
do {
|
||||
tmp32u = arm_lock_read_d(ED);
|
||||
tmp32u = arm64_lock_read_d(ED);
|
||||
cmp32(emu, R_EAX, tmp32u);
|
||||
if(ACCESS_FLAG(F_ZF)) {
|
||||
tmp32s = arm_lock_write_d(ED, GD.dword[0]);
|
||||
tmp32s = arm64_lock_write_d(ED, GD->dword[0]);
|
||||
} else {
|
||||
R_EAX = tmp32u;
|
||||
R_RAX = tmp32u;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
}
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
if(rex.w) {
|
||||
@@ -209,20 +221,21 @@ int RunF0(x64emu_t *emu, rex_t rex)
|
||||
GETED(0);
|
||||
GETGD;
|
||||
#ifdef DYNAREC
|
||||
if(((uintptr_t)ED)&3) {
|
||||
if(rex.w) {
|
||||
do {
|
||||
tmp32u = ED->dword[0] & ~0xff;
|
||||
tmp32u |= arm_lock_read_b(ED);
|
||||
tmp32u2 = add32(emu, tmp32u, GD.dword[0]);
|
||||
} while(arm_lock_write_b(ED, tmp32u2&0xff));
|
||||
ED->dword[0] = tmp32u2;
|
||||
tmp64u = arm64_lock_read_dd(ED);
|
||||
tmp64u2 = add64(emu, tmp64u, GD->dword[0]);
|
||||
} while(arm64_lock_write_dd(ED, tmp64u2));
|
||||
GD->q[0] = tmp64u;
|
||||
} else {
|
||||
do {
|
||||
tmp32u = arm_lock_read_d(ED);
|
||||
tmp32u2 = add32(emu, tmp32u, GD.dword[0]);
|
||||
} while(arm_lock_write_d(ED, tmp32u2));
|
||||
tmp32u = arm64_lock_read_d(ED);
|
||||
tmp32u2 = add32(emu, tmp32u, GD->dword[0]);
|
||||
} while(arm64_lock_write_d(ED, tmp32u2));
|
||||
GD->q[0] = tmp32u;
|
||||
if(MODREG)
|
||||
ED->dword[1] = 0;
|
||||
}
|
||||
GD.dword[0] = tmp32u;
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
if(rex.w) {
|
||||
@@ -232,7 +245,7 @@ int RunF0(x64emu_t *emu, rex_t rex)
|
||||
} else {
|
||||
tmp32u = add32(emu, ED->dword[0], GD->dword[0]);
|
||||
GD->q[0] = ED->dword[0];
|
||||
if((nextop&0xC0)==0xC0)
|
||||
if(MODREG)
|
||||
ED->q[0] = tmp32u;
|
||||
else
|
||||
ED->dword[0] = tmp32u;
|
||||
@@ -256,15 +269,40 @@ int RunF0(x64emu_t *emu, rex_t rex)
|
||||
} else
|
||||
tmp64u = F32S64;
|
||||
#ifdef DYNAREC
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: do { tmp32u2 = arm_lock_read_d(ED);} while(arm_lock_write_d(ED, add32(emu, tmp32u2, tmp32u))); break;
|
||||
case 1: do { tmp32u2 = arm_lock_read_d(ED);} while(arm_lock_write_d(ED, or32(emu, tmp32u2, tmp32u))); break;
|
||||
case 2: do { tmp32u2 = arm_lock_read_d(ED);} while(arm_lock_write_d(ED, adc32(emu, tmp32u2, tmp32u))); break;
|
||||
case 3: do { tmp32u2 = arm_lock_read_d(ED);} while(arm_lock_write_d(ED, sbb32(emu, tmp32u2, tmp32u))); break;
|
||||
case 4: do { tmp32u2 = arm_lock_read_d(ED);} while(arm_lock_write_d(ED, and32(emu, tmp32u2, tmp32u))); break;
|
||||
case 5: do { tmp32u2 = arm_lock_read_d(ED);} while(arm_lock_write_d(ED, sub32(emu, tmp32u2, tmp32u))); break;
|
||||
case 6: do { tmp32u2 = arm_lock_read_d(ED);} while(arm_lock_write_d(ED, xor32(emu, tmp32u2, tmp32u))); break;
|
||||
case 7: cmp32(emu, ED->dword[0], tmp32u); break;
|
||||
if(rex.w) {
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: do { tmp64u2 = arm64_lock_read_dd(ED); tmp64u2 = add64(emu, tmp64u2, tmp64u);} while(arm64_lock_write_dd(ED, tmp64u2)); break;
|
||||
case 1: do { tmp64u2 = arm64_lock_read_dd(ED); tmp64u2 = or64(emu, tmp64u2, tmp64u);} while(arm64_lock_write_dd(ED, tmp64u2)); break;
|
||||
case 2: do { tmp64u2 = arm64_lock_read_dd(ED); tmp64u2 = adc64(emu, tmp64u2, tmp64u);} while(arm64_lock_write_dd(ED, tmp64u2)); break;
|
||||
case 3: do { tmp64u2 = arm64_lock_read_dd(ED); tmp64u2 = sbb64(emu, tmp64u2, tmp64u);} while(arm64_lock_write_dd(ED, tmp64u2)); break;
|
||||
case 4: do { tmp64u2 = arm64_lock_read_dd(ED); tmp64u2 = and64(emu, tmp64u2, tmp64u);} while(arm64_lock_write_dd(ED, tmp64u2)); break;
|
||||
case 5: do { tmp64u2 = arm64_lock_read_dd(ED); tmp64u2 = sub64(emu, tmp64u2, tmp64u);} while(arm64_lock_write_dd(ED, tmp64u2)); break;
|
||||
case 6: do { tmp64u2 = arm64_lock_read_dd(ED); tmp64u2 = xor64(emu, tmp64u2, tmp64u);} while(arm64_lock_write_dd(ED, tmp64u2)); break;
|
||||
case 7: cmp64(emu, ED->q[0], tmp64u); break;
|
||||
}
|
||||
} else {
|
||||
if(MODREG)
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: ED->q[0] = add32(emu, ED->dword[0], tmp64u); break;
|
||||
case 1: ED->q[0] = or32(emu, ED->dword[0], tmp64u); break;
|
||||
case 2: ED->q[0] = adc32(emu, ED->dword[0], tmp64u); break;
|
||||
case 3: ED->q[0] = sbb32(emu, ED->dword[0], tmp64u); break;
|
||||
case 4: ED->q[0] = and32(emu, ED->dword[0], tmp64u); break;
|
||||
case 5: ED->q[0] = sub32(emu, ED->dword[0], tmp64u); break;
|
||||
case 6: ED->q[0] = xor32(emu, ED->dword[0], tmp64u); break;
|
||||
case 7: cmp32(emu, ED->dword[0], tmp64u); break;
|
||||
}
|
||||
else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: do { tmp32u2 = arm64_lock_read_d(ED); tmp32u2 = add32(emu, tmp32u2, tmp64u);} while(arm64_lock_write_d(ED, tmp32u2)); break;
|
||||
case 1: do { tmp32u2 = arm64_lock_read_d(ED); tmp32u2 = or32(emu, tmp32u2, tmp64u);} while(arm64_lock_write_d(ED, tmp32u2)); break;
|
||||
case 2: do { tmp32u2 = arm64_lock_read_d(ED); tmp32u2 = adc32(emu, tmp32u2, tmp64u);} while(arm64_lock_write_d(ED, tmp32u2)); break;
|
||||
case 3: do { tmp32u2 = arm64_lock_read_d(ED); tmp32u2 = sbb32(emu, tmp32u2, tmp64u);} while(arm64_lock_write_d(ED, tmp32u2)); break;
|
||||
case 4: do { tmp32u2 = arm64_lock_read_d(ED); tmp32u2 = and32(emu, tmp32u2, tmp64u);} while(arm64_lock_write_d(ED, tmp32u2)); break;
|
||||
case 5: do { tmp32u2 = arm64_lock_read_d(ED); tmp32u2 = sub32(emu, tmp32u2, tmp64u);} while(arm64_lock_write_d(ED, tmp32u2)); break;
|
||||
case 6: do { tmp32u2 = arm64_lock_read_d(ED); tmp32u2 = xor32(emu, tmp32u2, tmp64u);} while(arm64_lock_write_d(ED, tmp32u2)); break;
|
||||
case 7: cmp32(emu, ED->dword[0], tmp64u); break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
|
||||
@@ -19,10 +19,6 @@
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
@@ -18,12 +18,7 @@
|
||||
#include "x64trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box64context.h"
|
||||
//#include "my_cpuid.h"
|
||||
#include "bridge.h"
|
||||
//#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ typedef struct dynablocklist_s dynablocklist_t;
|
||||
typedef struct mmaplist_s mmaplist_t;
|
||||
typedef struct kh_dynablocks_s kh_dynablocks_t;
|
||||
#endif
|
||||
#define DYNAMAP_SHIFT 16
|
||||
#define JMPTABL_SHIFT 16
|
||||
|
||||
typedef void* (*procaddess_t)(const char* name);
|
||||
typedef void* (*vkprocaddess_t)(void* instance, const char* name);
|
||||
|
||||
+25
-25
@@ -6,31 +6,31 @@
|
||||
|
||||
typedef struct box64context_s box64context_t;
|
||||
|
||||
//void* customMalloc(size_t size);
|
||||
//void* customCalloc(size_t n, size_t size);
|
||||
//void* customRealloc(void* p, size_t size);
|
||||
//void customFree(void* p);
|
||||
void* customMalloc(size_t size);
|
||||
void* customCalloc(size_t n, size_t size);
|
||||
void* customRealloc(void* p, size_t size);
|
||||
void customFree(void* p);
|
||||
|
||||
//#define kcalloc customCalloc
|
||||
//#define kmalloc customMalloc
|
||||
//#define krealloc customRealloc
|
||||
//#define kfree customFree
|
||||
#define kcalloc customCalloc
|
||||
#define kmalloc customMalloc
|
||||
#define krealloc customRealloc
|
||||
#define kfree customFree
|
||||
|
||||
#ifdef DYNAREC
|
||||
//typedef struct dynablock_s dynablock_t;
|
||||
//typedef struct dynablocklist_s dynablocklist_t;
|
||||
//// custom protection flag to mark Page that are Write protected for Dynarec purpose
|
||||
//uintptr_t AllocDynarecMap(dynablock_t* db, int size);
|
||||
//void FreeDynarecMap(dynablock_t* db, uintptr_t addr, uint32_t size);
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
// custom protection flag to mark Page that are Write protected for Dynarec purpose
|
||||
uintptr_t AllocDynarecMap(dynablock_t* db, int size);
|
||||
void FreeDynarecMap(dynablock_t* db, uintptr_t addr, uint32_t size);
|
||||
|
||||
//void addDBFromAddressRange(uintptr_t addr, uintptr_t size);
|
||||
//void cleanDBFromAddressRange(uintptr_t addr, uintptr_t size, int destroy);
|
||||
void addDBFromAddressRange(uintptr_t addr, uintptr_t size);
|
||||
void cleanDBFromAddressRange(uintptr_t addr, uintptr_t size, int destroy);
|
||||
|
||||
//dynablocklist_t* getDB(uintptr_t idx);
|
||||
//void addJumpTableIfDefault(void* addr, void* jmp);
|
||||
//void setJumpTableDefault(void* addr);
|
||||
//uintptr_t getJumpTable();
|
||||
//uintptr_t getJumpTableAddress(uintptr_t addr);
|
||||
dynablocklist_t* getDB(uintptr_t idx);
|
||||
void addJumpTableIfDefault64(void* addr, void* jmp);
|
||||
void setJumpTableDefault64(void* addr);
|
||||
uintptr_t getJumpTable64();
|
||||
uintptr_t getJumpTableAddress64(uintptr_t addr);
|
||||
#endif
|
||||
|
||||
#define PROT_DYNAREC 0x80
|
||||
@@ -38,11 +38,11 @@ void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot);
|
||||
void setProtection(uintptr_t addr, uintptr_t size, uint32_t prot);
|
||||
uint32_t getProtection(uintptr_t addr);
|
||||
#ifdef DYNAREC
|
||||
//void protectDB(uintptr_t addr, uintptr_t size);
|
||||
//void protectDBnolock(uintptr_t addr, uintptr_t size);
|
||||
//void unprotectDB(uintptr_t addr, uintptr_t size);
|
||||
//void lockDB();
|
||||
//void unlockDB();
|
||||
void protectDB(uintptr_t addr, uintptr_t size);
|
||||
void protectDBnolock(uintptr_t addr, uintptr_t size);
|
||||
void unprotectDB(uintptr_t addr, uintptr_t size);
|
||||
void lockDB();
|
||||
void unlockDB();
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
+8
-1
@@ -7,6 +7,13 @@ extern int box64_log; // log level
|
||||
extern int box64_dynarec_log;
|
||||
extern int box64_dynarec;
|
||||
extern int box64_pagesize;
|
||||
#ifdef DYNAREC
|
||||
extern int box64_dynarec_dump;
|
||||
extern int box64_dynarec_trace;
|
||||
extern int box64_dynarec_forced;
|
||||
extern int box64_dynarec_largest;
|
||||
extern uintptr_t box64_nodynarec_start, box64_nodynarec_end;
|
||||
#endif
|
||||
extern int dlsym_error; // log dlsym error
|
||||
extern int trace_xmm; // include XMM reg in trace?
|
||||
extern int trace_emm; // include EMM reg in trace?
|
||||
@@ -30,7 +37,7 @@ extern FILE* ftrace;
|
||||
|
||||
#define printf_log(L, ...) do {if(L<=box64_log) {fprintf(ftrace, __VA_ARGS__); fflush(ftrace);}} while(0)
|
||||
|
||||
#define dynarec_log(L, ...) do {if(L<=box64_dynarec_log) {fprintf(ftrace, __VA_ARGS__); /*fflush(ftrace);*/}} while(0)
|
||||
#define dynarec_log(L, ...) do {if(L<=box64_dynarec_log) {fprintf(ftrace, __VA_ARGS__); fflush(ftrace);}} while(0)
|
||||
|
||||
#define EXPORT __attribute__((visibility("default")))
|
||||
#ifdef BUILD_DYNAMIC
|
||||
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#ifndef __DYNABLOCK_H_
|
||||
#define __DYNABLOCK_H_
|
||||
|
||||
typedef struct x64emu_s x64emu_t;
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
typedef struct kh_dynablocks_s kh_dynablocks_t;
|
||||
|
||||
uint32_t X31_hash_code(void* addr, int len);
|
||||
dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct);
|
||||
void FreeDynablockList(dynablocklist_t** dynablocks);
|
||||
void FreeDynablock(dynablock_t* db);
|
||||
void MarkDynablock(dynablock_t* db);
|
||||
void FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
|
||||
void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
|
||||
|
||||
dynablock_t* FindDynablockFromNativeAddress(void* addr); // defined in box64context.h
|
||||
dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks);
|
||||
|
||||
uintptr_t StartDynablockList(dynablocklist_t* db);
|
||||
uintptr_t EndDynablockList(dynablocklist_t* db);
|
||||
void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
|
||||
|
||||
// Handling of Dynarec block (i.e. an exectable chunk of x64 translated code)
|
||||
dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, dynablock_t** current); // return NULL if block is not found / cannot be created. Don't create if create==0
|
||||
dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr);
|
||||
|
||||
// Create and Add an new dynablock in the list, handling direct/map
|
||||
dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* created);
|
||||
|
||||
#endif //__DYNABLOCK_H_
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#ifndef __DYNAREC_ARM_H_
|
||||
#define __DYNAREC_ARM_H_
|
||||
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
typedef struct x64emu_s x64emu_t;
|
||||
|
||||
void* FillBlock64(dynablock_t* block, uintptr_t addr);
|
||||
|
||||
#endif //__DYNAREC_ARM_H_
|
||||
+24
-13
@@ -2,11 +2,19 @@
|
||||
#define __REGS_H_
|
||||
|
||||
enum {
|
||||
_AX, _CX, _DX, _BX,
|
||||
_SP, _BP, _SI, _DI,
|
||||
_RAX, _RCX, _RDX, _RBX,
|
||||
_RSP, _RBP, _RSI, _RDI,
|
||||
_R8, _R9,_R10,_R11,
|
||||
_R12,_R13,_R14,_R15
|
||||
};
|
||||
#define _AX _RAX
|
||||
#define _CX _RCX
|
||||
#define _DX _RDX
|
||||
#define _BX _RBX
|
||||
#define _SP _RSP
|
||||
#define _BP _RBP
|
||||
#define _SI _RSI
|
||||
#define _DI _RDI
|
||||
|
||||
enum {
|
||||
_CS, _DS, _SS, _ES, _FS, _GS
|
||||
@@ -39,7 +47,8 @@ typedef enum {
|
||||
d_none = 0,
|
||||
d_add8,
|
||||
d_add16,
|
||||
d_add32,
|
||||
d_add32, // using 64bits res
|
||||
d_add32b, // using 32bits res
|
||||
d_add64,
|
||||
d_and8,
|
||||
d_and16,
|
||||
@@ -100,6 +109,7 @@ typedef enum {
|
||||
d_adc8,
|
||||
d_adc16,
|
||||
d_adc32,
|
||||
d_adc32b,
|
||||
d_adc64,
|
||||
d_sbb8,
|
||||
d_sbb16,
|
||||
@@ -150,18 +160,18 @@ typedef struct {
|
||||
|
||||
typedef union {
|
||||
struct __attribute__ ((__packed__)) {
|
||||
unsigned int _F_CF:1;
|
||||
unsigned int _F_CF:1; //0x0001
|
||||
unsigned int _F_res1:1;
|
||||
unsigned int _F_PF:1;
|
||||
unsigned int _F_PF:1; //0x0004
|
||||
unsigned int _F_res2:1;
|
||||
unsigned int _F_AF:1;
|
||||
unsigned int _F_AF:1; //0x0010
|
||||
unsigned int _F_res3:1;
|
||||
unsigned int _F_ZF:1;
|
||||
unsigned int _F_SF:1;
|
||||
unsigned int _F_TF:1;
|
||||
unsigned int _F_IF:1;
|
||||
unsigned int _F_DF:1;
|
||||
unsigned int _F_OF:1;
|
||||
unsigned int _F_ZF:1; //0x0040
|
||||
unsigned int _F_SF:1; //0x0080
|
||||
unsigned int _F_TF:1; //0x0100
|
||||
unsigned int _F_IF:1; //0x0200
|
||||
unsigned int _F_DF:1; //0x0400
|
||||
unsigned int _F_OF:1; //0x0800
|
||||
unsigned int _F_IOPL:2;
|
||||
unsigned int _F_NT:1;
|
||||
unsigned int _F_dummy:1;
|
||||
@@ -171,8 +181,9 @@ typedef union {
|
||||
unsigned int _F_VIF:1;
|
||||
unsigned int _F_VIP:1;
|
||||
unsigned int _F_ID:1;
|
||||
unsigned int _F_fill1:10;
|
||||
uint32_t _F_fill2;
|
||||
} f;
|
||||
uint32_t x32;
|
||||
uint64_t x64;
|
||||
} x64flags_t;
|
||||
|
||||
|
||||
@@ -430,7 +430,8 @@ int GetGlobalNoWeakSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* st
|
||||
|
||||
int IsGlobalNoWeakSymbolInNative(lib_t *maplib, const char* name)
|
||||
{
|
||||
uintptr_t start, end;
|
||||
uintptr_t start=0;
|
||||
uintptr_t end=0;
|
||||
for(int i=0; i<maplib->libsz; ++i)
|
||||
if(GetElfIndex(maplib->libraries[i].lib)==-1)
|
||||
if(GetLibNoWeakSymbolStartEnd(maplib->libraries[i].lib, name, &start, &end))
|
||||
|
||||
+69
-46
@@ -446,12 +446,12 @@ void my_sigactionhandler_oldcode(int32_t sig, siginfo_t* info, void * ucntx, int
|
||||
// get that actual ESP first!
|
||||
x64emu_t *emu = thread_get_emu();
|
||||
uintptr_t *frame = (uintptr_t*)R_RSP;
|
||||
#if defined(DYNAREC) && defined(__arm__)
|
||||
#if defined(DYNAREC) && defined(__aarch64__)
|
||||
ucontext_t *p = (ucontext_t *)ucntx;
|
||||
void * pc = (void*)p->uc_mcontext.arm_pc;
|
||||
void * pc = (void*)p->uc_mcontext.pc;
|
||||
dynablock_t* db = (dynablock_t*)cur_db;//FindDynablockFromNativeAddress(pc);
|
||||
if(db) {
|
||||
frame = (uint32_t*)p->uc_mcontext.arm_r8;
|
||||
frame = (uintptr_t*)p->uc_mcontext.regs[10+_SP];
|
||||
}
|
||||
#endif
|
||||
// stack tracking
|
||||
@@ -492,20 +492,28 @@ void my_sigactionhandler_oldcode(int32_t sig, siginfo_t* info, void * ucntx, int
|
||||
sigcontext->uc_mcontext.gregs[X64_RSP] = R_RSP;
|
||||
sigcontext->uc_mcontext.gregs[X64_RBX] = R_RBX;
|
||||
// flags
|
||||
sigcontext->uc_mcontext.gregs[X64_EFL] = emu->eflags.x32;
|
||||
sigcontext->uc_mcontext.gregs[X64_EFL] = emu->eflags.x64;
|
||||
// get segments
|
||||
sigcontext->uc_mcontext.gregs[X64_CSGSFS] = ((uint64_t)(R_CS)) | (((uint64_t)(R_GS))<<16) | (((uint64_t)(R_FS))<<32);
|
||||
#if defined(DYNAREC) && defined(__arm__)
|
||||
#if defined(DYNAREC) && defined(__aarch64__)
|
||||
if(db) {
|
||||
sigcontext->uc_mcontext.gregs[X64_RAX] = p->uc_mcontext.arm_r4;
|
||||
sigcontext->uc_mcontext.gregs[X64_RCX] = p->uc_mcontext.arm_r5;
|
||||
sigcontext->uc_mcontext.gregs[X64_RDX] = p->uc_mcontext.arm_r6;
|
||||
sigcontext->uc_mcontext.gregs[X64_RBX] = p->uc_mcontext.arm_r7;
|
||||
sigcontext->uc_mcontext.gregs[X64_RSP] = p->uc_mcontext.arm_r8;
|
||||
sigcontext->uc_mcontext.gregs[X64_RBP] = p->uc_mcontext.arm_r9;
|
||||
sigcontext->uc_mcontext.gregs[X64_RSI] = p->uc_mcontext.arm_r10;
|
||||
sigcontext->uc_mcontext.gregs[X64_RDI] = p->uc_mcontext.arm_fp;
|
||||
sigcontext->uc_mcontext.gregs[X64_RIP] = getX86Address(db, (uintptr_t)pc);
|
||||
sigcontext->uc_mcontext.gregs[X64_RAX] = p->uc_mcontext.regs[10];
|
||||
sigcontext->uc_mcontext.gregs[X64_RCX] = p->uc_mcontext.regs[11];
|
||||
sigcontext->uc_mcontext.gregs[X64_RDX] = p->uc_mcontext.regs[12];
|
||||
sigcontext->uc_mcontext.gregs[X64_RBX] = p->uc_mcontext.regs[13];
|
||||
sigcontext->uc_mcontext.gregs[X64_RSP] = p->uc_mcontext.regs[14];
|
||||
sigcontext->uc_mcontext.gregs[X64_RBP] = p->uc_mcontext.regs[15];
|
||||
sigcontext->uc_mcontext.gregs[X64_RSI] = p->uc_mcontext.regs[16];
|
||||
sigcontext->uc_mcontext.gregs[X64_RDI] = p->uc_mcontext.regs[17];
|
||||
sigcontext->uc_mcontext.gregs[X64_R8] = p->uc_mcontext.regs[18];
|
||||
sigcontext->uc_mcontext.gregs[X64_R9] = p->uc_mcontext.regs[19];
|
||||
sigcontext->uc_mcontext.gregs[X64_R10] = p->uc_mcontext.regs[20];
|
||||
sigcontext->uc_mcontext.gregs[X64_R11] = p->uc_mcontext.regs[21];
|
||||
sigcontext->uc_mcontext.gregs[X64_R12] = p->uc_mcontext.regs[22];
|
||||
sigcontext->uc_mcontext.gregs[X64_R13] = p->uc_mcontext.regs[23];
|
||||
sigcontext->uc_mcontext.gregs[X64_R14] = p->uc_mcontext.regs[24];
|
||||
sigcontext->uc_mcontext.gregs[X64_R15] = p->uc_mcontext.regs[25];
|
||||
sigcontext->uc_mcontext.gregs[X64_RIP] = getX64Address(db, (uintptr_t)pc);
|
||||
}
|
||||
#endif
|
||||
// get FloatPoint status
|
||||
@@ -608,7 +616,7 @@ void my_sigactionhandler_oldcode(int32_t sig, siginfo_t* info, void * ucntx, int
|
||||
if(sigcontext->uc_mcontext.gregs[X64_RIP]!=sigcontext_copy.uc_mcontext.gregs[X64_RIP]) ejb->emu->ip.dword[0]=sigcontext->uc_mcontext.gregs[X64_RIP];
|
||||
sigcontext->uc_mcontext.gregs[X64_RIP] = R_RIP;
|
||||
// flags
|
||||
if(sigcontext->uc_mcontext.gregs[X64_EFL]!=sigcontext_copy.uc_mcontext.gregs[X64_EFL]) ejb->emu->eflags.x32=sigcontext->uc_mcontext.gregs[X64_EFL];
|
||||
if(sigcontext->uc_mcontext.gregs[X64_EFL]!=sigcontext_copy.uc_mcontext.gregs[X64_EFL]) ejb->emu->eflags.x64=sigcontext->uc_mcontext.gregs[X64_EFL];
|
||||
// get segments
|
||||
uint16_t seg;
|
||||
seg = (sigcontext->uc_mcontext.gregs[X64_CSGSFS] >> 0)&0xffff;
|
||||
@@ -637,7 +645,7 @@ void my_sigactionhandler_oldcode(int32_t sig, siginfo_t* info, void * ucntx, int
|
||||
new_ss->ss_flags = 0;
|
||||
}
|
||||
|
||||
void my_box86signalhandler(int32_t sig, siginfo_t* info, void * ucntx)
|
||||
void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx)
|
||||
{
|
||||
// sig==SIGSEGV || sig==SIGBUS || sig==SIGILL here!
|
||||
int log_minimum = (my_context->is_sigaction[sig] && sig==SIGSEGV)?LOG_INFO:LOG_NONE;
|
||||
@@ -659,32 +667,47 @@ void my_box86signalhandler(int32_t sig, siginfo_t* info, void * ucntx)
|
||||
dynablock_t* db = NULL;
|
||||
int db_searched = 0;
|
||||
if ((sig==SIGSEGV) && (addr) && (info->si_code == SEGV_ACCERR) && (prot&PROT_DYNAREC)) {
|
||||
if(box86_dynarec_smc) {
|
||||
dynablock_t* db_pc = NULL;
|
||||
db_pc = FindDynablockFromNativeAddress(pc);
|
||||
if(db_pc) {
|
||||
db = FindDynablockFromNativeAddress(addr);
|
||||
db_searched = 1;
|
||||
}
|
||||
if(db_pc && db) {
|
||||
if (db_pc == db) {
|
||||
dynarec_log(LOG_NONE, "Warning: Access to protected %p from %p, inside same dynablock\n", addr, pc);
|
||||
}
|
||||
}
|
||||
if(db && db->x86_addr>= addr && (db->x86_addr+db->x86_size)<addr) {
|
||||
dynarec_log(LOG_INFO, "Warning, addr inside current dynablock!\n");
|
||||
}
|
||||
}
|
||||
dynarec_log(LOG_DEBUG, "Access to protected %p from %p, unprotecting memory (prot=%x)\n", addr, pc, prot);
|
||||
// access error, unprotect the block (and mark them dirty)
|
||||
if(prot&PROT_DYNAREC) // on heavy multi-thread program, the protection can already be gone...
|
||||
unprotectDB((uintptr_t)addr, 1); // unprotect 1 byte... But then, the whole page will be unprotected
|
||||
// check if SMC inside block
|
||||
if(!db_searched) {
|
||||
db = FindDynablockFromNativeAddress(pc);
|
||||
db_searched = 1;
|
||||
}
|
||||
if(db && (addr>=db->x64_addr && addr<(db->x64_addr+db->x64_size))) {
|
||||
// dynablock got auto-dirty! need to get out of it!!!
|
||||
emu_jmpbuf_t* ejb = GetJmpBuf();
|
||||
if(ejb->jmpbuf_ok) {
|
||||
ejb->emu->regs[_AX].q[0] = p->uc_mcontext.regs[10];
|
||||
ejb->emu->regs[_CX].q[0] = p->uc_mcontext.regs[11];
|
||||
ejb->emu->regs[_DX].q[0] = p->uc_mcontext.regs[12];
|
||||
ejb->emu->regs[_BX].q[0] = p->uc_mcontext.regs[13];
|
||||
ejb->emu->regs[_SP].q[0] = p->uc_mcontext.regs[14];
|
||||
ejb->emu->regs[_BP].q[0] = p->uc_mcontext.regs[15];
|
||||
ejb->emu->regs[_SI].q[0] = p->uc_mcontext.regs[16];
|
||||
ejb->emu->regs[_DI].q[0] = p->uc_mcontext.regs[17];
|
||||
ejb->emu->regs[_R8].q[0] = p->uc_mcontext.regs[18];
|
||||
ejb->emu->regs[_R9].q[0] = p->uc_mcontext.regs[19];
|
||||
ejb->emu->regs[_R10].q[0] = p->uc_mcontext.regs[20];
|
||||
ejb->emu->regs[_R11].q[0] = p->uc_mcontext.regs[21];
|
||||
ejb->emu->regs[_R12].q[0] = p->uc_mcontext.regs[22];
|
||||
ejb->emu->regs[_R13].q[0] = p->uc_mcontext.regs[23];
|
||||
ejb->emu->regs[_R14].q[0] = p->uc_mcontext.regs[24];
|
||||
ejb->emu->regs[_R15].q[0] = p->uc_mcontext.regs[25];
|
||||
ejb->emu->ip.q[0] = getX64Address(db, (uintptr_t)pc);
|
||||
ejb->emu->eflags.x64 = p->uc_mcontext.regs[26];
|
||||
dynarec_log(LOG_DEBUG, "Auto-SMC detected, getting out of current Dynablock!\n");
|
||||
longjmp(ejb->jmpbuf, 2);
|
||||
}
|
||||
dynarec_log(LOG_INFO, "Warning, Auto-SMC (%p for db %p/%p) detected, but jmpbuffer not ready!\n", (void*)addr, db, (void*)db->x64_addr);
|
||||
}
|
||||
// done
|
||||
if(prot&PROT_WRITE) return; // if there is no write permission, don't return and continue to program signal handling
|
||||
} else if ((sig==SIGSEGV) && (addr) && (info->si_code == SEGV_ACCERR) && (prot&(PROT_READ|PROT_WRITE))) {
|
||||
db = FindDynablockFromNativeAddress(pc);
|
||||
db_searched = 1;
|
||||
if(db && db->x86_addr>= addr && (db->x86_addr+db->x86_size)<addr) {
|
||||
if(db && db->x64_addr>= addr && (db->x64_addr+db->x64_size)<addr) {
|
||||
dynarec_log(LOG_INFO, "Warning, addr inside current dynablock!\n");
|
||||
}
|
||||
if(addr && pc && db) {
|
||||
@@ -718,13 +741,13 @@ exit(-1);
|
||||
x64emu_t* emu = thread_get_emu();
|
||||
x64pc = R_RIP;
|
||||
rsp = (void*)R_RSP;
|
||||
#if defined(__arm__) && defined(DYNAREC)
|
||||
if(db && p->uc_mcontext.arm_r0>0x10000) {
|
||||
emu = (x64emu_t*)p->uc_mcontext.arm_r0;
|
||||
#if defined(__aarch64__) && defined(DYNAREC)
|
||||
if(db && p->uc_mcontext.regs[0]>0x10000) {
|
||||
emu = (x64emu_t*)p->uc_mcontext.regs[0];
|
||||
}
|
||||
if(db) {
|
||||
x64pc = getX64Address(db, (uintptr_t)pc);
|
||||
rsp = (void*)p->uc_mcontext.arm_r8;
|
||||
rsp = (void*)p->uc_mcontext.regs[10+_SP];
|
||||
}
|
||||
#endif
|
||||
x64name = getAddrFunctionName(x64pc);
|
||||
@@ -755,12 +778,12 @@ exit(-1);
|
||||
#ifdef DYNAREC
|
||||
uint32_t hash = 0;
|
||||
if(db)
|
||||
hash = X31_hash_code(db->x86_addr, db->x86_size);
|
||||
hash = X31_hash_code(db->x64_addr, db->x64_size);
|
||||
printf_log(log_minimum, "%04d|%s @%p (%s) (x64pc=%p/%s:\"%s\", rsp=%p), for accessing %p (code=%d/prot=%x), db=%p(%p:%p/%p:%p/%s:%s, hash:%x/%x)",
|
||||
GetTID(), signame, pc, name, (void*)x64pc, elfname?elfname:"???", x64name?x64name:"???", rsp, addr, info->si_code,
|
||||
prot, db, db?db->block:0, db?(db->block+db->size):0,
|
||||
db?db->x86_addr:0, db?(db->x86_addr+db->x86_size):0,
|
||||
getAddrFunctionName((uintptr_t)(db?db->x86_addr:0)), (db?db->need_test:0)?"need_stest":"clean", db?db->hash:0, hash);
|
||||
db?db->x64_addr:0, db?(db->x64_addr+db->x64_size):0,
|
||||
getAddrFunctionName((uintptr_t)(db?db->x64_addr:0)), (db?db->need_test:0)?"need_stest":"clean", db?db->hash:0, hash);
|
||||
#else
|
||||
printf_log(log_minimum, "%04d|%s @%p (%s) (x64pc=%p/%s:\"%s\", rsp=%p), for accessing %p (code=%d)", GetTID(), signame, pc, name, (void*)x64pc, elfname?elfname:"???", x64name?x64name:"???", rsp, addr, info->si_code);
|
||||
#endif
|
||||
@@ -788,7 +811,7 @@ void my_sigactionhandler(int32_t sig, siginfo_t* info, void * ucntx)
|
||||
{
|
||||
#ifdef DYNAREC
|
||||
ucontext_t *p = (ucontext_t *)ucntx;
|
||||
void * pc = (void*)p->uc_mcontext.arm_pc;
|
||||
void * pc = (void*)p->uc_mcontext.pc;
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(pc);
|
||||
#else
|
||||
void* db = NULL;
|
||||
@@ -1133,15 +1156,15 @@ void init_signal_helper(box64context_t* context)
|
||||
for(int i=0; i<MAX_SIGNAL; ++i) {
|
||||
context->signals[i] = 1; // SIG_DFL
|
||||
}
|
||||
struct sigaction action;
|
||||
struct sigaction action = {0};
|
||||
action.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER;
|
||||
action.sa_sigaction = my_box86signalhandler;
|
||||
action.sa_sigaction = my_box64signalhandler;
|
||||
sigaction(SIGSEGV, &action, NULL);
|
||||
action.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER;
|
||||
action.sa_sigaction = my_box86signalhandler;
|
||||
action.sa_sigaction = my_box64signalhandler;
|
||||
sigaction(SIGBUS, &action, NULL);
|
||||
action.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER;
|
||||
action.sa_sigaction = my_box86signalhandler;
|
||||
action.sa_sigaction = my_box64signalhandler;
|
||||
sigaction(SIGILL, &action, NULL);
|
||||
|
||||
pthread_once(&sigstack_key_once, sigstack_key_alloc);
|
||||
|
||||
+38
-28
@@ -56,6 +56,8 @@ typedef struct x64_unwind_buff_s {
|
||||
void *__pad[4];
|
||||
} x64_unwind_buff_t __attribute__((__aligned__));
|
||||
|
||||
typedef void(*vFv_t)();
|
||||
|
||||
KHASH_MAP_INIT_INT64(threadstack, threadstack_t*)
|
||||
KHASH_MAP_INIT_INT64(cancelthread, __pthread_unwind_buf_t*)
|
||||
|
||||
@@ -152,8 +154,10 @@ typedef struct emuthread_s {
|
||||
static void emuthread_destroy(void* p)
|
||||
{
|
||||
emuthread_t *et = (emuthread_t*)p;
|
||||
FreeX64Emu(&et->emu);
|
||||
free(et);
|
||||
if(et) {
|
||||
FreeX64Emu(&et->emu);
|
||||
free(et);
|
||||
}
|
||||
}
|
||||
|
||||
static pthread_key_t thread_key;
|
||||
@@ -297,7 +301,7 @@ EXPORT int my_pthread_create(x64emu_t *emu, void* t, void* attr, void* start_rou
|
||||
et->fnc = (uintptr_t)start_routine;
|
||||
et->arg = arg;
|
||||
#ifdef DYNAREC
|
||||
if(box86_dynarec) {
|
||||
if(box64_dynarec) {
|
||||
// pre-creation of the JIT code for the entry point of the thread
|
||||
dynablock_t *current = NULL;
|
||||
DBGetBlock(emu, (uintptr_t)start_routine, 1, ¤t);
|
||||
@@ -415,28 +419,6 @@ GO(27) \
|
||||
GO(28) \
|
||||
GO(29)
|
||||
|
||||
// once_callback
|
||||
#define GO(A) \
|
||||
static uintptr_t my_once_callback_fct_##A = 0; \
|
||||
static void my_once_callback_##A() \
|
||||
{ \
|
||||
RunFunction(my_context, my_once_callback_fct_##A, 0, 0);\
|
||||
}
|
||||
SUPER()
|
||||
#undef GO
|
||||
static void* findonce_callbackFct(void* fct)
|
||||
{
|
||||
if(!fct) return fct;
|
||||
if(GetNativeFnc((uintptr_t)fct)) return GetNativeFnc((uintptr_t)fct);
|
||||
#define GO(A) if(my_once_callback_fct_##A == (uintptr_t)fct) return my_once_callback_##A;
|
||||
SUPER()
|
||||
#undef GO
|
||||
#define GO(A) if(my_once_callback_fct_##A == 0) {my_once_callback_fct_##A = (uintptr_t)fct; return my_once_callback_##A; }
|
||||
SUPER()
|
||||
#undef GO
|
||||
printf_log(LOG_NONE, "Warning, no more slot for pthread once_callback callback\n");
|
||||
return NULL;
|
||||
}
|
||||
// key_destructor
|
||||
#define GO(A) \
|
||||
static uintptr_t my_key_destructor_fct_##A = 0; \
|
||||
@@ -484,9 +466,25 @@ static void* findcleanup_routineFct(void* fct)
|
||||
|
||||
#undef SUPER
|
||||
|
||||
// once_callback
|
||||
// Don't use a "GO" scheme, once callback are only called once by definition
|
||||
static __thread uintptr_t my_once_callback_fct = 0;
|
||||
static void my_once_callback()
|
||||
{
|
||||
if(my_once_callback_fct) {
|
||||
if(GetNativeFnc((uintptr_t)my_once_callback_fct)) {
|
||||
vFv_t f = (vFv_t)GetNativeFnc((uintptr_t)my_once_callback_fct);
|
||||
f();
|
||||
return;
|
||||
}
|
||||
RunFunction(my_context, my_once_callback_fct, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int EXPORT my_pthread_once(x64emu_t* emu, void* once, void* cb)
|
||||
{
|
||||
return pthread_once(once, findonce_callbackFct(cb));
|
||||
my_once_callback_fct = (uintptr_t)cb;
|
||||
return pthread_once(once, my_once_callback);
|
||||
}
|
||||
EXPORT int my___pthread_once(x64emu_t* emu, void* once, void* cb) __attribute__((alias("my_pthread_once")));
|
||||
|
||||
@@ -732,8 +730,10 @@ EXPORT int my_pthread_mutex_unlock(pthread_mutex_t *m)
|
||||
static void emujmpbuf_destroy(void* p)
|
||||
{
|
||||
emu_jmpbuf_t *ej = (emu_jmpbuf_t*)p;
|
||||
free(ej->jmpbuf);
|
||||
free(ej);
|
||||
if(ej) {
|
||||
free(ej->jmpbuf);
|
||||
free(ej);
|
||||
}
|
||||
}
|
||||
|
||||
static pthread_key_t jmpbuf_key;
|
||||
@@ -778,4 +778,14 @@ void fini_pthread_helper(box64context_t* context)
|
||||
);
|
||||
kh_destroy(mutex, unaligned_mutex);
|
||||
#endif
|
||||
emu_jmpbuf_t *ejb = (emu_jmpbuf_t*)pthread_getspecific(jmpbuf_key);
|
||||
if(ejb) {
|
||||
emujmpbuf_destroy(ejb);
|
||||
pthread_setspecific(jmpbuf_key, NULL);
|
||||
}
|
||||
emuthread_t *et = (emuthread_t*)pthread_getspecific(thread_key);
|
||||
if(et) {
|
||||
emuthread_destroy(et);
|
||||
pthread_setspecific(thread_key, NULL);
|
||||
}
|
||||
}
|
||||
+87
-3
@@ -29,7 +29,16 @@ int box64_log = LOG_INFO; //LOG_NONE;
|
||||
int box64_nobanner = 0;
|
||||
int box64_dynarec_log = LOG_NONE;
|
||||
int box64_pagesize;
|
||||
#ifdef DYNAREC
|
||||
int box64_dynarec = 1;
|
||||
int box64_dynarec_dump = 0;
|
||||
int box64_dynarec_forced = 0;
|
||||
int box64_dynarec_largest = 0;
|
||||
uintptr_t box64_nodynarec_start = 0;
|
||||
uintptr_t box64_nodynarec_end = 0;
|
||||
#else //DYNAREC
|
||||
int box64_dynarec = 0;
|
||||
#endif
|
||||
int dlsym_error = 0;
|
||||
int trace_xmm = 0;
|
||||
int trace_emm = 0;
|
||||
@@ -128,6 +137,61 @@ void LoadLogEnv()
|
||||
if(!box64_nobanner)
|
||||
printf_log(LOG_INFO, "Debug level is %d\n", box64_log);
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
p = getenv("BOX64_DYNAREC_DUMP");
|
||||
if(p) {
|
||||
if(strlen(p)==1) {
|
||||
if(p[0]>='0' && p[1]<='1')
|
||||
box64_dynarec_dump = p[0]-'0';
|
||||
}
|
||||
if (box64_dynarec_dump) printf_log(LOG_INFO, "Dynarec blocks are dumped%s\n", (box64_dynarec_dump>1)?" in color":"");
|
||||
}
|
||||
p = getenv("BOX64_DYNAREC_LOG");
|
||||
if(p) {
|
||||
if(strlen(p)==1) {
|
||||
if((p[0]>='0'+LOG_NONE) && (p[0]<='0'+LOG_DUMP))
|
||||
box64_dynarec_log = p[0]-'0';
|
||||
} else {
|
||||
if(!strcasecmp(p, "NONE"))
|
||||
box64_dynarec_log = LOG_NONE;
|
||||
else if(!strcasecmp(p, "INFO"))
|
||||
box64_dynarec_log = LOG_INFO;
|
||||
else if(!strcasecmp(p, "DEBUG"))
|
||||
box64_dynarec_log = LOG_DEBUG;
|
||||
else if(!strcasecmp(p, "VERBOSE"))
|
||||
box64_dynarec_log = LOG_DUMP;
|
||||
}
|
||||
printf_log(LOG_INFO, "Dynarec log level is %d\n", box64_dynarec_log);
|
||||
}
|
||||
p = getenv("BOX64_DYNAREC");
|
||||
if(p) {
|
||||
if(strlen(p)==1) {
|
||||
if(p[0]>='0' && p[1]<='1')
|
||||
box64_dynarec = p[0]-'0';
|
||||
}
|
||||
printf_log(LOG_INFO, "Dynarec is %s\n", box64_dynarec?"On":"Off");
|
||||
}
|
||||
p = getenv("BOX64_DYNAREC_FORCED");
|
||||
if(p) {
|
||||
if(strlen(p)==1) {
|
||||
if(p[0]>='0' && p[1]<='1')
|
||||
box64_dynarec_forced = p[0]-'0';
|
||||
}
|
||||
if(box64_dynarec_forced)
|
||||
printf_log(LOG_INFO, "Dynarec is Forced on all addresses\n");
|
||||
}
|
||||
p = getenv("BOX64_NODYNAREC");
|
||||
if(p) {
|
||||
if (strchr(p,'-')) {
|
||||
if(sscanf(p, "%ld-%ld", &box64_nodynarec_start, &box64_nodynarec_end)!=2) {
|
||||
if(sscanf(p, "0x%lX-0x%lX", &box64_nodynarec_start, &box64_nodynarec_end)!=2)
|
||||
sscanf(p, "%lx-%lx", &box64_nodynarec_start, &box64_nodynarec_end);
|
||||
}
|
||||
printf_log(LOG_INFO, "No Dynablock creation that start in %p - %p range\n", (void*)box64_nodynarec_start, (void*)box64_nodynarec_end);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef HAVE_TRACE
|
||||
p = getenv("BOX64_TRACE_XMM");
|
||||
if(p) {
|
||||
@@ -149,6 +213,17 @@ void LoadLogEnv()
|
||||
start_cnt = strtoll(p, &p2, 10);
|
||||
printf_log(LOG_INFO, "Will start trace only after %lu instructions\n", start_cnt);
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
p = getenv("BOX64_DYNAREC_TRACE");
|
||||
if(p) {
|
||||
if(strlen(p)==1) {
|
||||
if(p[0]>='0' && p[1]<='0'+1)
|
||||
box64_dynarec_trace = p[0]-'0';
|
||||
if(box64_dynarec_trace)
|
||||
printf_log(LOG_INFO, "Dynarec generated code will also print a trace\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
// grab BOX64_TRACE_FILE envvar, and change %pid to actual pid is present in the name
|
||||
openFTrace();
|
||||
@@ -345,6 +420,11 @@ void PrintHelp() {
|
||||
printf(" BOX64_LD_LIBRARY_PATH is the box64 version LD_LIBRARY_PATH (default is '.:lib')\n");
|
||||
printf(" BOX64_LOG with 0/1/2/3 or NONE/INFO/DEBUG/DUMP to set the printed debug info\n");
|
||||
printf(" BOX64_NOBANNER with 0/1 to enable/disable the printing of box64 version and build at start\n");
|
||||
#ifdef DYNAREC
|
||||
printf(" BOX64_DYNAREC_LOG with 0/1/2/3 or NONE/INFO/DEBUG/DUMP to set the printed dynarec info\n");
|
||||
printf(" BOX64_DYNAREC with 0/1 to disable or enable Dynarec (On by default)\n");
|
||||
printf(" BOX64_NODYNAREC with address interval (0x1234-0x4567) to forbid dynablock creation in the interval specified\n");
|
||||
#endif
|
||||
#ifdef HAVE_TRACE
|
||||
printf(" BOX64_TRACE with 1 to enable x86_64 execution trace\n");
|
||||
printf(" or with XXXXXX-YYYYYY to enable x86_64 execution trace only between address\n");
|
||||
@@ -353,6 +433,9 @@ void PrintHelp() {
|
||||
printf(" BOX64_TRACE_EMM with 1 to enable dump of MMX registers along with regular registers\n");
|
||||
printf(" BOX64_TRACE_XMM with 1 to enable dump of SSE registers along with regular registers\n");
|
||||
printf(" BOX64_TRACE_START with N to enable trace after N instructions\n");
|
||||
#ifdef DYNAREC
|
||||
printf(" BOX64_DYNAREC_TRACE with 0/1 to disable or enable Trace on generated code too\n");
|
||||
#endif
|
||||
#endif
|
||||
printf(" BOX64_TRACE_FILE with FileName to redirect logs in a file");
|
||||
printf(" BOX64_DLSYM_ERROR with 1 to log dlsym errors\n");
|
||||
@@ -765,7 +848,7 @@ int main(int argc, const char **argv, const char **env) {
|
||||
if(ElfCheckIfUseTCMallocMinimal(elf_header)) {
|
||||
if(!box64_tcmalloc_minimal) {
|
||||
// need to reload with tcmalloc_minimal as a LD_PRELOAD!
|
||||
printf_log(LOG_INFO, "BOX86: tcmalloc_minimal.so.4 used, reloading box64 with the lib preladed\n");
|
||||
printf_log(LOG_INFO, "BOX64: tcmalloc_minimal.so.4 used, reloading box64 with the lib preladed\n");
|
||||
// need to get a new envv variable. so first count it and check if LD_PRELOAD is there
|
||||
int preload=(getenv("LD_PRELOAD"))?1:0;
|
||||
int nenv = 0;
|
||||
@@ -805,7 +888,7 @@ int main(int argc, const char **argv, const char **env) {
|
||||
if(execve(newargv[0], newargv, newenv)<0)
|
||||
printf_log(LOG_NONE, "Failed to relaunch, error is %d/%s\n", errno, strerror(errno));
|
||||
} else {
|
||||
printf_log(LOG_INFO, "BOX86: Using tcmalloc_minimal.so.4, and it's in the LD_PRELOAD command\n");
|
||||
printf_log(LOG_INFO, "BOX64: Using tcmalloc_minimal.so.4, and it's in the LD_PRELOAD command\n");
|
||||
}
|
||||
}
|
||||
// get and alloc stack size and align
|
||||
@@ -850,7 +933,8 @@ int main(int argc, const char **argv, const char **env) {
|
||||
if(ld_preload.size) {
|
||||
for (int i=0; i<ld_preload.size; ++i) {
|
||||
if(AddNeededLib(NULL, NULL, 0, ld_preload.paths[i], my_context, emu)) {
|
||||
printf_log(LOG_INFO, "Warning, cannot pre-load lib: \"%s\"\n", ld_preload.paths[i]);
|
||||
if(!strstr(ld_preload.paths[i], "vgpreload_"))
|
||||
printf_log(LOG_INFO, "Warning, cannot pre-load lib: \"%s\"\n", ld_preload.paths[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+41
-28
@@ -5,7 +5,7 @@
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
|
||||
//#include "custommem.h"
|
||||
#include "custommem.h"
|
||||
#include "bridge.h"
|
||||
#include "bridge_private.h"
|
||||
#include "khash.h"
|
||||
@@ -37,7 +37,9 @@ typedef struct bridge_s {
|
||||
brick_t* NewBrick()
|
||||
{
|
||||
brick_t* ret = (brick_t*)calloc(1, sizeof(brick_t));
|
||||
posix_memalign((void**)&ret->b, box64_pagesize, NBRICK*sizeof(onebridge_t));
|
||||
if(posix_memalign((void**)&ret->b, box64_pagesize, NBRICK*sizeof(onebridge_t))) {
|
||||
printf_log(LOG_NONE, "Warning, cannot allocate 0x%lx aligned bytes for bridge, will probably crash later\n", NBRICK*sizeof(onebridge_t));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -76,43 +78,53 @@ void addBridgeName(void* addr, const char* name);
|
||||
|
||||
uintptr_t AddBridge(bridge_t* bridge, wrapper_t w, void* fnc, int N, const char* name)
|
||||
{
|
||||
pthread_mutex_lock(&bridge->mutex);
|
||||
brick_t *b = bridge->last;
|
||||
if(b->sz == NBRICK) {
|
||||
b->next = NewBrick();
|
||||
b = b->next;
|
||||
bridge->last = b;
|
||||
}
|
||||
brick_t *b = NULL;
|
||||
int sz = -1;
|
||||
#ifdef DYNAREC
|
||||
int prot = 0;
|
||||
if(box64_dynarec) {
|
||||
prot=(getProtection((uintptr_t)b->b)&PROT_DYNAREC)?1:0;
|
||||
if(prot)
|
||||
unprotectDB((uintptr_t)b->b, NBRICK*sizeof(onebridge_t));
|
||||
addDBFromAddressRange((uintptr_t)&b->b[b->sz].CC, sizeof(onebridge_t));
|
||||
}
|
||||
do {
|
||||
#endif
|
||||
pthread_mutex_lock(&bridge->mutex);
|
||||
b = bridge->last;
|
||||
if(b->sz == NBRICK) {
|
||||
b->next = NewBrick();
|
||||
b = b->next;
|
||||
bridge->last = b;
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
sz = b->sz;
|
||||
pthread_mutex_unlock(&bridge->mutex);
|
||||
if(box64_dynarec) {
|
||||
prot=(getProtection((uintptr_t)b->b)&PROT_DYNAREC)?1:0;
|
||||
if(prot)
|
||||
unprotectDB((uintptr_t)b->b, NBRICK*sizeof(onebridge_t));
|
||||
addDBFromAddressRange((uintptr_t)&b->b[b->sz].CC, sizeof(onebridge_t));
|
||||
}
|
||||
} while(sz!=b->sz); // this while loop if someone took the slot when the bridge mutex was unlocked doing memory protection managment
|
||||
pthread_mutex_lock(&bridge->mutex);
|
||||
#endif
|
||||
b->b[b->sz].CC = 0xCC;
|
||||
b->b[b->sz].S = 'S'; b->b[b->sz].C='C';
|
||||
b->b[b->sz].w = w;
|
||||
b->b[b->sz].f = (uintptr_t)fnc;
|
||||
b->b[b->sz].C3 = N?0xC2:0xC3;
|
||||
b->b[b->sz].N = N;
|
||||
b->sz++;
|
||||
b->b[sz].CC = 0xCC;
|
||||
b->b[sz].S = 'S'; b->b[sz].C='C';
|
||||
b->b[sz].w = w;
|
||||
b->b[sz].f = (uintptr_t)fnc;
|
||||
b->b[sz].C3 = N?0xC2:0xC3;
|
||||
b->b[sz].N = N;
|
||||
// add bridge to map, for fast recovery
|
||||
int ret;
|
||||
khint_t k = kh_put(bridgemap, bridge->bridgemap, (uintptr_t)fnc, &ret);
|
||||
kh_value(bridge->bridgemap, k) = (uintptr_t)&b->b[sz].CC;
|
||||
pthread_mutex_unlock(&bridge->mutex);
|
||||
#ifdef DYNAREC
|
||||
if(box64_dynarec && prot)
|
||||
protectDB((uintptr_t)b->b, NBRICK*sizeof(onebridge_t));
|
||||
#endif
|
||||
// add bridge to map, for fast recovery
|
||||
int ret;
|
||||
khint_t k = kh_put(bridgemap, bridge->bridgemap, (uintptr_t)fnc, &ret);
|
||||
kh_value(bridge->bridgemap, k) = (uintptr_t)&b->b[b->sz].CC;
|
||||
pthread_mutex_unlock(&bridge->mutex);
|
||||
#ifdef HAVE_TRACE
|
||||
if(name)
|
||||
addBridgeName(fnc, name);
|
||||
#endif
|
||||
|
||||
return (uintptr_t)&b->b[b->sz++].CC;
|
||||
return (uintptr_t)&b->b[sz].CC;
|
||||
}
|
||||
|
||||
uintptr_t CheckBridged(bridge_t* bridge, void* fnc)
|
||||
@@ -146,7 +158,8 @@ uintptr_t AddAutomaticBridge(x64emu_t* emu, bridge_t* bridge, wrapper_t w, void*
|
||||
addAlternate(fnc, (void*)ret);
|
||||
#ifdef DYNAREC
|
||||
// now, check if dynablock at native address exist
|
||||
DBAlternateBlock(emu, (uintptr_t)fnc, ret);
|
||||
if(box64_dynarec)
|
||||
DBAlternateBlock(emu, (uintptr_t)fnc, ret);
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
|
||||
@@ -209,6 +209,7 @@
|
||||
#() iFiii
|
||||
#() iFiiu
|
||||
#() iFiip
|
||||
#() iFiiO
|
||||
#() iFiuu
|
||||
#() iFiLN
|
||||
#() iFipu
|
||||
@@ -435,6 +436,7 @@
|
||||
#() LFpLLp
|
||||
#() LFpLpp
|
||||
#() LFppii
|
||||
#() LFppLp
|
||||
#() pFEipp
|
||||
#() pFEupp
|
||||
#() pFEpii
|
||||
|
||||
@@ -242,6 +242,7 @@ typedef int32_t (*iFiwC_t)(int32_t, int16_t, uint8_t);
|
||||
typedef int32_t (*iFiii_t)(int32_t, int32_t, int32_t);
|
||||
typedef int32_t (*iFiiu_t)(int32_t, int32_t, uint32_t);
|
||||
typedef int32_t (*iFiip_t)(int32_t, int32_t, void*);
|
||||
typedef int32_t (*iFiiO_t)(int32_t, int32_t, int32_t);
|
||||
typedef int32_t (*iFiuu_t)(int32_t, uint32_t, uint32_t);
|
||||
typedef int32_t (*iFiLN_t)(int32_t, uintptr_t, ...);
|
||||
typedef int32_t (*iFipu_t)(int32_t, void*, uint32_t);
|
||||
@@ -468,6 +469,7 @@ typedef uintptr_t (*LFpuuu_t)(void*, uint32_t, uint32_t, uint32_t);
|
||||
typedef uintptr_t (*LFpLLp_t)(void*, uintptr_t, uintptr_t, void*);
|
||||
typedef uintptr_t (*LFpLpp_t)(void*, uintptr_t, void*, void*);
|
||||
typedef uintptr_t (*LFppii_t)(void*, void*, int32_t, int32_t);
|
||||
typedef uintptr_t (*LFppLp_t)(void*, void*, uintptr_t, void*);
|
||||
typedef void* (*pFEipp_t)(x64emu_t*, int32_t, void*, void*);
|
||||
typedef void* (*pFEupp_t)(x64emu_t*, uint32_t, void*, void*);
|
||||
typedef void* (*pFEpii_t)(x64emu_t*, void*, int32_t, int32_t);
|
||||
@@ -1190,6 +1192,7 @@ void iFiwC(x64emu_t *emu, uintptr_t fcn) { iFiwC_t fn = (iFiwC_t)fcn; R_RAX=fn((
|
||||
void iFiii(x64emu_t *emu, uintptr_t fcn) { iFiii_t fn = (iFiii_t)fcn; R_RAX=fn((int32_t)R_RDI, (int32_t)R_RSI, (int32_t)R_RDX); }
|
||||
void iFiiu(x64emu_t *emu, uintptr_t fcn) { iFiiu_t fn = (iFiiu_t)fcn; R_RAX=fn((int32_t)R_RDI, (int32_t)R_RSI, (uint32_t)R_RDX); }
|
||||
void iFiip(x64emu_t *emu, uintptr_t fcn) { iFiip_t fn = (iFiip_t)fcn; R_RAX=fn((int32_t)R_RDI, (int32_t)R_RSI, (void*)R_RDX); }
|
||||
void iFiiO(x64emu_t *emu, uintptr_t fcn) { iFiiO_t fn = (iFiiO_t)fcn; R_RAX=fn((int32_t)R_RDI, (int32_t)R_RSI, of_convert((int32_t)R_RDX)); }
|
||||
void iFiuu(x64emu_t *emu, uintptr_t fcn) { iFiuu_t fn = (iFiuu_t)fcn; R_RAX=fn((int32_t)R_RDI, (uint32_t)R_RSI, (uint32_t)R_RDX); }
|
||||
void iFiLN(x64emu_t *emu, uintptr_t fcn) { iFiLN_t fn = (iFiLN_t)fcn; R_RAX=fn((int32_t)R_RDI, (uintptr_t)R_RSI, (void*)R_RDX); }
|
||||
void iFipu(x64emu_t *emu, uintptr_t fcn) { iFipu_t fn = (iFipu_t)fcn; R_RAX=fn((int32_t)R_RDI, (void*)R_RSI, (uint32_t)R_RDX); }
|
||||
@@ -1416,6 +1419,7 @@ void LFpuuu(x64emu_t *emu, uintptr_t fcn) { LFpuuu_t fn = (LFpuuu_t)fcn; R_RAX=(
|
||||
void LFpLLp(x64emu_t *emu, uintptr_t fcn) { LFpLLp_t fn = (LFpLLp_t)fcn; R_RAX=(uintptr_t)fn((void*)R_RDI, (uintptr_t)R_RSI, (uintptr_t)R_RDX, (void*)R_RCX); }
|
||||
void LFpLpp(x64emu_t *emu, uintptr_t fcn) { LFpLpp_t fn = (LFpLpp_t)fcn; R_RAX=(uintptr_t)fn((void*)R_RDI, (uintptr_t)R_RSI, (void*)R_RDX, (void*)R_RCX); }
|
||||
void LFppii(x64emu_t *emu, uintptr_t fcn) { LFppii_t fn = (LFppii_t)fcn; R_RAX=(uintptr_t)fn((void*)R_RDI, (void*)R_RSI, (int32_t)R_RDX, (int32_t)R_RCX); }
|
||||
void LFppLp(x64emu_t *emu, uintptr_t fcn) { LFppLp_t fn = (LFppLp_t)fcn; R_RAX=(uintptr_t)fn((void*)R_RDI, (void*)R_RSI, (uintptr_t)R_RDX, (void*)R_RCX); }
|
||||
void pFEipp(x64emu_t *emu, uintptr_t fcn) { pFEipp_t fn = (pFEipp_t)fcn; R_RAX=(uintptr_t)fn(emu, (int32_t)R_RDI, (void*)R_RSI, (void*)R_RDX); }
|
||||
void pFEupp(x64emu_t *emu, uintptr_t fcn) { pFEupp_t fn = (pFEupp_t)fcn; R_RAX=(uintptr_t)fn(emu, (uint32_t)R_RDI, (void*)R_RSI, (void*)R_RDX); }
|
||||
void pFEpii(x64emu_t *emu, uintptr_t fcn) { pFEpii_t fn = (pFEpii_t)fcn; R_RAX=(uintptr_t)fn(emu, (void*)R_RDI, (int32_t)R_RSI, (int32_t)R_RDX); }
|
||||
|
||||
@@ -239,6 +239,7 @@ void iFiwC(x64emu_t *emu, uintptr_t fnc);
|
||||
void iFiii(x64emu_t *emu, uintptr_t fnc);
|
||||
void iFiiu(x64emu_t *emu, uintptr_t fnc);
|
||||
void iFiip(x64emu_t *emu, uintptr_t fnc);
|
||||
void iFiiO(x64emu_t *emu, uintptr_t fnc);
|
||||
void iFiuu(x64emu_t *emu, uintptr_t fnc);
|
||||
void iFiLN(x64emu_t *emu, uintptr_t fnc);
|
||||
void iFipu(x64emu_t *emu, uintptr_t fnc);
|
||||
@@ -465,6 +466,7 @@ void LFpuuu(x64emu_t *emu, uintptr_t fnc);
|
||||
void LFpLLp(x64emu_t *emu, uintptr_t fnc);
|
||||
void LFpLpp(x64emu_t *emu, uintptr_t fnc);
|
||||
void LFppii(x64emu_t *emu, uintptr_t fnc);
|
||||
void LFppLp(x64emu_t *emu, uintptr_t fnc);
|
||||
void pFEipp(x64emu_t *emu, uintptr_t fnc);
|
||||
void pFEupp(x64emu_t *emu, uintptr_t fnc);
|
||||
void pFEpii(x64emu_t *emu, uintptr_t fnc);
|
||||
|
||||
@@ -214,12 +214,12 @@ GOM(dl_iterate_phdr, iFEpp) //Weak
|
||||
//GO(__dprintf_chk,
|
||||
//GO(drand48,
|
||||
//GO(drand48_r,
|
||||
//GOW(dup,
|
||||
//GO(__dup2,
|
||||
//GOW(dup2,
|
||||
//GOW(dup3,
|
||||
//GO(__duplocale,
|
||||
//GOW(duplocale,
|
||||
GOW(dup, iFi)
|
||||
GO(__dup2, iFii)
|
||||
GOW(dup2, iFii)
|
||||
GOW(dup3, iFiiO)
|
||||
GO(__duplocale, pFp)
|
||||
GOW(duplocale, pFp)
|
||||
//GO(dysize,
|
||||
//GOW(eaccess,
|
||||
//GO(ecb_crypt,
|
||||
@@ -1111,7 +1111,7 @@ GO(malloc, pFL) // need to wrap to clear allocated memory?
|
||||
//GOW(mbsinit,
|
||||
//GOW(mbsnrtowcs,
|
||||
//GO(__mbsnrtowcs_chk,
|
||||
//GOW(mbsrtowcs,
|
||||
GOW(mbsrtowcs, LFppLp)
|
||||
//GO(__mbsrtowcs_chk,
|
||||
//GO(mbstowcs,
|
||||
//GO(__mbstowcs_chk,
|
||||
@@ -1497,10 +1497,10 @@ GO2(__realpath_chk, pFppv, my_realpath)
|
||||
//GOW(re_match,
|
||||
//GOW(re_match_2,
|
||||
//DATA(re_max_failures,
|
||||
//GO(remove,
|
||||
GO(remove, iFp)
|
||||
//GO(removexattr,
|
||||
//GO(remque,
|
||||
//GO(rename,
|
||||
GO(rename, iFpp)
|
||||
//GOW(renameat,
|
||||
//GOW(renameat2,
|
||||
//DATAB(_res,
|
||||
@@ -1980,15 +1980,15 @@ GOW(toupper_l, iFip)
|
||||
//GOW(towctrans,
|
||||
//GO(__towctrans_l,
|
||||
//GOW(towctrans_l,
|
||||
//GOW(towlower,
|
||||
//GO(__towlower_l,
|
||||
//GOW(towlower_l,
|
||||
//GOW(towupper,
|
||||
//GO(__towupper_l,
|
||||
//GOW(towupper_l,
|
||||
GOW(towlower, iFi)
|
||||
GO(__towlower_l, iFip)
|
||||
GOW(towlower_l, iFip)
|
||||
GOW(towupper, iFi)
|
||||
GO(__towupper_l, iFip)
|
||||
GOW(towupper_l, iFip)
|
||||
//GO(tr_break,
|
||||
//GOW(truncate,
|
||||
//GOW(truncate64,
|
||||
GOW(truncate, iFpl)
|
||||
GOW(truncate64, iFpI)
|
||||
//GO(__tsearch,
|
||||
//GOW(tsearch,
|
||||
//GO(ttyname,
|
||||
@@ -2092,18 +2092,18 @@ GOW(waitpid, lFlpi)
|
||||
//GO(__wcscat_chk,
|
||||
//GOI(wcschr,
|
||||
//GOW(wcschrnul,
|
||||
//GOI(wcscmp,
|
||||
//GOW(wcscoll,
|
||||
//GO(__wcscoll_l,
|
||||
//GOW(wcscoll_l,
|
||||
//GOI(wcscpy,
|
||||
//GO(__wcscpy_chk,
|
||||
GO(wcscmp, iFpp)
|
||||
GOW(wcscoll, iFpp)
|
||||
GO(__wcscoll_l, iFppp)
|
||||
GOW(wcscoll_l, iFppp)
|
||||
GO(wcscpy, pFpp)
|
||||
GO(__wcscpy_chk, pFppL)
|
||||
//GO(wcscspn,
|
||||
//GO(wcsdup,
|
||||
GO(wcsdup, pFp)
|
||||
//GO(wcsftime,
|
||||
//GO(__wcsftime_l,
|
||||
//GOW(wcsftime_l,
|
||||
//GOI(wcslen,
|
||||
GO(wcslen, LFp)
|
||||
//GOW(wcsncasecmp,
|
||||
//GO(__wcsncasecmp_l,
|
||||
//GOW(wcsncasecmp_l,
|
||||
|
||||
Reference in new issue
Block a user