mirror of
https://github.com/ptitSeb/box86.git
synced 2026-11-08 02:08:33 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32accd0e77 | ||
|
|
c4b3fc25e0 | ||
|
|
676b02b5aa | ||
|
|
3c8e34f691 | ||
|
|
630f42e9e2 | ||
|
|
58b0338dff | ||
|
|
80c77bad96 | ||
|
|
771ff1b2e2 | ||
|
|
cef87f7f7d | ||
|
|
e8d4ffc782 | ||
|
|
85397e9895 | ||
|
|
8194ad9728 | ||
|
|
b82f203a9d | ||
|
|
151e2ae3a4 | ||
|
|
0072524d5d | ||
|
|
949417f412 | ||
|
|
21fea0f195 | ||
|
|
9c1317f899 | ||
|
|
127a48f199 | ||
|
|
66b8c58cc1 | ||
|
|
39bb606c06 | ||
|
|
626826f33e | ||
|
|
a9082f60b6 | ||
|
|
3b394b8f0d | ||
|
|
a108a23c56 | ||
|
|
51baede9c1 | ||
|
|
d601b42ddc | ||
|
|
d430332c45 | ||
|
|
63fae1b6c8 | ||
|
|
c45d3d80ab | ||
|
|
57e9e95411 | ||
|
|
68fb291c83 | ||
|
|
f3ee727bc4 | ||
|
|
21ed47c4cb | ||
|
|
2147d92d9d | ||
|
|
1465ff8aad | ||
|
|
ac895e3dad | ||
|
|
983a3d9926 | ||
|
|
ecec73547f | ||
|
|
6ed82e7f7d | ||
|
|
83a9b2cab5 | ||
|
|
666e41a0cb | ||
|
|
c78be09d7f | ||
|
|
21023e9802 | ||
|
|
38c07f2a2f | ||
|
|
e6d124aed4 | ||
|
|
8335a8c2d9 | ||
|
|
6f7a513051 | ||
|
|
43189a2914 | ||
|
|
3bf9e4d989 | ||
|
|
fe3419957e | ||
|
|
f8c8a5d596 | ||
|
|
9ee7f84015 | ||
|
|
36b316746b | ||
|
|
0131572edf | ||
|
|
d74e873a85 | ||
|
|
be53b823d3 | ||
|
|
e5b6c8b6e0 | ||
|
|
ecf7bfd848 | ||
|
|
2a7b848d0e | ||
|
|
fa5fa7b5c0 | ||
|
|
b7283b8d9d | ||
|
|
b8d72023c5 | ||
|
|
e10a710591 | ||
|
|
9ee030a566 | ||
|
|
a8e96764b5 | ||
|
|
c43f1d882c | ||
|
|
1e67cefc43 | ||
|
|
5cdc1b9fa2 | ||
|
|
ab75a3e2d3 | ||
|
|
21d097853b | ||
|
|
2e3bdbefc7 | ||
|
|
a19773cfb0 | ||
|
|
1988eb0366 | ||
|
|
54d5aaa11d | ||
|
|
205ec1f4dc | ||
|
|
005367ea3c | ||
|
|
8ac9bc30a2 | ||
|
|
f0691e56fc | ||
|
|
bc06c277ec | ||
|
|
1341a4a55f | ||
|
|
82cf77b9d9 | ||
|
|
10db79df4a | ||
|
|
bce188e217 | ||
|
|
220a64af1f | ||
|
|
e73fa8f3fb | ||
|
|
053a75f5d5 | ||
|
|
bcb19dbe5d | ||
|
|
039c62f740 | ||
|
|
7663aacd1b | ||
|
|
fd5bf804ec | ||
|
|
70d18cfb7c | ||
|
|
1e32ccc9c7 | ||
|
|
23fa99d148 | ||
|
|
0e3ce6d8b1 | ||
|
|
970384559f | ||
|
|
2f8a939485 | ||
|
|
4f13c33628 | ||
|
|
4ef5da404c | ||
|
|
15fa9f687c | ||
|
|
331e5700a2 | ||
|
|
1411d44b51 | ||
|
|
bf53a76223 | ||
|
|
ecbc1e6642 | ||
|
|
7dc5b501f3 | ||
|
|
af67f69ee2 | ||
|
|
8f2a4ea880 | ||
|
|
eb44fd62fb | ||
|
|
46f015da9d | ||
|
|
705414a3d0 | ||
|
|
4591d337cb | ||
|
|
54e13be02a | ||
|
|
1524e883cd | ||
|
|
7a65bd60e9 | ||
|
|
8c1694e530 | ||
|
|
292d1455b6 | ||
|
|
9c69702011 | ||
|
|
3554d6decb | ||
|
|
7fb36acf85 | ||
|
|
ed3296978e | ||
|
|
4b212f91bf | ||
|
|
94f451c4b7 | ||
|
|
13bbf105ad | ||
|
|
3eb16fb7bd | ||
|
|
e85bcb671a | ||
|
|
1a0888ca51 | ||
|
|
3043f5066f | ||
|
|
b3b55d2d74 | ||
|
|
58426cbfb6 | ||
|
|
4a88ff38ea | ||
|
|
8d96ff02e3 | ||
|
|
eaa6ecb9cc | ||
|
|
027909bddc | ||
|
|
0eca6a8b94 | ||
|
|
24494ba143 | ||
|
|
a813321ad4 | ||
|
|
a43884ff66 | ||
|
|
27b269f53a |
No files matched your search
+56
-16
@@ -29,6 +29,9 @@ option(HAVE_TRACE "Set to ON to have Trace ability (needs ZydisInfo library)" ${
|
||||
option(NOLOADADDR "Set to ON to avoid fixing the load address of Box86" ${NO_LOADAADR})
|
||||
option(NOGETCLOCK "Set to ON to avoid using clock_gettime with CLOCK_MONOTONIC_COARSE for RDTSC opcode (use gltimeofday instead)" ${NOGETCLOCK})
|
||||
option(NOGIT "Set to ON if not building from a git clone repo (like when building from a zip download from github)" ${NOGIT})
|
||||
option(NO_LIB_INSTALL "Set ON to not install a few x86 libs that are used by many program" ${NO_LIB_INSTALL})
|
||||
option(NO_CONF_INSTALL "Set ON to not install config files" ${NO_CONF_INSTALL})
|
||||
|
||||
if(PANDORA OR PYRA OR RPI2 OR RPI3 OR RPI4 OR GAMESHELL OR ODROID OR GOA_CLONE OR RK3288 OR RK3399 OR ODROIDN2 OR TEGRAX1 OR TEGRAX1ARM32 OR RPI3ARM64 OR RPI4ARM64 OR PHYTIUM OR SD845 OR A64 OR LX2160A OR ARM64 OR RK3588)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
@@ -297,9 +300,6 @@ set(ELFLOADER_SRC
|
||||
"${BOX86_ROOT}/src/librarian/symbols.c"
|
||||
"${BOX86_ROOT}/src/librarian/globalsymbols.c"
|
||||
"${BOX86_ROOT}/src/emu/x86emu.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run66.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run660f.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run_private.c"
|
||||
"${BOX86_ROOT}/src/emu/x86syscall.c"
|
||||
"${BOX86_ROOT}/src/emu/x86primop.c"
|
||||
@@ -307,7 +307,6 @@ set(ELFLOADER_SRC
|
||||
"${BOX86_ROOT}/src/emu/x86int3.c"
|
||||
"${BOX86_ROOT}/src/emu/x86tls.c"
|
||||
"${BOX86_ROOT}/src/emu/x87emu_private.c"
|
||||
"${BOX86_ROOT}/src/emu/x87run.c"
|
||||
"${BOX86_ROOT}/src/libtools/auxval.c"
|
||||
"${BOX86_ROOT}/src/libtools/myalign.c"
|
||||
"${BOX86_ROOT}/src/libtools/myalign64.c"
|
||||
@@ -324,6 +323,33 @@ if(NOT ANDROID)
|
||||
list(APPEND ELFLOADER_SRC "${BOX86_ROOT}/src/libtools/obstack.c")
|
||||
endif()
|
||||
|
||||
set(INTERPRETER
|
||||
"${BOX86_ROOT}/src/emu/x86run.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run0f.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run64.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run640f.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run6466.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run6467.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run66.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run660f.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run66d9.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run66dd.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run67.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run6766.c"
|
||||
"${BOX86_ROOT}/src/emu/x86rund8.c"
|
||||
"${BOX86_ROOT}/src/emu/x86rund9.c"
|
||||
"${BOX86_ROOT}/src/emu/x86runda.c"
|
||||
"${BOX86_ROOT}/src/emu/x86rundb.c"
|
||||
"${BOX86_ROOT}/src/emu/x86rundc.c"
|
||||
"${BOX86_ROOT}/src/emu/x86rundd.c"
|
||||
"${BOX86_ROOT}/src/emu/x86runde.c"
|
||||
"${BOX86_ROOT}/src/emu/x86rundf.c"
|
||||
"${BOX86_ROOT}/src/emu/x86runf0.c"
|
||||
"${BOX86_ROOT}/src/emu/x86runf066.c"
|
||||
"${BOX86_ROOT}/src/emu/x86runf20f.c"
|
||||
"${BOX86_ROOT}/src/emu/x86runf30f.c"
|
||||
)
|
||||
|
||||
set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibc.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibpthread.c"
|
||||
@@ -492,6 +518,7 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedpcap.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedfaudio.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedtbbmallocproxy.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibfuse.c"
|
||||
)
|
||||
if(ANDROID)
|
||||
list(APPEND WRAPPEDS
|
||||
@@ -545,7 +572,9 @@ if(ARM_DYNAREC)
|
||||
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_functions.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_jmpnext.c"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_printer.c"
|
||||
"${BOX86_ROOT}/src/emu/x86test.c"
|
||||
|
||||
"${BOX86_ROOT}/src/dynarec/arm_prolog.S"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_epilog.S"
|
||||
@@ -593,6 +622,8 @@ if(ARM_DYNAREC)
|
||||
set_target_properties(arm_pass2 PROPERTIES COMPILE_FLAGS "-DSTEP=2")
|
||||
add_library(arm_pass3 OBJECT ${DYNAREC_PASS})
|
||||
set_target_properties(arm_pass3 PROPERTIES COMPILE_FLAGS "-DSTEP=3")
|
||||
add_library(test_interpreter OBJECT ${INTERPRETER})
|
||||
set_target_properties(test_interpreter PROPERTIES COMPILE_FLAGS "-DTEST_INTERPRETER")
|
||||
add_dependencies(arm_pass0 WRAPPERS)
|
||||
add_dependencies(arm_pass1 WRAPPERS)
|
||||
add_dependencies(arm_pass2 WRAPPERS)
|
||||
@@ -604,6 +635,7 @@ if(ARM_DYNAREC)
|
||||
$<TARGET_OBJECTS:arm_pass1>
|
||||
$<TARGET_OBJECTS:arm_pass2>
|
||||
$<TARGET_OBJECTS:arm_pass3>
|
||||
$<TARGET_OBJECTS:test_interpreter>
|
||||
)
|
||||
|
||||
endif()
|
||||
@@ -613,16 +645,18 @@ if(ARM_DYNAREC)
|
||||
add_custom_command(
|
||||
OUTPUT "${BOX86_ROOT}/src/git_head.h"
|
||||
COMMAND bash -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX86_ROOT}/src/git_head.h\""
|
||||
DEPENDS dynarec ${ELFLOADER_SRC} ${WRAPPEDS}
|
||||
DEPENDS dynarec ${ELFLOADER_SRC} ${INTERPRETER} ${WRAPPEDS}
|
||||
VERBATIM)
|
||||
else()
|
||||
add_custom_command(
|
||||
OUTPUT "${BOX86_ROOT}/src/git_head.h"
|
||||
COMMAND bash -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX86_ROOT}/src/git_head.h\""
|
||||
DEPENDS ${ELFLOADER_SRC} ${WRAPPEDS}
|
||||
DEPENDS ${ELFLOADER_SRC} ${INTERPRETER} ${WRAPPEDS}
|
||||
VERBATIM)
|
||||
endif()
|
||||
|
||||
add_library(interpreter OBJECT ${INTERPRETER})
|
||||
|
||||
if(BOX86LIB)
|
||||
#build a static or dynamic lib...
|
||||
if(BOX86DYNAMIC)
|
||||
@@ -632,9 +666,9 @@ else()
|
||||
endif()
|
||||
if(ARM_DYNAREC)
|
||||
if(ANDROID)
|
||||
target_link_libraries(${BOX86} dynarec m dl)
|
||||
target_link_libraries(${BOX86} dynarec interpreter m dl)
|
||||
else()
|
||||
target_link_libraries(${BOX86} dynarec m dl rt pthread resolv)
|
||||
target_link_libraries(${BOX86} dynarec interpreter m dl rt pthread resolv)
|
||||
endif()
|
||||
endif()
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.13")
|
||||
@@ -660,7 +694,9 @@ else()
|
||||
set_target_properties(${BOX86} PROPERTIES LINK_FLAGS "-Wl,--no-as-needed -lc -lm -ldl -lrt -lpthread -lresolv -Wl,--as-needed -pthread")
|
||||
endif()
|
||||
if(ARM_DYNAREC)
|
||||
target_link_libraries(${BOX86} dynarec)
|
||||
target_link_libraries(${BOX86} dynarec interpreter)
|
||||
else()
|
||||
target_link_libraries(${BOX86} interpreter)
|
||||
endif()
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.13")
|
||||
@@ -679,13 +715,17 @@ endif()
|
||||
if(NOT _x86 AND NOT _x86_64)
|
||||
install(TARGETS ${BOX86}
|
||||
RUNTIME DESTINATION bin)
|
||||
configure_file(system/box86.conf.cmake system/box86.conf)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/system/box86.conf DESTINATION /etc/binfmt.d/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.6 DESTINATION /usr/lib/i386-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.5 DESTINATION /usr/lib/i386-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libgcc_s.so.1 DESTINATION /usr/lib/i386-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libpng12.so.0 DESTINATION /usr/lib/i386-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/system/box86.box86rc DESTINATION /etc/)
|
||||
if(NOT NO_CONF_INSTALL)
|
||||
configure_file(system/box86.conf.cmake system/box86.conf)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/system/box86.conf DESTINATION /etc/binfmt.d/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/system/box86.box86rc DESTINATION /etc/)
|
||||
endif()
|
||||
if(NOT NO_LIB_INSTALL)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.6 DESTINATION /usr/lib/i386-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.5 DESTINATION /usr/lib/i386-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libgcc_s.so.1 DESTINATION /usr/lib/i386-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libpng12.so.0 DESTINATION /usr/lib/i386-linux-gnu/)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET uninstall)
|
||||
|
||||
Vendored
+2
-1
@@ -6,7 +6,8 @@
|
||||
override_dh_auto_configure:
|
||||
dh_auto_configure -- \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DARM_DYNAREC=1
|
||||
-DARM_DYNAREC=1 \
|
||||
-DNOGIT=1
|
||||
|
||||
override_dh_shlibdeps:
|
||||
dh_shlibdeps --exclude=libgcc_s.so.1 --exclude=libpng12.so.0 --exclude=libstdc++.so.5 --exclude=libstdc++.so.6
|
||||
@@ -1,3 +1,16 @@
|
||||
v0.3.2
|
||||
======
|
||||
* Better syscall handling
|
||||
* Fixed some wrapped functions, added some others
|
||||
* Introduced another wrapper helper
|
||||
* Added some more opcodes
|
||||
* Added a cosimulation mode (to compare the behaviour of the dynarec against the interpreter)
|
||||
* Added support of FASTNAN for some more opcodes
|
||||
* Reduced memory footprint
|
||||
* Added BOX86_NOSANDBOX (adds an argument to the command line)
|
||||
* Added an ukrainian translation
|
||||
=> Mostly a stability update with improved elfloader, fixed opcodes and refined profiles
|
||||
|
||||
v0.3.0
|
||||
======
|
||||
* Added rcfile handling: box86 now read `/etc/box86.box86rc` and `~/.box86rc` and apply per process parameters
|
||||
|
||||
+3
-3
@@ -6,7 +6,7 @@ You can use [@Itai-Nelken](https://github.com/Itai-Nelken)'s apt repository to i
|
||||
|
||||
```
|
||||
sudo wget https://itai-nelken.github.io/weekly-box86-debs/debian/box86.list -O /etc/apt/sources.list.d/box86.list
|
||||
wget -qO- https://itai-nelken.github.io/weekly-box86-debs/debian/KEY.gpg | sudo apt-key add -
|
||||
wget -qO- https://itai-nelken.github.io/weekly-box86-debs/debian/KEY.gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/box86-debs-archive-keyring.gpg
|
||||
sudo apt update && sudo apt install box86 -y
|
||||
```
|
||||
|
||||
@@ -117,7 +117,7 @@ Also, on armbian, you may need to install `libc6-dev-armhf-cross` or you may hav
|
||||
|
||||
#### for Other ARM64 64bits Linux platform
|
||||
|
||||
`mkdir build; cd build; cmake .. -DARM64 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
`mkdir build; cd build; cmake .. -DARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
|
||||
You can also add `-DBAD_SIGNAL=ON` to the cmake command if you are on Linux Kernel mixed with Android, like on RK3588 or maybe Termux
|
||||
|
||||
@@ -194,5 +194,5 @@ NVIDIA doesn't provide armhf libraries for their GPU drivers at this time. There
|
||||
|
||||
Debian Packaging
|
||||
----
|
||||
Box86 can also be packaged into a .deb file with `DEB_BUILD_OPTIONS=nostrip dpkg-buildpackage -us -uc -nc`.
|
||||
Box86 can also be packaged into a .deb file ***using the source code zip from the releases page*** with `DEB_BUILD_OPTIONS=nostrip dpkg-buildpackage -us -uc -nc`. Configure any additional cmake options you might want in `debian/rules`.
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
|
||||
Linux Userspace x86 Emulator with a twist
|
||||
|
||||
[View changelog](https://github.com/ptitSeb/box86/blob/master/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box86/blob/master/docs/README_CN.md) | [Report an error](https://github.com/ptitSeb/box86/issues/new)
|
||||
[View changelog](https://github.com/ptitSeb/box86/blob/master/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box86/blob/master/docs/README_CN.md) | [Українська](https://github.com/ptitSeb/box86/blob/master/docs/README_UK.md) | [Report an error](https://github.com/ptitSeb/box86/issues/new)
|
||||
|
||||
     
|
||||
|
||||
@@ -88,7 +88,7 @@ So, your settings in `~/.bashrc` may override the setting from your command line
|
||||
Notes about Unity game emulation
|
||||
----
|
||||
|
||||
Running Unity games shoudl generaly work now, but you should also note that many Unity3D games require OpenGL 3+ which can be tricky to provide on ARM SBC (single-board computers) for now.
|
||||
Running Unity games should generaly work now, but you should also note that many Unity3D games require OpenGL 3+ which can be tricky to provide on ARM SBC (single-board computers) for now.
|
||||
Hint: on Pi4, use `MESA_GL_VERSION_OVERRIDE=3.2` and with Panfrost use `PAN_MESA_DEBUG=gl3` to use higher profile if the game starts then quits before showing anything.
|
||||
|
||||
----
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
Linux用户空间的x86应用模拟器
|
||||
|
||||
[更新历史](https://github.com/ptitSeb/box86/blob/master/docs/CHANGELOG.md) | [English](https://github.com/ptitSeb/box86/blob/master/docs/README.md) | [报告错误](https://github.com/ptitSeb/box86/issues/new)
|
||||
[更新历史](https://github.com/ptitSeb/box86/blob/master/docs/CHANGELOG.md) | [English](https://github.com/ptitSeb/box86/blob/master/docs/README.md) | [Українська](https://github.com/ptitSeb/box86/blob/master/docs/README_UK.md) | [报告错误](https://github.com/ptitSeb/box86/issues/new)
|
||||
|
||||
     
|
||||
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||

|
||||
|
||||
Емулятор простіра користувача x86_64 із родзинкою
|
||||
|
||||
[Дивитись журнал змін](https://github.com/ptitSeb/box86/blob/master/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box86/blob/master/docs/README_CN.md) | [Українська](https://github.com/ptitSeb/box86/blob/master/docs/README_UK.md) | [Повідомити про помилку](https://github.com/ptitSeb/box86/issues/new)
|
||||
|
||||
     
|
||||
|
||||
----
|
||||
|
||||
Box86 дозволяє запускати x86 Linux програми (наприклад, ігри) на системах Linux відмінних від x86, наприклад ARM (хост-система має мати 32-розрядний порядок редагування).
|
||||
|
||||
Вам *ПОТРІБНА* 32-розрядна підсистема для запуску та створення Box86. Box86 марний лише на 64-розрядних системах. Крім того, вам *ПОТРІБЕН* 32-розрядний інструментарій для створення Box86. Ланцюжок інструментів, який підтримує лише 64-розрядні версії, не компілює Box86, і ви отримаєте помилки (зазвичай на aarch64 ви отримуєте що «-marm» не розпізнається, і вам знадобиться середовище з мультиархітектурою або chroot).
|
||||
|
||||
Оскільки Box86 використовує рідні версії деяких «системних» бібліотек, таких як libc, libm, SDL і OpenGL, його легко інтегрувати та використовувати з більшістю програм, а продуктивність у багатьох випадках може бути напрочуд високою. Подивіться на цей стендовий аналіз для прикладу [тут](https://box86.org/index.php/2021/06/game-performances/). Це також означає, що вам знадобиться 32-бітний простір користувача на 64-бітній ОС, наприклад `armhf` поверх `aarch64` 64-бітної ОС.
|
||||
|
||||
Більшість x86-ігор потребують OpenGL, тому на платформах ARM може знадобитися таке рішення, як [gl4es](https://github.com/ptitSeb/gl4es). (Деякі платформи ARM підтримують лише OpenGL ES і/або їх реалізація OpenGL хитра. (див. OpenGL на Android))
|
||||
|
||||
Box86 інтегрується з DynaRec (динамічний рекомпілятор) для платформ ARM64 і RV64 забезпечуючи підвищення швидкості в 5-10 разів, ніж використання лише інтерпретатора. Деякі високорівневі відомості про те, як працює DynaRec, можна знайти [тут](https://box86.org/2021/07/inner-workings-a-high%e2%80%91level-view-of-box86-and-a-low%e2%80%91level-view-of-the-dynarec/).
|
||||
|
||||
Багато ігор просто працюють без особливих налаштувань, наприклад: WorldOfGoo, Airline Tycoon Deluxe і FTL. Багато ігор GameMaker Linux також працюють нормально. (є довгий список, серед них UNDERTALE, A Risk of Rain і Cook Serve Delicious). Ігри Unity3D також працюють добре, але вимога OpenGL може бути проблемою на деяких платформах ARM.
|
||||
|
||||
Якщо ви серйозно ставитеся до розробки Box86, вам слід встановити ccache та створити Box86 з ним. (Використовуйте, наприклад, ccmake.)
|
||||
Щоб увімкнути TRACE (тобто скидання в stdout усіх окремих виконаних інструкцій x86 із дампом регістрів), вам також знадобиться [бібліотека Zydis](https://github.com/zyantific/zydis), доступна у вашій системі.
|
||||
|
||||
Деякі внутрішні коди операцій x86 використовують частини «Бібліотеки емулятора Realmode X86», дивіться [x86primop.c](../src/emu/x86primop.c) для детальної інформації про авторські права.
|
||||
|
||||
----
|
||||
Компіляція/Встановлення
|
||||
----
|
||||
> Інструкцію зі складання Box86 можна знайти [тут](COMPILE.md).\
|
||||
> Інструкцію з встановлення Wine для Box86 можна знайти [тут](X86WINE.md).
|
||||
|
||||
----
|
||||
|
||||
Ось 6 відео, перші 2 відео – це відео "Airline Tycoon Deluxe" і "Heretic 2", які працюють на GigaHertz OpenPandora (друге використовує Dynarec), а наступні 2 відео – це відео "Bit.Trip.Runner" і "Neverwinter Night", які працюють на ODroid XU4 (без dynarec), а останні 2 відео на Pi4: Shovel Knight (відео від @ITotalJustice) і Freedom Planet (відео від @djazz), також без Dynarec.
|
||||
|
||||
|
||||
[](https://www.youtube.com/watch?v=bLt0hMoFDLk) [](https://www.youtube.com/watch?v=MM7kWYts7IA) [](https://www.youtube.com/watch?v=8hr71S029Hg) [](https://www.youtube.com/watch?v=B4YN37z3-ws) [](https://www.youtube.com/watch?v=xk8Q30mxqPg) [](https://www.youtube.com/watch?v=_QMRMVvYrqU)
|
||||
|
||||
Ви можете знайти багато інших відео про Box86 у YouTube каналах [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ), [Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) або [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA).
|
||||
|
||||
Список сумісності доступний тут: https://github.com/ptitSeb/box86-compatibility-list/issues
|
||||
|
||||
<img src="img/Box86Icon.png" width="96" height="96">
|
||||
|
||||
Логотип і піктограма зроблені @grayduck, дякую!
|
||||
|
||||
Зауважте, що цей проект не слід плутати з [86box](https://github.com/86Box/86Box), гарним емулятором "повної системи", що спеціалізується на ранньому (до відносно недавньому) апаратному забезпеченні ПК.
|
||||
|
||||
----
|
||||
|
||||
Використання
|
||||
----
|
||||
|
||||
Є кілька змінних середовища для керування поведінкою Box86.
|
||||
|
||||
Дивіться [тут](USAGE.md) для перегляду всіх змінних середовища та того, що вони роблять.
|
||||
|
||||
Примітка: Dynarec від Box86 використовує механізм із захистом пам’яті та обробником сигналу помилки сегментів для обробки JIT коду. Простіше кажучи, якщо ви хочете використовувати GDB для налагодження запущеної програми, яка використовує JIT-код (наприклад, mono/Unity3D), ви все одно матимете багато «звичайних» помилок сегментів. Пропонується використовувати щось на зразок `handle SIGSEGV nostop` в GDB, щоб не зупинятися на кожній помилці сегмента, і, можливо, поставити точку зупину всередині `my_memprotectionhandler` в `signals.c`, якщо ви хочете перехопити помилки сегментів.
|
||||
|
||||
----
|
||||
|
||||
Історія версій/Журнал змін
|
||||
----
|
||||
|
||||
Історія версій доступна [тут](docs/CHANGELOG.md).
|
||||
|
||||
----
|
||||
|
||||
Примітки щодо 64-розрядних платформ
|
||||
----
|
||||
|
||||
Оскільки Box86 працює шляхом прямого перекладу викликів функцій із x86 на хост-систему, хост-система (на якій працює Box86) повинна мати 32-розрядні бібліотеки. Box86 не містить 32-біт <-> 64-біт перекладу. Отже, щоб запустити Box86, наприклад, на платформі ARM64, вам потрібно буде зібрати Box86 для 32-бітної ARM, а також потрібно мати chroot з 32-бітними бібліотеками.
|
||||
|
||||
Якщо ви дивитесь на 64-розрядну версію box86, подивіться на [Box64](https://github.com/ptitSeb/box64): він може запускати двійкові файли x86_64 на 64-розрядних платформах. Але зауважте, що вам все одно потрібен Box86 (і 32-розрядний chroot) для запуску бінарних файлів x86 (як це також трапляється в реальному Linux x86_64, для запуску якого потрібні бібліотеки x86 і двійковий файл в multiarch).
|
||||
|
||||
----
|
||||
|
||||
Примітки щодо конфігурації Box86
|
||||
----
|
||||
|
||||
Box86 тепер має конфігураційні файли. Завантажуються 2 файли: `/etc/box4.box86rc` і `~/.box86rc`. Обидва файли мають однаковий синтаксис і в основному є файлами ini. Розділ у квадратних дужках визначає назву процесу, а решта — встановлють змінну середовища. Подивіться на [використання](docs/USAGE.md), щоб дізнатися, які параметри можна використовувати. Box86 поставляється з файлом за замовчуванням, який слід інсталювати для кращої стабільності. Файл знаходиться в `system/box86.box86rc` і має бути встановлено в `/etc/box86.box86rc`. Якщо з певних причин ви не хочете встановлювати цей файл у `/etc`, принаймні скопіюйте його в `~/.box86rc` або гра може не працювати належним чином. Зауважте, що пріоритетом є: `~/.bashrc` > `/etc/box86.box86rc` > командний рядок
|
||||
Таким чином, ваші налаштування в `~/.bashrc` можуть замінити налаштування з вашого командного рядка...
|
||||
|
||||
----
|
||||
|
||||
Примітки щодо емуляції ігор Unity
|
||||
----
|
||||
|
||||
Запуск ігор Unity має працювати, але ви також повинні зауважити, що для багатьох ігор Unity3D потрібен OpenGL 3+, який може бути складно забезпечити на ARM SBC (одноплатних комп’ютерах). Крім того, багато нових ігор Unity3D (наприклад, KSP) використовують стиснуті текстури BC7, які не підтримуються багатьма інтегрованими GPU ARM.
|
||||
Підказка: в Pi4 використовуйте `MESA_GL_VERSION_OVERRIDE=3.2`, а в Panfrost — `PAN_MESA_DEBUG=gl3`, щоб використовувати вищий профіль, якщо гра запускається, а потім завершується, перш ніж щось показує.
|
||||
|
||||
----
|
||||
|
||||
Примітки щодо Steam
|
||||
----
|
||||
|
||||
Linux версія Steam тепер може працювати з Box86, але вам також потрібен Box64, щоб його можна було повністю використовувати.
|
||||
Рекомендується запускати Steam у small режимі, оскільки він використовує менше пам’яті, але steamwebhelper (64-бітний процес) усе одно завантажуватиметься, навіть якщо він не використовується.
|
||||
Екран входу не може працювати без steamwebhelper, і буде показувати лише порожні вікна без належного налаштування box64 у системі.
|
||||
Зауважте, що Steam використовуватиме багато пам’яті та ледве поміститься в систему з 4 ГБ оперативної пам’яті. Він більше не працюватиме в системі з меншим об’ємом пам’яті (як обхідний шлях, створіть файл підкачки, увійдіть і поставте прапорець «запам’ятати мене», використовуйте box64rc, щоб вимкнути steamwebhelper і запускати лише в малому режимі без підкачки після першого входу в систему)
|
||||
Останнє зауваження: Steam BigPicture працюватиме, але також потрібен steamwebhelper (і box64) і багато пам’яті. Він не запуститься в системі лише з 4 ГБ оперативної пам’яті без файлу підкачки.
|
||||
- Якщо у вас виникли проблеми зі встановленням Steam, ви можете знайти `install_steam.sh` у кореневій папці сховища box86. Цей простий скрипт завантажить і встановить Steam у вашу домашню папку, а потім створить ярлик steam у `/usr/local/bin` (для цього він запитає дозвіл sudo). Просто використовуйте `steam` для запуску після встановлення. Зауважте, що інсталяція, яка знаходиться в папці Home, працюватиме лише для одного користувача. Не використовуйте цей скрипт, якщо вам потрібна багатокористувацька інсталяція.
|
||||
- Щоб уникнути повідомлення «libc.so.6 відсутній», ви можете використовувати `STEAMOS=1` і `STEAM_RUNTIME=1` як змінні середовища (воно автоматично з’являється, якщо ви використовували сценарій `install_steam.sh`)
|
||||
|
||||
Щоб вимкнути `steamwebhelper`, коли Box64 встановлений і працює, створіть (або відредагуйте) `~/.box64rc` і додайте у ньому:
|
||||
```
|
||||
[steamwebhelper]
|
||||
BOX64_EXIT=1
|
||||
```
|
||||
І тоді `steamwebhelper` буде вимкнено. Прокоментуйте `#` ці 2 рядки, щоб увімкнути його знову.
|
||||
|
||||
----
|
||||
|
||||
Примітки щодо Wine
|
||||
----
|
||||
|
||||
Wine тепер підтримується. Інтегровани програми Wine працює як і багато програм та ігор для Windows. Не забувайте, що більшість ігор для Windows використовують Direct3D, для цього може знадобитися повний драйвер OpenGL і якомога більш високий профіль (і gl4es з бекендом ES2 наразі мають проблеми з Wine).
|
||||
Примітка: якщо ви плануєте використовувати box86 з Wine на Raspberry Pi 3 або ранішої версії, ці моделі використовують ОС за замовчуванням, яка має ядро з розділенням 2/2 (тобто 2G місця для програми користувача та 2 Г місця для ядра). Це несумісно з програмами Wine, яким потрібен доступ до пам’яті > 2 Гб адреси. Тож вам потрібно буде переналаштувати ядро для розділення 3G/1G.
|
||||
|
||||
----
|
||||
|
||||
Примітки щодо Vulkan
|
||||
----
|
||||
|
||||
Box86 вже використовує Vulkan. Якщо у вашій системі є 32-розрядний драйвер Vulkan, Box86 використовуватиме його за потреби. Профіль 1.0, 1.1, 1.2 і 1.3, з деякими розширеннями, має бути в порядку. DXVK, включаючи 2.0, працює. Я знаю, що деякі демонстраційні версії працюють на Pi4 (демонстраційні версії Sascha Willems для x86 працюють так само, як якщо б створювати безпосередньо на armhf). Зауважте, що драйвер Vulkan для Pi4 наразі НЕ підтримує DXVK (обгортка Wine DirectX->Vulkan). Це не проблема Box86, у драйвері відсутні розширення (підтримка апаратного забезпечення) та кілька інших речей, через які DXVK не працює на pi4. З боку Panfrost, PanVK трохи молодий, і я ще не тестував DXVK з ним.
|
||||
|
||||
----
|
||||
Останнє слово
|
||||
----
|
||||
|
||||
Я хочу подякувати всім, хто зробив внесок у розвиток box86.
|
||||
Є багато способів зробити свій внесок: код, фінанси, апаратне забезпечення та реклама!
|
||||
Отже, без особливого порядку, я хочу подякувати:
|
||||
* За основний внесок у код: rajdakin, icecream95, M-HT
|
||||
* За великий фінансовий внесок: FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* За внесок у апаратне забезпечення: [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [DragonBox](https://pyra-handheld.com/), [Novaspirit](https://www.youtube.com/channel/UCrjKdwxaQMSV_NDywgKXVmw), [HardKernel](https://www.hardkernel.com/), [Команда TwisterOS](https://twisteros.com/)
|
||||
* За постійну рекламу Box86: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[Команда TwisterOS](https://twisteros.com/), [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg)
|
||||
|
||||
І я також дякую багатьом іншим людям, які хоч раз брали участь у проекті.
|
||||
|
||||
(Якщо ви використовуєте Box86 у своєму проекті, будь ласка, не забудьте згадати про це!)
|
||||
@@ -127,6 +127,11 @@ Enables/Disables trace for generated code.
|
||||
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)
|
||||
|
||||
#### BOX86_DYNAREC_TEST *
|
||||
Dynarec will compare it's execution with the interpreter (super slow, only for testing)
|
||||
* 0 : No comparison
|
||||
* 1 : Each opcode runs on interepter and on Dynarec, and regs and memory are compared and print if different
|
||||
|
||||
#### BOX86_DYNAREC_BIGBLOCK *
|
||||
Enables/Disables Box86's Dynarec building BigBlock.
|
||||
* 0 : Don't try to build block as big as possible (can help program using lots of thread and a JIT, like C#/Unity) (Default when libmonobdwgc-2.0.so is loaded)
|
||||
@@ -170,11 +175,26 @@ Handling of HotPage (Page beeing both executed and writen)
|
||||
* 0 : Don't track hotpage
|
||||
* 1-255 : Trak HotPage, and disable execution of a page beeing writen for N attempts (default is 16)
|
||||
|
||||
#### BOX86_DYNAREC_FASTPAGE *
|
||||
Will use a faster handling of HotPage (Page being both executed and written)
|
||||
* 0 : use regular hotpage (Default)
|
||||
* 1 : Use faster hotpage, taking the risk of running obsolete JIT code (might be faster, but more prone to crash)
|
||||
|
||||
#### BOX86_DYNAREC_BLEEDING_EDGE *
|
||||
Detect MonoBleedingEdge and apply conservative settings
|
||||
* 0 : Don't detect MonoBleedingEdge
|
||||
* 1 : Detect MonoBleedingEdge, and apply BIGBLOCK=0 STRONGMEM=1 if detected (Default)
|
||||
|
||||
#### BOX86_DYNAREC_JVM *
|
||||
Detect libjvm and apply conservative settings
|
||||
* 0 : Don't detect libjvm
|
||||
* 1 : Detect libjvm, and apply BIGBLOCK=0 STRONGMEM=1 if detected (Default)
|
||||
|
||||
#### BOX86_DYNAREC_WAIT *
|
||||
Behavior with FillBlock is not availble (FillBlock build Dynarec blocks and is not multithreaded)
|
||||
* 0 : Dynarec will not wait for FillBlock to ready and use Interpreter instead (might speedup a bit massive multithread or JIT programs)
|
||||
* 1 : Dynarec will wait for FillBlock to be ready (Default)
|
||||
|
||||
#### BOX86_SSE_FLUSHTO0 *
|
||||
Handling of SSE Flush to 0 flags
|
||||
* 0 : Just track the flag (Default)
|
||||
@@ -185,6 +205,11 @@ Handling of x87 80bits long double
|
||||
* 0 : Try to handle 80bits long double as precise as possible (Default)
|
||||
* 1 : Handle them as double
|
||||
|
||||
#### BOX86_LIBCEF *
|
||||
Detect libcef and apply malloc_hack settings
|
||||
* 0 : Don't detect libcef
|
||||
* 1 : Detect libcef, and apply MALLOC_HACK=2 if detected (Default)
|
||||
|
||||
#### BOX86_LIBGL *
|
||||
* libXXXX set the name for libGL (defaults to libGL.so.1).
|
||||
* /PATH/TO/libGLXXX : Sets the name and path for libGL
|
||||
@@ -281,3 +306,8 @@ Will use yyyy as x86_64 interpretor, to launch x64_64 binaries
|
||||
|
||||
#### BOX86_NORCFILES
|
||||
If the env var exist, no rc files (like /etc/box86.box86rc and ~/.box86rc) will be loaded
|
||||
|
||||
#### BOX86_NOSANDBOX
|
||||
* 0 : Nothing special
|
||||
* 1 : Added "--no-sandbox" to command line arguments (usefull for chrome based programs)
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ rm ~/wine.tgz # clean up
|
||||
|
||||
# Install shortcuts (make launcher & symlinks. Credits: grayduck, Botspot)
|
||||
echo -e '#!/bin/bash\nsetarch linux32 -L '"$HOME/wine/bin/wine "'"$@"' | sudo tee -a /usr/local/bin/wine >/dev/null # Create a script to launch wine programs as 32bit only
|
||||
#sudo ln -s ~/wine/bin/wine /usr/local/bin/wine # You could aslo just make a symlink, but box86 only works for 32bit apps at the moment
|
||||
#sudo ln -s ~/wine/bin/wine /usr/local/bin/wine # You could also just make a symlink, but box86 only works for 32bit apps at the moment
|
||||
sudo ln -s ~/wine/bin/wineboot /usr/local/bin/wineboot
|
||||
sudo ln -s ~/wine/bin/winecfg /usr/local/bin/winecfg
|
||||
sudo ln -s ~/wine/bin/wineserver /usr/local/bin/wineserver
|
||||
|
||||
+10
-3
@@ -22,20 +22,27 @@ echo "#!/bin/bash
|
||||
export STEAMOS=1
|
||||
export STEAM_RUNTIME=1
|
||||
export DBUS_FATAL_WARNINGS=0
|
||||
~/steam/bin/steam -noreactlogin steam://open/minigameslist $@" > steam
|
||||
~/steam/bin/steam steam://open/minigameslist $@" > steam
|
||||
|
||||
# make script executable and move
|
||||
chmod +x steam
|
||||
sudo mv steam /usr/local/bin/
|
||||
|
||||
# detect if we're running on 64 bit Debian
|
||||
# detect if we're running on 64 bit Debian (maybe this can be moved in another script then mentioned in documentation for the people that don't use steam but don't want a headache)
|
||||
MACHINE_TYPE=`uname -m`
|
||||
if [ ${MACHINE_TYPE} == 'aarch64' ] && [ -f '/etc/debian_version' ]; then
|
||||
echo "Detected 64 bit ARM Debian. Installing 32 bit libraries"
|
||||
sudo dpkg --add-architecture armhf # enable installation of armhf libraries
|
||||
sudo apt update # update package lists with the newly added arch
|
||||
# install the libraries that Steam requires
|
||||
sudo apt install libc6:armhf libncurses5:armhf libsdl2-2.0-0:armhf libsdl2-image-2.0-0:armhf libsdl2-mixer-2.0-0:armhf libsdl2-ttf-2.0-0:armhf libopenal1:armhf libpng16-16:armhf libfontconfig1:armhf libxcomposite1:armhf libbz2-1.0:armhf libxtst6:armhf
|
||||
sudo apt install libc6:armhf libncurses5:armhf libsdl2-2.0-0:armhf libsdl2-image-2.0-0:armhf libsdl2-mixer-2.0-0:armhf libsdl2-ttf-2.0-0:armhf libopenal1:armhf libpng16-16:armhf libfontconfig1:armhf libxcomposite1:armhf libbz2-1.0:armhf libxtst6:armhf libsm6:armhf libice6:armhf libgl1:armhf libxinerama1:armhf libxdamage1:armhf
|
||||
|
||||
# install mesa for armhf if already installed
|
||||
if dpkg-query -W libgl1-mesa-dri 2>/dev/null; then
|
||||
echo "Detected mesa driver for 64 bit ARM. Installing complementary 32 bit one"
|
||||
sudo apt install libgl1-mesa-dri:armhf
|
||||
fi
|
||||
|
||||
echo "Don't forget to compile/install Box64!"
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-rk3399-git
|
||||
pkgver=r3858.5368285
|
||||
pkgname=box86-a64-git
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -9,21 +9,28 @@ url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
|
||||
provides=("${pkgname%-git}" "${pkgname%-a64-git}-git" "${pkgname%-a64-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-a64-git}-git" "${pkgname%-a64-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}"
|
||||
cd "${srcdir}/${pkgname%-a64-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-a64-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DA64=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cmake -B build -S "${pkgname%-rk3399-git}" -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
cd "${srcdir}/${pkgname%-a64-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
cd "${srcdir}/${pkgname%-a64-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
+13
-6
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-arm-git
|
||||
pkgver=r3858.5368285
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -15,15 +15,22 @@ source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-arm-git}"
|
||||
cd "${srcdir}/${pkgname%-arm-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-arm-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cmake -B build -S "${pkgname%-arm-git}" -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
cd "${srcdir}/${pkgname%-arm-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
cd "${srcdir}/${pkgname%-arm-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-arm64-git
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-arm64-git}-git" "${pkgname%-arm64-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-arm64-git}-git" "${pkgname%-arm64-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname%-arm64-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-arm64-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DARM64=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-arm64-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-arm64-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-gameshell-git
|
||||
pkgver=r3858.5368285
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -15,15 +15,22 @@ source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-gameshell-git}"
|
||||
cd "${srcdir}/${pkgname%-gameshell-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-gameshell-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DGAMESHELL=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cmake -B build -S "${pkgname%-gameshell-git}" -DGAMESHELL=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
cd "${srcdir}/${pkgname%-gameshell-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
cd "${srcdir}/${pkgname%-gameshell-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-goaclone-git
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-goaclone-git}-git" "${pkgname%-goaclone-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-goaclone-git}-git" "${pkgname%-goaclone-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname%-goaclone-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-goaclone-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DGOA_CLONE=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-goaclone-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-goaclone-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-lx2610a-git
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-lx2610a-git}-git" "${pkgname%-lx2610a-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-lx2610a-git}-git" "${pkgname%-lx2610a-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname%-lx2610a-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-lx2610a-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DLX2610A=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-lx2610a-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-lx2610a-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-odroid-git
|
||||
pkgver=r3858.5368285
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -15,15 +15,22 @@ source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-odroid-git}"
|
||||
cd "${srcdir}/${pkgname%-odroid-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-odroid-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DODROID=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cmake -B build -S "${pkgname%-odroid-git}" -DODROID=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
cd "${srcdir}/${pkgname%-odroid-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
cd "${srcdir}/${pkgname%-odroid-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-odroidn2-git
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-odroidn2-git}-git" "${pkgname%-odroidn2-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-odroidn2-git}-git" "${pkgname%-odroidn2-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname%-odroidn2-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-odroidn2-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DODROID=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-odroidn2-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-odroidn2-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-pandora-git
|
||||
pkgver=r3858.5368285
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -15,15 +15,22 @@ source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-pandora-git}"
|
||||
cd "${srcdir}/${pkgname%-pandora-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-pandora-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DPANDORA=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cmake -B build -S "${pkgname%-pandora-git}" -DPANDORA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
cd "${srcdir}/${pkgname%-pandora-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
cd "${srcdir}/${pkgname%-pandora-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-phytium-git
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-phytium-git}"-git "${pkgname%-phytium-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-phytium-git}"-git "${pkgname%-phytium-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname%-phytium-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-phytium-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DPHYTIUM=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-phytium-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-phytium-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
+13
-6
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-pyra-git
|
||||
pkgver=r3858.5368285
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -15,15 +15,22 @@ source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-pyra-git}"
|
||||
cd "${srcdir}/${pkgname%-pyra-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-pyra-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DPYRA=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cmake -B build -S "${pkgname%-pyra-git}" -DPYRA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
cd "${srcdir}/${pkgname%-pyra-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
cd "${srcdir}/${pkgname%-pyra-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-rpi-git
|
||||
pkgver=r3858.5368285
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -16,11 +16,12 @@ md5sums=('SKIP')
|
||||
_pimodel=`tr -d '\0' < /sys/firmware/devicetree/base/model`
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}"
|
||||
cd "${srcdir}/${pkgname%-rpi-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
build() {
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-rpi-git}"
|
||||
# Check for Pi version number
|
||||
if [[ ${_pimodel} =~ "Raspberry Pi 4" ]]; then
|
||||
_piversion=4
|
||||
@@ -31,15 +32,20 @@ build() {
|
||||
else
|
||||
# This RPI is not supported or this device is not a pi.
|
||||
# We should cancel then the build.
|
||||
echo -e "\033[01m\033[01;31m==> ERROR:\033[00;01m Your device is not supported! This script is for RPi model 4/3/2 (1/0 isn't supported yet).\033[00m"
|
||||
echo -e "\033[01m\033[01;31m==> ERROR:\033[00;01m Your device is not supported! This script is for RPi model 4/3/2 (1/0 isn't supported).\033[00m"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "\033[01m\033[01;34m==> INFO:\033[00;01m Your detected Pi verion number is: \033[01;31m${_piversion}\033[01m.\033[00m"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DRPI${_piversion}=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
cmake -B build -S "${pkgname%-rpi-git}" -DRPI${_piversion}=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-rpi-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
cd "${srcdir}/${pkgname%-rpi-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-rk3xxx-git
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-rk3xxx-git}-git" "${pkgname%-rk3xxx-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-rk3xxx-git}-git" "${pkgname%-rk3xxx-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-rk3xxx-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-rk3xxx-git}"
|
||||
# Check for RockChip version number
|
||||
if [[ ${_rkmodel} =~ "rk3288"]]; then
|
||||
_rksuffix=3288
|
||||
elif [[ ${_rkmodel} =~ "rk3399" ]]; then
|
||||
_rksuffix=3399
|
||||
elif [[ ${_rkmodel} =~ "rk3588" ]]; then
|
||||
_rksuffix=3588
|
||||
else
|
||||
# This RKxxxx is not supported or this device is not RockChip based.
|
||||
# We should cancel then the build.
|
||||
echo -e "\033[01m\033[01;31m==> ERROR:\033[00;01m Your device is not supported! This script is for RockChip model 3399/3588.\033[00m"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "\033[01m\033[01;34m==> INFO:\033[00;01m Your detected RockChip verion number is: \033[01;31m${_rksuffix}\033[01m.\033[00m"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DRK${_rksuffix}=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-rk3xxx-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-rk3xxx-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-sd845-git
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-sd845-git}-git" "${pkgname%-sd845-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-sd845-git}-git" "${pkgname%-sd845-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname%-sd845-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-sd845-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DSD845=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-sd845-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-sd845-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-tegra-git
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-tegra-git}"-git "${pkgname%-tegra-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-tegra-git}"-git "${pkgname%-tegra-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname%-tegra-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-tegra-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DTEGRAX1ARM32=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-tegra-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-tegra-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
+13
-6
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-x86-git
|
||||
pkgver=r3858.5368285
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('i386')
|
||||
@@ -14,15 +14,22 @@ source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-x86-git}"
|
||||
cd "${srcdir}/${pkgname%-x86-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-x86-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DLD80BITS=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cmake -B build -S "${pkgname%-x86-git}" -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make -C build
|
||||
cd "${srcdir}/${pkgname%-x86-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
make -C build DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
cd "${srcdir}/${pkgname%-x86-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
+1
-1
@@ -12,7 +12,7 @@ This will copy the PKGBUILD for your platform (where you type your platform name
|
||||
In the future, I might try to do an unified PKGBUILD for all platforms that will recognize your platform automatically.
|
||||
|
||||
### 2. What platforms are currently supported.
|
||||
All specified in [COMPILE.md](../docs/COMPILE.md).
|
||||
Most specified in [COMPILE.md](../docs/COMPILE.md). Except PowerPC based.
|
||||
|
||||
### 3. Any advantages with that sollution?
|
||||
This might give you some advantages like those:
|
||||
|
||||
+1
-1
@@ -1834,7 +1834,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
start = (start >> 4) + ((start & 0xF) << 1);
|
||||
}
|
||||
|
||||
char tmp[6];
|
||||
char tmp[7];
|
||||
for (int cur = start; cur < start + size - 1; ++cur) {
|
||||
sprintf(tmp, "%c%d, ", regChr, cur);
|
||||
strcat(ret, tmp);
|
||||
|
||||
+37
-14
@@ -679,12 +679,12 @@ class Clauses:
|
||||
return isinstance(o, Clauses) and (self.clauses == o.clauses)
|
||||
|
||||
JumbledFunctions = CustOrderedDictList[Clause, Function]
|
||||
FilesSpecific = Dict[Filename, FileSpec]
|
||||
FileSpecifics = Dict[Filename, FileSpec]
|
||||
|
||||
SortedGlobals = CustOrderedDictList[Clauses, FunctionType]
|
||||
SortedRedirects = CustOrderedDictList[Clauses, FunctionType]
|
||||
|
||||
def readFiles(files: Iterable[str]) -> Tuple[JumbledFunctions, JumbledFunctions, FilesSpecific]:
|
||||
def readFiles(files: Iterable[str]) -> Tuple[JumbledFunctions, JumbledFunctions, FileSpecifics]:
|
||||
"""
|
||||
readFiles
|
||||
|
||||
@@ -693,7 +693,7 @@ def readFiles(files: Iterable[str]) -> Tuple[JumbledFunctions, JumbledFunctions,
|
||||
|
||||
gbls: JumbledFunctions = CustOrderedDictList()
|
||||
redirects: JumbledFunctions = CustOrderedDictList()
|
||||
filespecs: FilesSpecific = {}
|
||||
filespecs: FileSpecifics = {}
|
||||
|
||||
symbols: Dict[str, Filename] = {}
|
||||
need_halt: bool = False
|
||||
@@ -880,7 +880,7 @@ def readFiles(files: Iterable[str]) -> Tuple[JumbledFunctions, JumbledFunctions,
|
||||
|
||||
return gbls, redirects, filespecs
|
||||
|
||||
def sortArrays(gbl_funcs: JumbledFunctions, red_funcs: JumbledFunctions, filespecs: FilesSpecific) \
|
||||
def sortArrays(gbl_funcs: JumbledFunctions, red_funcs: JumbledFunctions, filespecs: FileSpecifics) \
|
||||
-> Tuple[SortedGlobals, SortedRedirects]:
|
||||
# First sort file specific stuff
|
||||
for fn in filespecs:
|
||||
@@ -944,13 +944,13 @@ def sortArrays(gbl_funcs: JumbledFunctions, red_funcs: JumbledFunctions, filespe
|
||||
redirects[red_vals[funtype]].append(funtype)
|
||||
redirects.sort(key=Clauses.splitdef)
|
||||
|
||||
def fail(): assert(False)
|
||||
def fail(): assert False
|
||||
for clauses in redirects:
|
||||
redirects[clauses].sort(key=lambda v: fail() if v.redirected is None else v.splitchar() + v.redirected.splitchar())
|
||||
|
||||
return gbls, redirects
|
||||
|
||||
def checkRun(root: str, gbls: SortedGlobals, redirects: SortedRedirects, filesspec: FilesSpecific) -> Optional[str]:
|
||||
def checkRun(root: str, gbls: SortedGlobals, redirects: SortedRedirects, filespecs: FileSpecifics) -> Optional[str]:
|
||||
# Check if there was any new functions compared to last run
|
||||
functions_list: str = ""
|
||||
for clauses in gbls:
|
||||
@@ -960,18 +960,18 @@ def checkRun(root: str, gbls: SortedGlobals, redirects: SortedRedirects, filessp
|
||||
for v in redirects[clauses]:
|
||||
assert(v.redirected is not None)
|
||||
functions_list = functions_list + "#" + str(clauses) + " " + v.orig + " -> " + v.redirected.orig + "\n"
|
||||
for filename in sorted(filesspec.keys()):
|
||||
for filename in sorted(filespecs.keys()):
|
||||
functions_list = functions_list + filename + ":\n"
|
||||
for st in filesspec[filename].structs:
|
||||
struct = filesspec[filename].structs[st]
|
||||
for st in filespecs[filename].structs:
|
||||
struct = filespecs[filename].structs[st]
|
||||
functions_list = functions_list + \
|
||||
"% " + st + " " + struct.name + " " + struct.repl + "\n"
|
||||
for _bare in filesspec[filename].typedefs:
|
||||
for _bare in filespecs[filename].typedefs:
|
||||
functions_list = functions_list + "- " + _bare.orig + ":\n"
|
||||
for fn in filesspec[filename].typedefs[_bare]:
|
||||
for fn in filespecs[filename].typedefs[_bare]:
|
||||
if fn.no_dlsym: continue
|
||||
functions_list = functions_list + " - " + fn.name + "\n"
|
||||
for funtype in filesspec[filename].structsuses:
|
||||
for funtype in filespecs[filename].structsuses:
|
||||
assert(funtype.redirected is not None)
|
||||
functions_list = functions_list + "% " + funtype.orig + " -> " + funtype.redirected.orig + "\n"
|
||||
|
||||
@@ -992,7 +992,7 @@ def checkRun(root: str, gbls: SortedGlobals, redirects: SortedRedirects, filessp
|
||||
return functions_list
|
||||
|
||||
def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobals, redirects: SortedRedirects, \
|
||||
filespecs: FilesSpecific) -> None:
|
||||
filespecs: FileSpecifics) -> None:
|
||||
# Files header and guard
|
||||
files_header = {
|
||||
"wrapper.c": """
|
||||
@@ -1148,6 +1148,13 @@ def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobal
|
||||
for fhdr in files_header:
|
||||
files_guard[fhdr] = trim(files_guard[fhdr])
|
||||
|
||||
# TODO: put the informations below in a structure (like in box64, where
|
||||
# typedefs & co. are stored in an ABI-specific structure)
|
||||
|
||||
return_x87: str = "DKdf"
|
||||
if any(c not in FileSpec.values for c in return_x87):
|
||||
raise NotImplementedError("Invalid character")
|
||||
|
||||
# Typedefs
|
||||
# E v c w i I C W u U f d D K l L p V O S 2 P G N M s
|
||||
tdtypes = ["x86emu_t*", "void", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t", "float", "double", "long double", "double", "intptr_t", "uintptr_t", "void*", "void*", "int32_t", "void*", "_2uint_struct_t", "void*", "void*", "...", "...", "void*"]
|
||||
@@ -1309,6 +1316,22 @@ def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobal
|
||||
if not clauses.empty():
|
||||
file.write("#endif\n")
|
||||
|
||||
# Finally, write predicate functions
|
||||
|
||||
# isRetX87Wrapper
|
||||
file.write("\nint isRetX87Wrapper(wrapper_t fun) {\n")
|
||||
for clauses in gbls:
|
||||
empty = True
|
||||
for funtype in gbls[clauses]:
|
||||
if funtype.orig[0] in return_x87: # TODO: put this in a function (functions would request the ABI for more info)
|
||||
if empty and (not clauses.empty()):
|
||||
file.write("#if " + str(clauses) + "\n")
|
||||
empty = False
|
||||
file.write("\tif (fun == &" + funtype.orig + ") return 1;\n")
|
||||
if not empty:
|
||||
file.write("#endif\n")
|
||||
file.write("\treturn 0;\n}\n")
|
||||
|
||||
file.write(files_guard["wrapper.c"].format(lbr="{", rbr="}", version=ver))
|
||||
|
||||
# Rewrite the wrapper.h file:
|
||||
@@ -1398,6 +1421,6 @@ if __name__ == '__main__':
|
||||
if v == "--":
|
||||
limit.append(i)
|
||||
Define.defines = list(map(DefineType, sys.argv[2:limit[0]]))
|
||||
if main(sys.argv[1], sys.argv[limit[0]+1:], "2.0.0.10") != 0:
|
||||
if main(sys.argv[1], sys.argv[limit[0]+1:], "2.0.0.11") != 0:
|
||||
exit(2)
|
||||
exit(0)
|
||||
+50
-17
@@ -23,6 +23,7 @@
|
||||
#include "custommem.h"
|
||||
#include "dictionnary.h"
|
||||
#include "rcfile.h"
|
||||
#include "gltools.h"
|
||||
#ifdef DYNAREC
|
||||
#include "dynablock.h"
|
||||
#include "dynarec/arm_lock_helper.h"
|
||||
@@ -146,6 +147,7 @@ static void init_mutexes(box86context_t* context)
|
||||
arm_lock_stored(&context->mutex_tls, 0);
|
||||
arm_lock_stored(&context->mutex_thread, 0);
|
||||
arm_lock_stored(&context->mutex_bridge, 0);
|
||||
pthread_mutex_init(&context->mutex_lock, NULL);
|
||||
#else
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
@@ -210,7 +212,7 @@ box86context_t *NewBox86Context(int argc)
|
||||
#ifdef BUILD_LIB
|
||||
context->deferedInit = 0;
|
||||
#else
|
||||
context->deferedInit = 1;
|
||||
context->deferredInit = 1;
|
||||
#endif
|
||||
context->sel_serial = 1;
|
||||
|
||||
@@ -220,11 +222,12 @@ box86context_t *NewBox86Context(int argc)
|
||||
context->local_maplib = NewLibrarian(context, 1);
|
||||
context->versym = NewDictionnary();
|
||||
context->system = NewBridge();
|
||||
context->globaldefver = NewDefaultVersion();
|
||||
context->weakdefver = NewDefaultVersion();
|
||||
// Cannot use Bridge name as the map is not initialized yet
|
||||
// create vsyscall
|
||||
context->vsyscall = AddBridge(context->system, iFEv, x86Syscall, 0, NULL);
|
||||
addAlternate((void*)0xffffe400, (void*)context->vsyscall);
|
||||
// create exit bridge
|
||||
context->exit_bridge = AddBridge(context->system, NULL, NULL, 0, NULL);
|
||||
#ifdef BUILD_LIB
|
||||
context->box86lib = RTLD_DEFAULT; // not ideal
|
||||
#else
|
||||
@@ -246,11 +249,13 @@ box86context_t *NewBox86Context(int argc)
|
||||
context->canary[/*getrand(4)*/0] = 0;
|
||||
printf_log(LOG_DEBUG, "Setting up canary (for Stack protector) at GS:0x14, value:%08X\n", *(uint32_t*)context->canary);
|
||||
|
||||
context->globdata = NewMapSymbols();
|
||||
|
||||
initAllHelpers(context);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
void freeALProcWrapper(box86context_t* context);
|
||||
EXPORTDYN
|
||||
void FreeBox86Context(box86context_t** context)
|
||||
{
|
||||
@@ -288,8 +293,8 @@ void FreeBox86Context(box86context_t** context)
|
||||
if(ctx->zydis)
|
||||
DeleteX86Trace(ctx);
|
||||
|
||||
if(ctx->deferedInitList)
|
||||
box_free(ctx->deferedInitList);
|
||||
if(ctx->deferredInitList)
|
||||
box_free(ctx->deferredInitList);
|
||||
|
||||
/*box_free(ctx->argv);*/
|
||||
|
||||
@@ -350,16 +355,19 @@ void FreeBox86Context(box86context_t** context)
|
||||
}
|
||||
}
|
||||
|
||||
free_neededlib(&ctx->neededlibs);
|
||||
free_neededlib(ctx->neededlibs);
|
||||
ctx->neededlibs = NULL;
|
||||
|
||||
if(ctx->emu_sig)
|
||||
FreeX86Emu(&ctx->emu_sig);
|
||||
FreeDefaultVersion(&ctx->globaldefver);
|
||||
FreeDefaultVersion(&ctx->weakdefver);
|
||||
|
||||
FreeMapSymbols(&ctx->globdata);
|
||||
|
||||
finiAllHelpers(ctx);
|
||||
|
||||
#ifndef DYNAREC
|
||||
#ifdef DYNAREC
|
||||
pthread_mutex_destroy(&ctx->mutex_lock);
|
||||
#else
|
||||
pthread_mutex_destroy(&ctx->mutex_once);
|
||||
pthread_mutex_destroy(&ctx->mutex_once2);
|
||||
pthread_mutex_destroy(&ctx->mutex_trace);
|
||||
@@ -375,20 +383,45 @@ void FreeBox86Context(box86context_t** context)
|
||||
}
|
||||
|
||||
int AddElfHeader(box86context_t* ctx, elfheader_t* head) {
|
||||
int idx = ctx->elfsize;
|
||||
if(idx==ctx->elfcap) {
|
||||
// resize...
|
||||
ctx->elfcap += 16;
|
||||
ctx->elfs = (elfheader_t**)box_realloc(ctx->elfs, sizeof(elfheader_t*) * ctx->elfcap);
|
||||
int idx = 0;
|
||||
while(idx<ctx->elfsize && ctx->elfs[idx]) idx++;
|
||||
if(idx == ctx->elfsize) {
|
||||
if(idx==ctx->elfcap) {
|
||||
// resize...
|
||||
ctx->elfcap += 16;
|
||||
ctx->elfs = (elfheader_t**)box_realloc(ctx->elfs, sizeof(elfheader_t*) * ctx->elfcap);
|
||||
}
|
||||
ctx->elfs[idx] = head;
|
||||
ctx->elfsize++;
|
||||
} else {
|
||||
ctx->elfs[idx] = head;
|
||||
}
|
||||
ctx->elfs[idx] = head;
|
||||
ctx->elfsize++;
|
||||
printf_log(LOG_DEBUG, "Adding \"%s\" as #%d in elf collection\n", ElfName(head), idx);
|
||||
return idx;
|
||||
}
|
||||
|
||||
void RemoveElfHeader(box86context_t* ctx, elfheader_t* head) {
|
||||
if(GetTLSBase(head)) {
|
||||
// should remove the tls info
|
||||
int tlsbase = GetTLSBase(head);
|
||||
/*if(tlsbase == -ctx->tlssize) {
|
||||
// not really correct, but will do for now
|
||||
ctx->tlssize -= GetTLSSize(head);
|
||||
if(!(++ctx->sel_serial))
|
||||
++ctx->sel_serial;
|
||||
}*/
|
||||
}
|
||||
for(int i=0; i<ctx->elfsize; ++i)
|
||||
if(ctx->elfs[i] == head) {
|
||||
ctx->elfs[i] = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int AddTLSPartition(box86context_t* context, int tlssize) {
|
||||
int oldsize = context->tlssize;
|
||||
// should in fact first try to map a hole, but rewinding all elfs and checking filled space, like with the mapmem utilities
|
||||
context->tlssize += tlssize;
|
||||
context->tlsdata = box_realloc(context->tlsdata, context->tlssize);
|
||||
memmove(context->tlsdata+tlssize, context->tlsdata, oldsize); // move to the top, using memmove as regions will probably overlap
|
||||
|
||||
+1
-1
@@ -3,6 +3,6 @@
|
||||
|
||||
#define BOX86_MAJOR 0
|
||||
#define BOX86_MINOR 3
|
||||
#define BOX86_REVISION 0
|
||||
#define BOX86_REVISION 2
|
||||
|
||||
#endif //__BOX86_VERSION_H_
|
||||
+578
-500
File diff suppressed because it is too large.
Load diff
@@ -390,6 +390,8 @@ Op is 20-27
|
||||
#define LDRD_IMM8(reg, addr, imm8) EMIT(c__ | 0b000<<25 | 1<<24 | (((imm8)<0)?0:1)<<23 | 1<<22 | 0<<21 | 0<<20 | ((reg) << 12) | ((addr) << 16) | ((abs(imm8))&0xf0)<<(8-4) | (0b1101<<4) | ((abs(imm8))&0x0f) )
|
||||
// ldrd reg, reg+1, [addr, +rm], reg must be even, reg+1 is implicit
|
||||
#define LDRD_REG(reg, addr, rm) EMIT(c__ | 0b000<<25 | 1<<24 | 1<<23 | 0<<22 | 0<<21 | 0<<20 | ((reg) << 12) | ((addr) << 16) | 0b1101<<4 | (rm) )
|
||||
// ldr reg, [pc+imm]
|
||||
#define LDR_literal(reg, imm12) EMIT(c__ | 0b010<<25 | 1<<24 | (((imm12)>=0)?1:0)<<23 | 0<<21 | 1<<20 | 0b1111<<16 | (reg)<<12 | (abs(imm12)))
|
||||
|
||||
// str reg, [addr, #+/-imm9]
|
||||
#define STR_IMM9(reg, addr, imm9) EMIT(0xe5000000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
|
||||
|
||||
@@ -335,9 +335,9 @@ NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 1 @<1> Rm @ param=1 char align[4
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> 1 1 0 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> 1 1 1 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> Rm @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 0 1 @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 1 1 @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> Rm @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 0 1 @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 1 1 @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> Rm @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
.extern LinkNext
|
||||
|
||||
.global arm_next
|
||||
.4byte 0 // NULL pointer before arm64_next, for getDB
|
||||
arm_next:
|
||||
// emu is r0
|
||||
//stm r0, {r4-r12,r14} // don't put put back reg value in emu, faster but more tricky to debug
|
||||
|
||||
@@ -159,7 +159,7 @@ const char* print_register_list_fpu(uint8_t start, uint8_t size, uint8_t double_
|
||||
start = (start >> 4) + ((start & 0xF) << 1);
|
||||
}
|
||||
|
||||
char tmp[6];
|
||||
char tmp[7];
|
||||
for (int cur = start; cur < start + size - 1; ++cur) {
|
||||
sprintf(tmp, "%c%d, ", regChr, cur);
|
||||
strcat(ret, tmp);
|
||||
@@ -3049,7 +3049,7 @@ const char* arm_print(uint32_t opcode) {
|
||||
int param1_1 = (opcode >> 5) & 0x1;
|
||||
int param2_1 = (opcode >> 4) & 0x1;
|
||||
|
||||
char align[4];
|
||||
char align[5];
|
||||
if (param2_1 == 1) {
|
||||
sprintf(align, ":%d", 16 << size);
|
||||
} else {
|
||||
@@ -3064,7 +3064,7 @@ const char* arm_print(uint32_t opcode) {
|
||||
int param1_1 = (opcode >> 5) & 0x1;
|
||||
int param2_1 = (opcode >> 4) & 0x1;
|
||||
|
||||
char align[4];
|
||||
char align[5];
|
||||
if (param2_1 == 1) {
|
||||
sprintf(align, ":%d", 16 << size);
|
||||
} else {
|
||||
@@ -3080,7 +3080,7 @@ const char* arm_print(uint32_t opcode) {
|
||||
int param1_1 = (opcode >> 5) & 0x1;
|
||||
int param2_1 = (opcode >> 4) & 0x1;
|
||||
|
||||
char align[4];
|
||||
char align[5];
|
||||
if (param2_1 == 1) {
|
||||
sprintf(align, ":%d", 16 << size);
|
||||
} else {
|
||||
|
||||
+187
-300
@@ -41,21 +41,37 @@ uint32_t X31_hash_code(void* addr, int len)
|
||||
return (uint32_t)h;
|
||||
}
|
||||
|
||||
dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct)
|
||||
dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock)
|
||||
{
|
||||
if(!textsz) {
|
||||
printf_log(LOG_NONE, "Error, creating a NULL sized Dynablock\n");
|
||||
return NULL;
|
||||
if(db) {
|
||||
if(db->gone)
|
||||
return NULL; // already in the process of deletion!
|
||||
dynarec_log(LOG_DEBUG, "InvalidDynablock(%p), db->block=%p x86=%p:%p already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size-1, db->gone);
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
// remove jumptable
|
||||
setJumpTableDefault(db->x86_addr);
|
||||
db->done = 0;
|
||||
db->gone = 1;
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
dynablocklist_t* ret = (dynablocklist_t*)box_calloc(1, sizeof(dynablocklist_t));
|
||||
ret->text = text;
|
||||
ret->textsz = textsz;
|
||||
if(direct && textsz) {
|
||||
ret->direct = (dynablock_t**)box_calloc(textsz, sizeof(dynablock_t*));
|
||||
if(!ret->direct) {printf_log(LOG_NONE, "Warning, fail to create direct block for dynablock @%p\n", (void*)text);}
|
||||
return db;
|
||||
}
|
||||
|
||||
void FreeInvalidDynablock(dynablock_t* db, int need_lock)
|
||||
{
|
||||
if(db) {
|
||||
if(!db->gone)
|
||||
return; // already in the process of deletion!
|
||||
dynarec_log(LOG_DEBUG, "FreeInvalidDynablock(%p), db->block=%p x86=%p:%p already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size-1, db->gone);
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
FreeDynarecMap((uintptr_t)db->actual_block);
|
||||
customFree(db);
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
dynarec_log(LOG_DEBUG, "New Dynablocklist %p, from %p->%p\n", ret, (void*)text, (void*)(text+textsz));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void FreeDynablock(dynablock_t* db, int need_lock)
|
||||
@@ -63,237 +79,100 @@ void FreeDynablock(dynablock_t* db, int need_lock)
|
||||
if(db) {
|
||||
if(db->gone)
|
||||
return; // already in the process of deletion!
|
||||
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x86=%p:%p father=%p, with %d son(s) already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size, db->father, db->sons_size, db->gone);
|
||||
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x86=%p:%p already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size-1, db->gone);
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
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->x86_addr;
|
||||
if(addr>=startdb && addr<enddb)
|
||||
db->parent->direct[addr-startdb] = NULL;
|
||||
}
|
||||
// remove jumptable
|
||||
setJumpTableDefault(db->x86_addr);
|
||||
// remove and free the sons
|
||||
for (int i=0; i<db->sons_size; ++i) {
|
||||
dynablock_t *son = (dynablock_t*)arm_lock_xchg(&db->sons[i], 0);
|
||||
FreeDynablock(son, 0);
|
||||
}
|
||||
// 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);
|
||||
box_free(db->sons);
|
||||
box_free(db->instsize);
|
||||
}
|
||||
box_free(db);
|
||||
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->actual_block, db->size);
|
||||
db->done = 0;
|
||||
db->gone = 1;
|
||||
if(db->previous)
|
||||
FreeInvalidDynablock(db->previous, 0);
|
||||
FreeDynarecMap((uintptr_t)db->actual_block);
|
||||
customFree(db);
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
}
|
||||
|
||||
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], my_context?1:0);
|
||||
}
|
||||
box_free((*dynablocks)->direct);
|
||||
}
|
||||
(*dynablocks)->direct = NULL;
|
||||
|
||||
box_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;
|
||||
setJumpTableDefault(db->x86_addr);
|
||||
for(int i=0; i<db->sons_size; ++i)
|
||||
setJumpTableDefault(db->sons[i]->x86_addr);
|
||||
dynarec_log(LOG_DEBUG, "MarkDynablock %p %p-%p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1);
|
||||
if(!setJumpTableIfRef(db->x86_addr, db->jmpnext, db->block)) {
|
||||
dynablock_t* old = db;
|
||||
db = getDB((uintptr_t)old->x86_addr);
|
||||
if(!old->gone && db!=old) {
|
||||
printf_log(LOG_INFO, "Warning, couldn't mark block as dirty for %p, block=%p, current_block=%p\n", old->x86_addr, old, db);
|
||||
// the block is lost, need to invalidate it...
|
||||
old->gone = 1;
|
||||
old->done = 0;
|
||||
if(!db || db->previous)
|
||||
FreeInvalidDynablock(old, 1);
|
||||
else
|
||||
db->previous = old;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
static 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)
|
||||
static int MarkedDynablock(dynablock_t* db)
|
||||
{
|
||||
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->x86_addr, (uintptr_t)db->x86_addr+db->x86_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) {
|
||||
int need_lock = my_context?1:0;
|
||||
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*)arm_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, need_lock);
|
||||
);
|
||||
kh_destroy(dynablocks, blocks);
|
||||
if(db) {
|
||||
if(getNeedTest((uintptr_t)db->x86_addr))
|
||||
return 1; // already done
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
|
||||
void MarkRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
// Mark will try to find *any* blocks that intersect the range to mark
|
||||
if(!db)
|
||||
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);
|
||||
dynarec_log(LOG_DEBUG, "MarkRangeDynablock %p-%p .. startdb=%p, sizedb=%p\n", (void*)addr, (void*)addr+size-1, (void*)db->x86_addr, (void*)db->x86_size);
|
||||
if(IntervalIntersects((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr+db->x86_size-1, addr, addr+size+1))
|
||||
MarkDynablock(db);
|
||||
}
|
||||
|
||||
int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!db)
|
||||
return 1;
|
||||
|
||||
int need_lock = my_context?1:0;
|
||||
if(IntervalIntersects((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr+db->x86_size-1, addr, addr+size+1)) {
|
||||
FreeDynablock(db, need_lock);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks)
|
||||
dynablock_t *AddNewDynablock(uintptr_t addr)
|
||||
{
|
||||
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 int 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;
|
||||
dynablock_t* block;
|
||||
#if 0
|
||||
// check if memory as the correct flags
|
||||
int prot = getProtection(addr);
|
||||
if(!(prot&(PROT_EXEC|PROT_DYNAREC|PROT_DYNAREC_R))) {
|
||||
dynarec_log(LOG_VERBOSE, "Block asked on a memory with no execution flags 0x%02X\n", prot);
|
||||
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_VERBOSE, "Block already exist in Direct Map\n");
|
||||
*created = 0;
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
||||
if (!*created)
|
||||
return block;
|
||||
|
||||
if(!dynablocks->direct) {
|
||||
dynablock_t** p = (dynablock_t**)box_calloc(dynablocks->textsz, sizeof(dynablock_t*));
|
||||
if(arm_lock_storeifnull(&dynablocks->direct, p)!=NULL)
|
||||
box_free(p); // someone already create the direct array, too late...
|
||||
}
|
||||
|
||||
#endif
|
||||
// create and add new block
|
||||
dynarec_log(LOG_VERBOSE, "Ask for DynaRec Block creation @%p\n", (void*)addr);
|
||||
|
||||
block = (dynablock_t*)box_calloc(1, sizeof(dynablock_t));
|
||||
block->parent = dynablocks;
|
||||
dynablock_t* tmp = (dynablock_t*)arm_lock_storeifref(&dynablocks->direct[addr-dynablocks->text], block, NULL);
|
||||
if(tmp != block) {
|
||||
// a block appeard!
|
||||
box_free(block);
|
||||
*created = 0;
|
||||
return tmp;
|
||||
}
|
||||
*created = 1;
|
||||
block = (dynablock_t*)customCalloc(1, sizeof(dynablock_t));
|
||||
return block;
|
||||
}
|
||||
|
||||
@@ -309,121 +188,120 @@ void cancelFillBlock()
|
||||
return NULL if block is not found / cannot be created.
|
||||
Don't create if create==0
|
||||
*/
|
||||
static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, dynablock_t* current, int need_lock)
|
||||
static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, int need_lock)
|
||||
{
|
||||
if(hasAlternate((void*)addr))
|
||||
return NULL;
|
||||
// try the quickest way first: get parent of current and check if ok!
|
||||
dynablocklist_t *dynablocks = NULL;
|
||||
dynablock_t* block = NULL;
|
||||
if(current && current->done) {
|
||||
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)
|
||||
dynablock_t* block = getDB(addr);
|
||||
if(block || !create)
|
||||
return block;
|
||||
|
||||
if(need_lock) {
|
||||
if(box86_dynarec_wait) {
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
} else {
|
||||
if(mutex_trylock(&my_context->mutex_dyndump)) // FillBlock not available for now
|
||||
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;
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
block = AddNewDynablock(dynablocks, addr, &created);
|
||||
if(!created) {
|
||||
if(need_lock)
|
||||
block = getDB(addr); // just in case
|
||||
if(block) {
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
return block; // existing block...
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
||||
block = AddNewDynablock(addr);
|
||||
|
||||
// fill the block
|
||||
block->x86_addr = (void*)addr;
|
||||
if(sigsetjmp(&dynarec_jmpbuf, 1)) {
|
||||
printf_log(LOG_INFO, "FillBlock at %p triggered a segfault, cancelling\n", (void*)addr);
|
||||
FreeDynablock(block, 0);
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
return NULL;
|
||||
}
|
||||
void* ret = FillBlock(block, filladdr);
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
if(!ret) {
|
||||
dynarec_log(LOG_DEBUG, "Fillblock of block %p for %p returned an error\n", block, (void*)addr);
|
||||
void* old = (void*)arm_lock_storeifref(&dynablocks->direct[addr-dynablocks->text], 0, block);
|
||||
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);
|
||||
// Doing nothing else, the block has not been written
|
||||
}
|
||||
box_free(block);
|
||||
customFree(block);
|
||||
block = NULL;
|
||||
}
|
||||
// check size
|
||||
if(block && block->x86_size) {
|
||||
if(block) {
|
||||
int blocksz = block->x86_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;
|
||||
}
|
||||
}
|
||||
//protectDB((uintptr_t)block->x86_addr, block->x86_size); // already protected in FillBlock
|
||||
// but check if it already need test
|
||||
if(block->need_test || (block->father && block->father->need_test))
|
||||
return NULL;
|
||||
if(blocksz>my_context->max_db_size)
|
||||
my_context->max_db_size = blocksz;
|
||||
// fill-in jumptable
|
||||
addJumpTableIfDefault(block->x86_addr, block->block);
|
||||
for(int i=0; i<block->sons_size; ++i)
|
||||
addJumpTableIfDefault(block->sons[i]->x86_addr, block->sons[i]->block);
|
||||
if(!addJumpTableIfDefault(block->x86_addr, block->dirty?block->jmpnext:block->block)) {
|
||||
FreeDynablock(block, 0);
|
||||
block = getDB(addr);
|
||||
MarkDynablock(block); // just in case...
|
||||
} else {
|
||||
if(block->x86_size)
|
||||
block->done = 1; // don't validate the block if the size is null, but keep the block
|
||||
}
|
||||
}
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
|
||||
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->x86_size:0)), (block)?block->block:0, (block)?block->size:0, (block)?block->sons_size:0);
|
||||
dynarec_log(LOG_DEBUG, "%04d| --- DynaRec Block created @%p:%p (%p, 0x%x bytes)\n", GetTID(), (void*)addr, (void*)(addr+((block)?block->x86_size:1)-1), (block)?block->block:0, (block)?block->size:0);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t** current)
|
||||
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create)
|
||||
{
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, *current, 1);
|
||||
if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, 1);
|
||||
if(db && db->done && db->block && getNeedTest(addr)) {
|
||||
if(db->always_test)
|
||||
sched_yield(); // just calm down...
|
||||
if(AreaInHotPage((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr + db->x86_size - 1)) {
|
||||
dynarec_log(LOG_DEBUG, "Not running block %p from %p:%p with for %p because it's in a hotpage\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, (void*)addr);
|
||||
return NULL;
|
||||
emu->test.test = 0;
|
||||
if(box86_dynarec_fastpage) {
|
||||
uint32_t hash = X31_hash_code(db->x86_addr, db->x86_size);
|
||||
if(hash==db->hash) { // seems ok, run it without reprotecting it
|
||||
setJumpTableIfRef(db->x86_addr, db->block, db->jmpnext);
|
||||
return db;
|
||||
}
|
||||
db->done = 0; // invalidating the block, it's already not good
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, hash, db->hash, (void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
FreeDynablock(db, 1);
|
||||
return NULL; // not building a new one, it's still a hotpage
|
||||
} else {
|
||||
dynarec_log(LOG_INFO, "Not running block %p from %p:%p with for %p because it's in a hotpage\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if(mutex_trylock(&my_context->mutex_dyndump))
|
||||
return NULL;
|
||||
dynablock_t *father = db->father?db->father:db;
|
||||
uint32_t hash = (getProtection((uintptr_t)father->x86_addr)&PROT_READ)?X31_hash_code(father->x86_addr, father->x86_size):0;
|
||||
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->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->sons_size, (void*)addr);
|
||||
// no more current if it gets invalidated too
|
||||
if(*current && father->x86_addr>=(*current)->x86_addr && (father->x86_addr+father->x86_size)<(*current)->x86_addr)
|
||||
*current = NULL;
|
||||
// Free father, it's now invalid!
|
||||
FreeDynablock(father, 0);
|
||||
uint32_t hash = X31_hash_code(db->x86_addr, db->x86_size);
|
||||
int need_lock = mutex_trylock(&my_context->mutex_dyndump);
|
||||
if(hash!=db->hash) {
|
||||
db->done = 0; // invalidating the block
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, hash, db->hash, (void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
dynablock_t* old = InvalidDynablock(db, need_lock);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, addr, create, *current, 0);
|
||||
db = internalDBGetBlock(emu, addr, addr, create, need_lock);
|
||||
if(db) {
|
||||
if(db->previous)
|
||||
FreeInvalidDynablock(db->previous, need_lock);
|
||||
db->previous = old;
|
||||
} else
|
||||
FreeInvalidDynablock(old, need_lock);
|
||||
} else {
|
||||
father->need_test = 0;
|
||||
protectDB((uintptr_t)father->x86_addr, father->x86_size);
|
||||
dynarec_log(LOG_DEBUG, "Validating block %p from %p:%p (hash:%X) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, db->hash, (void*)addr);
|
||||
protectDB((uintptr_t)db->x86_addr, db->x86_size);
|
||||
// fill back jumptable
|
||||
addJumpTableIfDefault(father->x86_addr, father->block);
|
||||
for(int i=0; i<father->sons_size; ++i)
|
||||
addJumpTableIfDefault(father->sons[i]->x86_addr, father->sons[i]->block);
|
||||
if(isprotectedDB((uintptr_t)db->x86_addr, db->x86_size) && !db->always_test) {
|
||||
setJumpTableIfRef(db->x86_addr, db->block, db->jmpnext);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
if(!need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
if(!db || !db->block || !db->done)
|
||||
emu->test.test = 0;
|
||||
return db;
|
||||
}
|
||||
|
||||
@@ -431,27 +309,36 @@ dynablock_t* DBAlternateBlock(x86emu_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, 1);
|
||||
if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
|
||||
if(mutex_trylock(&my_context->mutex_dyndump))
|
||||
return NULL;
|
||||
dynablock_t *father = db->father?db->father:db;
|
||||
uint32_t hash = (getProtection((uintptr_t)father->x86_addr)&PROT_READ)?X31_hash_code(father->x86_addr, father->x86_size):0;
|
||||
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->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->sons_size, (void*)addr);
|
||||
// Free father, it's now invalid!
|
||||
FreeDynablock(father, 0);
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, 1);
|
||||
if(db && db->done && db->block && getNeedTest(filladdr)) {
|
||||
if(db->always_test)
|
||||
sched_yield(); // just calm down...
|
||||
int need_lock = mutex_trylock(&my_context->mutex_dyndump);
|
||||
uint32_t hash = X31_hash_code(db->x86_addr, db->x86_size);
|
||||
if(hash!=db->hash) {
|
||||
db->done = 0; // invalidating the block
|
||||
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size, hash, db->hash, (void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
dynablock_t* old = InvalidDynablock(db, need_lock);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, filladdr, create, NULL, 0);
|
||||
db = internalDBGetBlock(emu, addr, filladdr, create, need_lock);
|
||||
if(db) {
|
||||
if(db->previous)
|
||||
FreeInvalidDynablock(db->previous, need_lock);
|
||||
db->previous = old;
|
||||
} else
|
||||
FreeInvalidDynablock(old, need_lock);
|
||||
} else {
|
||||
father->need_test = 0;
|
||||
protectDB((uintptr_t)father->x86_addr, father->x86_size);
|
||||
protectDB((uintptr_t)db->x86_addr, db->x86_size);
|
||||
// fill back jumptable
|
||||
addJumpTableIfDefault(father->x86_addr, father->block);
|
||||
for(int i=0; i<father->sons_size; ++i)
|
||||
addJumpTableIfDefault(father->sons[i]->x86_addr, father->sons[i]->block);
|
||||
if(isprotectedDB((uintptr_t)db->x86_addr, db->x86_size) && !db->always_test) {
|
||||
setJumpTableIfRef(db->x86_addr, db->block, db->jmpnext);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
if(!need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
if(!db || !db->block || !db->done)
|
||||
emu->test.test = 0;
|
||||
return db;
|
||||
}
|
||||
@@ -1,36 +1,26 @@
|
||||
#ifndef __DYNABLOCK_PRIVATE_H_
|
||||
#define __DYNABLOCK_PRIVATE_H_
|
||||
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
|
||||
typedef struct instsize_s {
|
||||
unsigned char x86:4;
|
||||
unsigned char nat:4;
|
||||
} instsize_t;
|
||||
|
||||
typedef struct dynablock_s {
|
||||
dynablocklist_t* parent;
|
||||
void* block;
|
||||
void* block; // block-sizeof(void*) == self
|
||||
void* actual_block; // the actual start of the block (so block-sizeof(void*))
|
||||
struct dynablock_s* previous; // a previous block that might need to be freed
|
||||
int size;
|
||||
void* x86_addr;
|
||||
uintptr_t x86_size;
|
||||
uint32_t hash;
|
||||
uint8_t need_test;
|
||||
uint8_t done;
|
||||
uint8_t gone;
|
||||
uint8_t dummy;
|
||||
uint8_t always_test;
|
||||
uint8_t dirty; // if need to be tested as soon as it's created
|
||||
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;
|
||||
void* jmpnext; // a branch jmpnext code when block is marked
|
||||
} 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_
|
||||
+51
-29
@@ -20,6 +20,7 @@
|
||||
#include "dynablock.h"
|
||||
#include "dynablock_private.h"
|
||||
#include "bridge.h"
|
||||
void x86test_check(x86emu_t* ref, uintptr_t ip);
|
||||
#endif
|
||||
|
||||
#ifdef ARM
|
||||
@@ -44,26 +45,27 @@ void* LinkNext(x86emu_t* emu, uintptr_t addr, void* x2)
|
||||
printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x86addr=%p/%s)\n", x2, db, x86addr, pcname);
|
||||
}
|
||||
#endif
|
||||
dynablock_t* current = NULL;
|
||||
void * jblock;
|
||||
dynablock_t* block = DBGetBlock(emu, addr, 1, ¤t);
|
||||
dynablock_t* block = NULL;
|
||||
if(hasAlternate((void*)addr)) {
|
||||
printf_log(LOG_INFO, "Jmp address has alternate: %p", (void*)addr);
|
||||
addr = (uintptr_t)getAlternate((void*)addr);
|
||||
R_EIP = addr;
|
||||
printf_log(LOG_INFO, " -> %p\n", (void*)addr);
|
||||
block = DBGetBlock(emu, addr, 1);
|
||||
} else
|
||||
block = DBGetBlock(emu, addr, 1);
|
||||
if(!block) {
|
||||
// no block, let link table as is...
|
||||
if(hasAlternate((void*)addr)) {
|
||||
printf_log(LOG_INFO, "Jmp address has alternate: %p", (void*)addr);
|
||||
addr = (uintptr_t)getAlternate((void*)addr);
|
||||
R_EIP = addr;
|
||||
printf_log(LOG_INFO, " -> %p\n", (void*)addr);
|
||||
block = DBGetBlock(emu, addr, 1, ¤t);
|
||||
}
|
||||
if(!block) {
|
||||
#ifdef HAVE_TRACE
|
||||
#ifdef HAVE_TRACE
|
||||
if(LOG_INFO<=box86_dynarec_log) {
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2);
|
||||
dynarec_log(LOG_INFO, "Warning, jumping to a no-block address %p from %p (db=%p, x86addr=%p)\n", (void*)addr, x2, db, db?(void*)getX86Address(db, (uintptr_t)x2):NULL);
|
||||
#endif
|
||||
//tableupdate(arm_epilog, addr, table);
|
||||
return arm_epilog;
|
||||
elfheader_t* h = FindElfAddress(my_context, (uintptr_t)x2);
|
||||
dynarec_log(LOG_INFO, "Warning, jumping to a no-block address %p from %p (db=%p, x64addr=%p(elf=%s))\n", (void*)addr, x2, db, db?(void*)getX86Address(db, (uintptr_t)x2-4):NULL, h?ElfName(h):"(none)");
|
||||
}
|
||||
#endif
|
||||
//tableupdate(arm_epilog, addr, table);
|
||||
return arm_epilog;
|
||||
}
|
||||
if(!block->done) {
|
||||
// not finished yet... leave linker
|
||||
@@ -84,18 +86,25 @@ void DynaCall(x86emu_t* emu, uintptr_t addr)
|
||||
// prepare setjump for signal handling
|
||||
emu_jmpbuf_t *ejb = NULL;
|
||||
int jmpbuf_reset = 0;
|
||||
int skip = 0;
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
if(!ejb->jmpbuf_ok) {
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
jmpbuf_reset = 1;
|
||||
int a;
|
||||
if((a=sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))) {
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaCall %d, fs=0x%x\n", a, ejb->emu->segs[_FS]);
|
||||
if((skip=sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))) {
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaCall %d, fs=0x%x\n", skip, ejb->emu->segs[_FS]);
|
||||
addr = R_EIP; // not sure if it should still be inside DynaCall!
|
||||
if(a==2)
|
||||
Run(emu, 1); // "single step" next instruction that is doing auto-smc
|
||||
#ifdef DYNAREC
|
||||
if(box86_dynarec_test) {
|
||||
if(emu->test.clean)
|
||||
x86test_check(emu, R_EIP);
|
||||
emu->test.clean = 0;
|
||||
}
|
||||
#endif
|
||||
if(skip!=2)
|
||||
skip = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,15 +126,18 @@ void DynaCall(x86emu_t* emu, uintptr_t addr)
|
||||
dynablock_t* block = NULL;
|
||||
dynablock_t* current = NULL;
|
||||
while(!emu->quit) {
|
||||
block = DBGetBlock(emu, R_EIP, 1, ¤t);
|
||||
block = (skip==2)?NULL:DBGetBlock(emu, R_EIP, 1);
|
||||
current = block;
|
||||
if(!block || !block->block || !block->done) {
|
||||
skip = 0;
|
||||
// no block, of block doesn't have DynaRec content (yet, temp is not null)
|
||||
// Use interpreter (should use single instruction step...)
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling Interpretor @%p, emu=%p\n", GetTID(), (void*)R_EIP, emu);
|
||||
if(box86_dynarec_test)
|
||||
emu->test.clean = 0;
|
||||
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_EIP, block->block, block->isize ,block->father, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x86 instructions emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize ,emu);
|
||||
CHECK_FLAGS(emu);
|
||||
// block is here, let's run it!
|
||||
#ifdef ARM
|
||||
@@ -173,6 +185,7 @@ int DynaRun(x86emu_t* emu)
|
||||
{
|
||||
// prepare setjump for signal handling
|
||||
emu_jmpbuf_t *ejb = NULL;
|
||||
int skip = 0;
|
||||
#ifdef DYNAREC
|
||||
int jmpbuf_reset = 1;
|
||||
#endif
|
||||
@@ -185,11 +198,17 @@ int DynaRun(x86emu_t* emu)
|
||||
#ifdef DYNAREC
|
||||
jmpbuf_reset = 1;
|
||||
#endif
|
||||
if((a=sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))) {
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaRun %d, fs=0x%x\n", a, ejb->emu->segs[_FS]);
|
||||
if(a==2)
|
||||
Run(emu, 1); // "single step" next instruction that is doing auto-smc
|
||||
|
||||
if((skip=sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))) {
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaRun %d, fs=0x%x\n", skip, ejb->emu->segs[_FS]);
|
||||
#ifdef DYNAREC
|
||||
if(box86_dynarec_test) {
|
||||
if(emu->test.clean)
|
||||
x86test_check(emu, R_EIP);
|
||||
emu->test.clean = 0;
|
||||
}
|
||||
#endif
|
||||
if(skip!=2)
|
||||
skip = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -202,15 +221,18 @@ int DynaRun(x86emu_t* emu)
|
||||
dynablock_t* block = NULL;
|
||||
dynablock_t* current = NULL;
|
||||
while(!emu->quit) {
|
||||
block = DBGetBlock(emu, R_EIP, 1, ¤t);
|
||||
block = (skip==2)?NULL:DBGetBlock(emu, R_EIP, 1);
|
||||
current = block;
|
||||
if(!block || !block->block || !block->done) {
|
||||
skip = 0;
|
||||
// no block, of block doesn't have DynaRec content (yet, temp is not null)
|
||||
// Use interpreter (should use single instruction step...)
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running Interpretor @%p, emu=%p\n", GetTID(), (void*)R_EIP, emu);
|
||||
if(box86_dynarec_test)
|
||||
emu->test.clean = 0;
|
||||
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_EIP, block->block, block->isize, block->father, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x86 insts emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize, emu);
|
||||
// block is here, let's run it!
|
||||
#ifdef ARM
|
||||
arm_prolog(emu, block->block);
|
||||
|
||||
+144
-126
@@ -73,8 +73,8 @@ void add_next(dynarec_arm_t *dyn, uintptr_t addr) {
|
||||
}
|
||||
// add slots
|
||||
if(dyn->next_sz == dyn->next_cap) {
|
||||
dyn->next_cap += 16;
|
||||
dyn->next = (uintptr_t*)box_realloc(dyn->next, dyn->next_cap*sizeof(uintptr_t));
|
||||
dyn->next_cap += 64;
|
||||
dyn->next = (uintptr_t*)dynaRealloc(dyn->next, dyn->next_cap*sizeof(uintptr_t));
|
||||
}
|
||||
dyn->next[dyn->next_sz++] = addr;
|
||||
}
|
||||
@@ -83,11 +83,13 @@ uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr) {
|
||||
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
|
||||
dyn->next[i] = 0;
|
||||
} else {
|
||||
if((dyn->next[i]<best) || !best)
|
||||
best = dyn->next[i];
|
||||
if(dyn->next[i]) {
|
||||
if(dyn->next[i]<addr) { // remove the address, it's before current address
|
||||
dyn->next[i] = 0;
|
||||
} else {
|
||||
if((dyn->next[i]<best) || !best)
|
||||
best = dyn->next[i];
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
@@ -241,35 +243,31 @@ int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n)
|
||||
return (i==n)?1:0;
|
||||
}
|
||||
|
||||
static instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x86_size, int arm_size)
|
||||
void addInst(instsize_t* insts, size_t* size, int x86_size, int native_size)
|
||||
{
|
||||
// x86 instruction is <16 bytes
|
||||
int toadd;
|
||||
if(x86_size>arm_size)
|
||||
if(x86_size>native_size)
|
||||
toadd = 1 + x86_size/15;
|
||||
else
|
||||
toadd = 1 + arm_size/15;
|
||||
if((*size)+toadd>(*cap)) {
|
||||
*cap = (*size)+toadd;
|
||||
insts = (instsize_t*)box_realloc(insts, (*cap)*sizeof(instsize_t));
|
||||
}
|
||||
toadd = 1 + native_size/15;
|
||||
while(toadd) {
|
||||
if(x86_size>15)
|
||||
insts[*size].x86 = 15;
|
||||
else
|
||||
insts[*size].x86 = x86_size;
|
||||
x86_size -= insts[*size].x86;
|
||||
if(arm_size>15)
|
||||
if(native_size>15)
|
||||
insts[*size].nat = 15;
|
||||
else
|
||||
insts[*size].nat = arm_size;
|
||||
arm_size -= insts[*size].nat;
|
||||
insts[*size].nat = native_size;
|
||||
native_size -= insts[*size].nat;
|
||||
++(*size);
|
||||
--toadd;
|
||||
}
|
||||
return insts;
|
||||
}
|
||||
|
||||
|
||||
static void fillPredecessors(dynarec_arm_t* dyn)
|
||||
{
|
||||
int pred_sz = 1; // to be safe
|
||||
@@ -281,6 +279,13 @@ static void fillPredecessors(dynarec_arm_t* dyn)
|
||||
++dyn->insts[dyn->insts[i].x86.jmp_insts].pred_sz;
|
||||
}
|
||||
}
|
||||
// remove "has_next" from orphean branch
|
||||
for(int i=0; i<dyn->size-1; ++i) {
|
||||
if(!dyn->insts[i].x86.has_next) {
|
||||
if(dyn->insts[i+1].x86.has_next && !dyn->insts[i+1].pred_sz)
|
||||
dyn->insts[i+1].x86.has_next = 0;
|
||||
}
|
||||
}
|
||||
// second the "has_next"
|
||||
for(int i=0; i<dyn->size-1; ++i) {
|
||||
if(dyn->insts[i].x86.has_next) {
|
||||
@@ -288,7 +293,7 @@ static void fillPredecessors(dynarec_arm_t* dyn)
|
||||
++dyn->insts[i+1].pred_sz;
|
||||
}
|
||||
}
|
||||
dyn->predecessor = (int*)box_malloc(pred_sz*sizeof(int));
|
||||
dyn->predecessor = (int*)dynaMalloc(pred_sz*sizeof(int));
|
||||
// fill pred pointer
|
||||
int* p = dyn->predecessor;
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
@@ -305,8 +310,6 @@ static void fillPredecessors(dynarec_arm_t* dyn)
|
||||
dyn->insts[j].pred[dyn->insts[j].pred_sz++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// updateNeed goes backward, from last intruction to top
|
||||
@@ -349,43 +352,77 @@ static int updateNeed(dynarec_arm_t* dyn, int ninst, uint8_t need) {
|
||||
else
|
||||
updateNeed(dyn, dyn->insts[ninst].pred[i], need);
|
||||
}
|
||||
if(!ok)
|
||||
return ninst - 1;
|
||||
--ninst;
|
||||
if(!ok)
|
||||
return ninst;
|
||||
}
|
||||
return ninst;
|
||||
}
|
||||
|
||||
void* current_helper = NULL;
|
||||
|
||||
void CancelBlock(int need_lock)
|
||||
{
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
dynarec_arm_t* helper = (dynarec_arm_t*)current_helper;
|
||||
current_helper = NULL;
|
||||
if(helper) {
|
||||
dynaFree(helper->next);
|
||||
dynaFree(helper->insts);
|
||||
dynaFree(helper->predecessor);
|
||||
if(helper->dynablock && helper->dynablock->actual_block) {
|
||||
FreeDynarecMap((uintptr_t)helper->dynablock->actual_block);
|
||||
helper->dynablock->actual_block = NULL;
|
||||
}
|
||||
}
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
|
||||
uintptr_t arm_pass0(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
uintptr_t arm_pass1(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
uintptr_t arm_pass2(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
uintptr_t arm_pass3(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
|
||||
void* current_helper = NULL;
|
||||
|
||||
void CancelBlock()
|
||||
{
|
||||
dynarec_arm_t* helper = (dynarec_arm_t*)current_helper;
|
||||
current_helper = NULL;
|
||||
if(!helper)
|
||||
return;
|
||||
box_free(helper->next);
|
||||
box_free(helper->insts);
|
||||
box_free(helper->predecessor);
|
||||
if(helper->dynablock && helper->dynablock->block)
|
||||
FreeDynarecMap(helper->dynablock, (uintptr_t)helper->dynablock->block, helper->dynablock->size);
|
||||
}
|
||||
void arm_epilog();
|
||||
void arm_next();
|
||||
|
||||
void* CreateEmptyBlock(dynablock_t* block, uintptr_t addr) {
|
||||
block->isize = 0;
|
||||
block->done = 0;
|
||||
block->size = 0;
|
||||
block->block = NULL;
|
||||
block->need_test = 0;
|
||||
size_t sz = 8*sizeof(void*);
|
||||
void* actual_p = (void*)AllocDynarecMap(sz);
|
||||
void* p = actual_p + sizeof(void*);
|
||||
if(actual_p==NULL) {
|
||||
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, cancelling block\n", block, sz);
|
||||
CancelBlock(0);
|
||||
return NULL;
|
||||
}
|
||||
block->size = sz;
|
||||
block->actual_block = actual_p;
|
||||
block->block = p;
|
||||
block->jmpnext = p;
|
||||
*(dynablock_t**)actual_p = block;
|
||||
*(void**)(p+4*sizeof(void*)) = arm_epilog;
|
||||
CreateJmpNext(block->jmpnext, p+4*sizeof(void*));
|
||||
// all done...
|
||||
__clear_cache(actual_p, actual_p+sz); // need to clear the cache before execution...
|
||||
return block;
|
||||
}
|
||||
|
||||
void* FillBlock(dynablock_t* block, uintptr_t addr) {
|
||||
/*
|
||||
A Block must have this layout:
|
||||
|
||||
0x0000..0x0003 : dynablock_t* : self
|
||||
0x0004..4+4*n : actual Native instructions, (n is the total number)
|
||||
B .. B+3 : dynablock_t* : self (as part of JmpNext, that simulate another block)
|
||||
B+4 .. B+15 : 3 Native code for jmpnext (or jmp epilog in case of empty block)
|
||||
B+16 .. B+19 : jmpnext (or jmp_epilog) address
|
||||
B+20 .. B+31 : empty (in case an architecture needs more than 3 opcodes)
|
||||
B+32 .. B+32+sz : instsize (compressed array with each instruction lenght on x86 and native side)
|
||||
|
||||
*/
|
||||
dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
if(IsInHotPage(addr)) {
|
||||
dynarec_log(LOG_DEBUG, "Cancelling dynarec FillBlock on hotpage for %p\n", (void*)addr);
|
||||
@@ -395,10 +432,6 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
dynarec_log(LOG_DEBUG, "Asked to fill a block in fobidden zone\n");
|
||||
return CreateEmptyBlock(block, addr);
|
||||
}
|
||||
if(!isJumpTableDefault((void*)addr)) {
|
||||
dynarec_log(LOG_DEBUG, "Asked to fill a block at %p, but JumpTable is not default\n", (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
if(current_helper) {
|
||||
dynarec_log(LOG_DEBUG, "Cancelling dynarec FillBlock at %p as anothor one is going on\n", (void*)addr);
|
||||
return NULL;
|
||||
@@ -412,23 +445,23 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
helper.start = addr;
|
||||
uintptr_t start = addr;
|
||||
helper.cap = 64; // needs epilog handling
|
||||
helper.insts = (instruction_arm_t*)box_calloc(helper.cap, sizeof(instruction_arm_t));
|
||||
helper.insts = (instruction_arm_t*)dynaCalloc(helper.cap, sizeof(instruction_arm_t));
|
||||
// pass 0, addresses, x86 jump addresses, overall size of the block
|
||||
uintptr_t end = arm_pass0(&helper, addr);
|
||||
// no need for next anymore
|
||||
box_free(helper.next);
|
||||
dynaFree(helper.next);
|
||||
helper.next_sz = helper.next_cap = 0;
|
||||
helper.next = NULL;
|
||||
// basic checks
|
||||
if(!helper.size) {
|
||||
dynarec_log(LOG_DEBUG, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
|
||||
CancelBlock();
|
||||
return (void*)block;
|
||||
CancelBlock(0);
|
||||
return CreateEmptyBlock(block, addr);
|
||||
}
|
||||
if(!isprotectedDB(addr, 1)) {
|
||||
dynarec_log(LOG_INFO, "Warning, write on current page on pass0, aborting dynablock creation (%p)\n", (void*)addr);
|
||||
AddHotPage(addr);
|
||||
CancelBlock();
|
||||
CancelBlock(0);
|
||||
return NULL;
|
||||
}
|
||||
// already protect the block and compute hash signature
|
||||
@@ -441,6 +474,8 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
if(helper.insts[i].x86.jmp) {
|
||||
uintptr_t j = helper.insts[i].x86.jmp;
|
||||
if(j<start || j>=end || j==helper.insts[i].x86.addr) {
|
||||
if(j==helper.insts[i].x86.addr) // if there is a loop on some opcode, make the block "always to tested"
|
||||
helper.always_test = 1;
|
||||
helper.insts[i].x86.jmp_insts = -1;
|
||||
helper.insts[i].x86.need_after |= X_PEND;
|
||||
} else {
|
||||
@@ -468,29 +503,69 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
// pass 2, instruction size
|
||||
arm_pass2(&helper, addr);
|
||||
// ok, now allocate mapped memory, with executable flag on
|
||||
int sz = helper.arm_size;
|
||||
void* p = (void*)AllocDynarecMap(block, sz);
|
||||
if(p==NULL) {
|
||||
dynarec_log(LOG_DEBUG, "AllocDynarecMap(%p, %d) failed, cancelling block\n", block, sz);
|
||||
CancelBlock();
|
||||
size_t insts_rsize = (helper.insts_size+2)*sizeof(instsize_t);
|
||||
insts_rsize = (insts_rsize+7)&~7; // round the size...
|
||||
size_t arm_size = (helper.arm_size+7)&~7; // round the size...
|
||||
// ok, now allocate mapped memory, with executable flag on
|
||||
size_t sz = sizeof(void*) + arm_size + 8*sizeof(void*) + insts_rsize;
|
||||
// dynablock_t* block (arm insts) jmpnext code instsize
|
||||
void* actual_p = (void*)AllocDynarecMap(sz);
|
||||
void* p = (void*)(((uintptr_t)actual_p) + sizeof(void*));
|
||||
void* next = p + arm_size;
|
||||
void* instsize = next + 8*sizeof(void*);
|
||||
if(actual_p==NULL) {
|
||||
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, cancelling block\n", block, sz);
|
||||
CancelBlock(0);
|
||||
return NULL;
|
||||
}
|
||||
helper.block = p;
|
||||
block->actual_block = actual_p;
|
||||
helper.arm_start = (uintptr_t)p;
|
||||
if(helper.sons_size) {
|
||||
helper.sons_x86 = (uintptr_t*)alloca(helper.sons_size*sizeof(uintptr_t));
|
||||
helper.sons_arm = (void**)alloca(helper.sons_size*sizeof(void*));
|
||||
}
|
||||
// pass 3, emit (log emit arm opcode)
|
||||
helper.jmp_next = (uintptr_t)next+sizeof(void*);
|
||||
helper.instsize = (instsize_t*)instsize;
|
||||
*(dynablock_t**)actual_p = block;
|
||||
// pass 3, emit (log emit native opcode)
|
||||
if(box86_dynarec_dump) {
|
||||
dynarec_log(LOG_NONE, "%s%04d|Emitting %d bytes for %d x86 bytes", (box86_dynarec_dump>1)?"\e[01;36m":"", GetTID(), helper.arm_size, helper.isize);
|
||||
printFunctionAddr(helper.start, " => ");
|
||||
dynarec_log(LOG_NONE, "%s\n", (box86_dynarec_dump>1)?"\e[m":"");
|
||||
}
|
||||
size_t oldarmsize = helper.arm_size;
|
||||
size_t oldinstsize = helper.insts_size;
|
||||
helper.arm_size = 0;
|
||||
helper.insts_size = 0; // reset
|
||||
arm_pass3(&helper, addr);
|
||||
if(sz!=helper.arm_size) {
|
||||
printf_log(LOG_NONE, "BOX86: Warning, size difference in block between pass2 (%d) & pass3 (%d)!\n", sz, helper.arm_size);
|
||||
// keep size of instructions for signal handling
|
||||
block->instsize = instsize;
|
||||
// ok, free the helper now
|
||||
dynaFree(helper.insts);
|
||||
helper.insts = NULL;
|
||||
helper.instsize = NULL;
|
||||
dynaFree(helper.predecessor);
|
||||
helper.predecessor = NULL;
|
||||
block->size = sz;
|
||||
block->isize = helper.size;
|
||||
block->block = p;
|
||||
block->jmpnext = next+sizeof(void*);
|
||||
block->always_test = helper.always_test;
|
||||
block->dirty = block->always_test;
|
||||
*(dynablock_t**)next = block;
|
||||
*(void**)(next+5*sizeof(void*)) = arm_next;
|
||||
CreateJmpNext(block->jmpnext, next+5*sizeof(void*));
|
||||
//block->x86_addr = (void*)start;
|
||||
block->x86_size = end-start;
|
||||
// all done...
|
||||
__clear_cache(actual_p, actual_p+sz); // need to clear the cache before execution...
|
||||
block->hash = X31_hash_code(block->x86_addr, block->x86_size);
|
||||
// Check if something changed, to abbort if it as
|
||||
if((block->hash != hash)) {
|
||||
dynarec_log(LOG_DEBUG, "Warning, a block changed while being processed hash(%p:%zu)=%x/%x\n", block->x86_addr, block->x86_size, block->hash, hash);
|
||||
AddHotPage(addr);
|
||||
CancelBlock(0);
|
||||
return NULL;
|
||||
}
|
||||
if((oldarmsize!=helper.arm_size)) {
|
||||
printf_log(LOG_NONE, "BOx86: Warning, size difference in block between pass2 (%zu) & pass3 (%zu)!\n", sz, helper.arm_size);
|
||||
uint8_t *dump = (uint8_t*)helper.start;
|
||||
printf_log(LOG_NONE, "Dump of %d x86 opcodes:\n", helper.size);
|
||||
for(int i=0; i<helper.size; ++i) {
|
||||
@@ -500,76 +575,19 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
printf_log(LOG_NONE, "\t%d -> %d\n", helper.insts[i].size2, helper.insts[i].size);
|
||||
}
|
||||
printf_log(LOG_NONE, " ------------\n");
|
||||
}
|
||||
// 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].x86.size>helper.insts[i].size)?helper.insts[i].x86.size:helper.insts[i].size)/15;
|
||||
size_t size = 0;
|
||||
block->instsize = (instsize_t*)box_calloc(cap, sizeof(instsize_t));
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
block->instsize = addInst(block->instsize, &size, &cap, helper.insts[i].x86.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
|
||||
box_free(helper.insts);
|
||||
helper.insts = NULL;
|
||||
box_free(helper.next);
|
||||
helper.next = NULL;
|
||||
block->size = sz;
|
||||
block->isize = helper.size;
|
||||
block->block = p;
|
||||
block->need_test = 0;
|
||||
//block->x86_addr = (void*)start;
|
||||
block->x86_size = end-start;
|
||||
if(box86_dynarec_largest<block->x86_size)
|
||||
box86_dynarec_largest = block->x86_size;
|
||||
block->hash = X31_hash_code(block->x86_addr, block->x86_size);
|
||||
// Check if something changed, to abbort if it as
|
||||
if(block->hash != hash) {
|
||||
dynarec_log(LOG_INFO, "Warning, a block changed while beeing processed hash(%p:%d)=%x/%x\n", block->x86_addr, block->x86_size, block->hash, hash);
|
||||
CancelBlock();
|
||||
AddHotPage(addr);
|
||||
CancelBlock(0);
|
||||
return NULL;
|
||||
}
|
||||
if(insts_rsize/sizeof(instsize_t)<helper.insts_size) {
|
||||
printf_log(LOG_NONE, "BOX86: Warning, ists_size difference in block between pass2 (%zu) and pass3 (%zu), allocated: %zu\n", oldinstsize, helper.insts_size, insts_rsize/sizeof(instsize_t));
|
||||
}
|
||||
if(!isprotectedDB(addr, end-addr)) {
|
||||
dynarec_log(LOG_DEBUG, "Warning, block unprotected while beeing processed %p:%zd, cancelling\n", block->x86_addr, block->x86_size);
|
||||
dynarec_log(LOG_DEBUG, "Warning, block unprotected while being processed %p:%zu, marking as need_test\n", block->x86_addr, block->x86_size);
|
||||
AddHotPage(addr);
|
||||
block->need_test = 1;
|
||||
block->dirty = 1;
|
||||
//protectDB(addr, end-addr);
|
||||
}
|
||||
// fill sons if any
|
||||
dynablock_t** sons = NULL;
|
||||
int sons_size = 0;
|
||||
if(helper.sons_size) {
|
||||
sons = (dynablock_t**)box_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_x86[i], &created);
|
||||
if(created) { // avoid breaking a working block!
|
||||
son->block = helper.sons_arm[i];
|
||||
son->x86_addr = (void*)helper.sons_x86[i];
|
||||
son->x86_size = end-helper.sons_x86[i];
|
||||
if(!son->x86_size) {printf_log(LOG_NONE, "Warning, son with null x86 size! (@%p / ARM=%p)", son->x86_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
|
||||
box_free(sons);
|
||||
}
|
||||
box_free(helper.predecessor);
|
||||
helper.predecessor = NULL;
|
||||
current_helper = NULL;
|
||||
block->done = 1;
|
||||
//block->done = 1;
|
||||
return (void*)block;
|
||||
}
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
int isRetX87Wrapper(wrapper_t fun);
|
||||
|
||||
uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop, opcode;
|
||||
@@ -1245,6 +1247,15 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
AND_REG_LSL_IMM5(xFlags, xFlags, x1, 0);
|
||||
ORR_IMM8(xFlags, xFlags, 2, 0);
|
||||
SET_DFNONE(x1);
|
||||
if(box86_wine) { // should this be done all the time?
|
||||
TSTS_IMM8_ROR(xFlags, 0x1, 12); // 0x100 == F_TF
|
||||
B_NEXT(cEQ);
|
||||
MOV32(x1, addr);
|
||||
STM(xEmu, (1<<xEAX)|(1<<xEBX)|(1<<xECX)|(1<<xEDX)|(1<<xESI)|(1<<xEDI)|(1<<xESP)|(1<<xEBP));
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, ip));
|
||||
CALL(arm_singlestep, -1, 0);
|
||||
BFC(xFlags, F_TF, 1); // should not be needed
|
||||
}
|
||||
break;
|
||||
case 0x9E:
|
||||
INST_NAME("SAHF");
|
||||
@@ -1663,6 +1674,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if((PK(0)==0) && (PK(1)==0) && (PK(2)==0) && (PK(3)==0))
|
||||
{
|
||||
addr+=4;
|
||||
SKIPTEST(x14);
|
||||
MESSAGE(LOG_DEBUG, "Exit x86 Emu\n");
|
||||
MOV32(x14, ip+1+2);
|
||||
STM(xEmu, (1<<xEAX)|(1<<xEBX)|(1<<xECX)|(1<<xEDX)|(1<<xESI)|(1<<xEDI)|(1<<xESP)|(1<<xEBP)|(1<<xEIP)|(1<<xFlags));
|
||||
@@ -1672,6 +1684,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
*need_epilog = 1;
|
||||
} else {
|
||||
MESSAGE(LOG_DUMP, "Native Call to %s\n", GetNativeName(GetNativeFnc(ip)));
|
||||
SKIPTEST(x14);
|
||||
x87_forget(dyn, ninst, x3, x14, 0);
|
||||
if((box86_log<2) && !cycle_log) { // call the wrapper directly
|
||||
uintptr_t ncall[2]; // to avoid BUSERROR!!!
|
||||
@@ -1715,10 +1728,11 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xCD:
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack, set all flags (to an unknown state...)
|
||||
SKIPTEST(x14);
|
||||
SMEND();
|
||||
if(PK(0)==0x80) {
|
||||
u8 = F8;
|
||||
if(u8==0x80) {
|
||||
INST_NAME("Syscall");
|
||||
u8 = F8;
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
MOV32(xEIP, ip+2);
|
||||
STM(xEmu, (1<<xEAX)|(1<<xEBX)|(1<<xECX)|(1<<xEDX)|(1<<xESI)|(1<<xEDI)|(1<<xESP)|(1<<xEBP)|(1<<xEIP)|(1<<xFlags));
|
||||
@@ -1734,7 +1748,11 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
jump_to_epilog(dyn, 0, xEIP, ninst);
|
||||
} else {
|
||||
INST_NAME("INT Ib");
|
||||
DEFAULT;
|
||||
if(box86_wine && u8==0x2D) {
|
||||
MESSAGE(LOG_DEBUG, "Hack for wine/int 2d\n");
|
||||
} else {
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2158,8 +2176,8 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
tmp = dyn->insts[ninst].pass2choice = 1;
|
||||
else if ((getProtection(u32)&PROT_READ) && (PKa(u32+0)==0x8B) && (((PKa(u32+1))&0xC7)==0x04) && (PKa(u32+2)==0x24) && (PKa(u32+3)==0xC3))
|
||||
tmp = dyn->insts[ninst].pass2choice = 2;
|
||||
/*else if(isNativeCall(dyn, u32, &dyn->insts[ninst].natcall, &dyn->insts[ninst].retn))
|
||||
tmp = dyn->insts[ninst].pass2choice = 3;*/
|
||||
else if(isNativeCall(dyn, u32, &dyn->insts[ninst].natcall, &dyn->insts[ninst].retn))
|
||||
tmp = dyn->insts[ninst].pass2choice = 3;
|
||||
else
|
||||
tmp = dyn->insts[ninst].pass2choice = 0;
|
||||
#else
|
||||
@@ -2169,18 +2187,19 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 1:
|
||||
//SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
|
||||
MESSAGE(LOG_DUMP, "Hack for Call 0\n");
|
||||
SKIPTEST(x14);
|
||||
MOV32(xEIP, addr);
|
||||
PUSH1(xEIP);
|
||||
break;
|
||||
case 2:
|
||||
//SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
|
||||
MESSAGE(LOG_DUMP, "Hack for Call x86.get_pc_thunk.reg\n");
|
||||
SKIPTEST(x14);
|
||||
u8 = PK(i32+1);
|
||||
gd = xEAX+((u8&0x38)>>3);
|
||||
MOV32(gd, addr);
|
||||
break;
|
||||
// disabling this to avoid fetching data outside current block (in case this part changed, this block will not been marck as dirty)
|
||||
/*case 3:
|
||||
case 3:
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
|
||||
BARRIER(BARRIER_FULL);
|
||||
BARRIER_NEXT(BARRIER_FULL);
|
||||
@@ -2188,7 +2207,10 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
PUSH1(x2);
|
||||
MESSAGE(LOG_DUMP, "Native Call to %s (retn=%d)\n", GetNativeName(GetNativeFnc(dyn->insts[ninst].natcall-1)), dyn->insts[ninst].retn);
|
||||
// calling a native function
|
||||
x87_forget(dyn, ninst, x3, x14, 0);
|
||||
if(isRetX87Wrapper(*(wrapper_t*)(dyn->insts[ninst].natcall+2))) {
|
||||
// return value will be on the stack, so the stack depth needs to be updated
|
||||
x87_purgecache(dyn, ninst, 0, x3, x14, x1);
|
||||
}
|
||||
if((box86_log<2) && !cycle_log && dyn->insts[ninst].natcall) { // call the wrapper directly
|
||||
uintptr_t ncall[2];
|
||||
memcpy(ncall, (void*)(dyn->insts[ninst].natcall+2), 2*sizeof(void*)); // the wrapper + function
|
||||
@@ -2219,16 +2241,22 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
B_NEXT(cNE); // not quitting, so lets continue
|
||||
MARK;
|
||||
jump_to_epilog(dyn, 0, xEIP, ninst);
|
||||
break;*/
|
||||
break;
|
||||
default:
|
||||
if((box86_dynarec_safeflags>1) || (ninst && dyn->insts[ninst-1].x86.set_flags)) {
|
||||
READFLAGS(X_PEND); // that's suspicious
|
||||
} else {
|
||||
//SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
|
||||
}
|
||||
// regular call
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
//BARRIER_NEXT(BARRIER_FULL);
|
||||
if(/*box86_dynarec_callret &&*/ box86_dynarec_bigblock>1) {
|
||||
BARRIER(BARRIER_FULL);
|
||||
} else {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
MOV32(x2, addr);
|
||||
@@ -2252,11 +2280,11 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("JMP Ib");
|
||||
i32 = F8S;
|
||||
}
|
||||
JUMP(addr+i32, 0);
|
||||
JUMP((uintptr_t)getAlternate((void*)(addr+i32)), 0);
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1) {
|
||||
// out of the block
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3);
|
||||
jump_to_next(dyn, addr+i32, 0, ninst);
|
||||
jump_to_next(dyn, (uintptr_t)getAlternate((void*)(addr+i32)), 0, ninst);
|
||||
} else {
|
||||
// inside the block
|
||||
CacheTransform(dyn, ninst, CHECK_CACHE(), x1, x2, x3);
|
||||
@@ -2271,9 +2299,19 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
*ok = 0;
|
||||
break;
|
||||
|
||||
case 0xEE:
|
||||
INST_NAME("OUT dx, al");
|
||||
//ignored!
|
||||
case 0xEC: /* IN AL, DX */
|
||||
case 0xED: /* IN EAX, DX */
|
||||
case 0xEE: /* OUT DX, AL */
|
||||
case 0xEF: /* OUT DX, EAX */
|
||||
INST_NAME(opcode==0xEC?"IN AL, DX":(opcode==0xED?"IN EAX, DX":(opcode==0xEE?"OUT DX? AL":"OUT DX, EAX")));
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags in "don't care" state
|
||||
STM(xEmu, (1<<xEAX)|(1<<xECX)|(1<<xEDX)|(1<<xEBX)|(1<<xESP)|(1<<xEBP)|(1<<xESI)|(1<<xEDI)|(1<<xFlags));
|
||||
STR_IMM9(xEIP, xEmu, offsetof(x86emu_t, ip));
|
||||
CALL(arm_priv, -1, 0);
|
||||
LDR_IMM9(xEIP, xEmu, offsetof(x86emu_t, ip));
|
||||
jump_to_epilog(dyn, 0, xEIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
@@ -2764,13 +2802,16 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ORRS_IMM8(xFlags, xFlags, 1, 0);
|
||||
break;
|
||||
case 0xFA:
|
||||
INST_NAME("CLI");
|
||||
BFC(xFlags, F_IF, 1);
|
||||
break;
|
||||
case 0xFB:
|
||||
INST_NAME("STI");
|
||||
MOVW(x1, 1);
|
||||
BFI(xFlags, x1, F_IF, 1);
|
||||
INST_NAME(opcode==0xFA?"STI":"CLI");
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags in "don't care" state
|
||||
STM(xEmu, (1<<xEAX)|(1<<xECX)|(1<<xEDX)|(1<<xEBX)|(1<<xESP)|(1<<xEBP)|(1<<xESI)|(1<<xEDI)|(1<<xFlags));
|
||||
STR_IMM9(xEIP, xEmu, offsetof(x86emu_t, ip));
|
||||
CALL(arm_priv, -1, 0);
|
||||
LDR_IMM9(xEIP, xEmu, offsetof(x86emu_t, ip));
|
||||
jump_to_epilog(dyn, 0, xEIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
case 0xFC:
|
||||
INST_NAME("CLD");
|
||||
@@ -2823,10 +2864,13 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 2: // CALL Ed
|
||||
INST_NAME("CALL Ed");
|
||||
PASS2IF((box86_dynarec_safeflags>1) || (ninst && dyn->insts[ninst-1].x86.set_flags), 1) {
|
||||
PASS2IF((box86_dynarec_safeflags>1) ||
|
||||
((ninst && dyn->insts[ninst-1].x86.set_flags)
|
||||
|| ((ninst>1) && dyn->insts[ninst-2].x86.set_flags)), 1)
|
||||
{
|
||||
READFLAGS(X_PEND); // that's suspicious
|
||||
} else {
|
||||
//SETFLAGS(X_ALL, SF_SET); //Hack to put flag in "don't care" state
|
||||
SETFLAGS(X_ALL, SF_SET); //Hack to put flag in "don't care" state
|
||||
}
|
||||
GETEDH(xEIP);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
|
||||
@@ -90,6 +90,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("UD2");
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags in "don't care" state
|
||||
//CALL(arm_ud, -1, 0);
|
||||
SKIPTEST(x14);
|
||||
UDF(0);
|
||||
break;
|
||||
|
||||
@@ -421,6 +422,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x31:
|
||||
INST_NAME("RDTSC");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SKIPTEST(x14);
|
||||
CALL(ReadTSC, xEAX, 0); // will return the u64 in x1:xEAX
|
||||
MOV_REG(xEDX, x1);
|
||||
break;
|
||||
@@ -656,6 +658,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0x51:
|
||||
INST_NAME("SQRTPS Gx, Ex");
|
||||
SKIPTEST(x1);
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
gd = (nextop&0x38)>>3;
|
||||
@@ -695,19 +698,42 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0x52:
|
||||
INST_NAME("RSQRTPS Gx, Ex");
|
||||
SKIPTEST(x1);
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
q1 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
v0 = fpu_get_scratch_quad(dyn);
|
||||
if(q1==q0 || !box86_dynarec_fastnan)
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
else
|
||||
v1 = q1;
|
||||
VRSQRTEQ_F32(v0, q0);
|
||||
VMULQ_F32(v1, v0, q0);
|
||||
VRSQRTSQ_F32(v1, v1, v0);
|
||||
VMULQ_F32(q1, v1, v0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VCEQQ_F32(v1, q1, q1); // 00 is nan
|
||||
VANDQ(q1, q1, v1); // if nan, remove
|
||||
VBICQ(v0, v0, v1); // if nan, keep
|
||||
VORRQ(q1, q1, v0);
|
||||
}
|
||||
break;
|
||||
case 0x53:
|
||||
INST_NAME("RCPPS Gx, Ex");
|
||||
SKIPTEST(x1);
|
||||
nextop = F8;
|
||||
GETEX(q0, 0);
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
q1 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
if(q0 == q1)
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
else
|
||||
v1 = q1;
|
||||
v0 = fpu_get_scratch_quad(dyn);
|
||||
VRECPEQ_F32(v0, q0);
|
||||
VRECPSQ_F32(v1, v0, q0);
|
||||
VMULQ_F32(q1, v0, v1);
|
||||
break;
|
||||
case 0x54:
|
||||
INST_NAME("ANDPS Gx, Ex");
|
||||
@@ -791,7 +817,23 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0);
|
||||
// VMIN/VMAX wll put default NaN if any input is NaN
|
||||
// but x86 will copy if either v0[x] or v1[x] is NaN, so lets force a copy if source is NaN
|
||||
if(!box86_dynarec_fastnan) {
|
||||
if(v0==v1) {
|
||||
q1 = fpu_get_scratch_quad(dyn);
|
||||
VMOVQ(q1, v1);
|
||||
} else
|
||||
q1 = v1;
|
||||
}
|
||||
VMINQ_F32(v0, v0, v1);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
VCEQQ_F32(q0, v0, v0); // 0 is NaN, -1 is not NaN
|
||||
VANDQ(v0, v0, q0);
|
||||
VBICQ(q0, q1, q0);
|
||||
VORRQ(v0, v0, q0);
|
||||
}
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVPS Gx, Ex");
|
||||
@@ -815,7 +857,23 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0);
|
||||
// VMIN/VMAX wll put default NaN if any input is NaN
|
||||
// but x86 will copy if either v0[x] or v1[x] is NaN, so lets force a copy if source is NaN
|
||||
if(!box86_dynarec_fastnan) {
|
||||
if(v0==v1) {
|
||||
q1 = fpu_get_scratch_quad(dyn);
|
||||
VMOVQ(q1, v1);
|
||||
} else
|
||||
q1 = v1;
|
||||
}
|
||||
VMAXQ_F32(v0, v0, v1);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
VCEQQ_F32(q0, v0, v0); // 0 is NaN, -1 is not NaN
|
||||
VANDQ(v0, v0, q0);
|
||||
VBICQ(q0, q1, q0);
|
||||
VORRQ(v0, v0, q0);
|
||||
}
|
||||
break;
|
||||
case 0x60:
|
||||
INST_NAME("PUNPCKLBW Gm,Em");
|
||||
@@ -1640,7 +1698,20 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("XRSTOR Ed (not implemented");
|
||||
FAKEED;
|
||||
SETFLAGS(X_ALL, SF_SET); // Hack to set flags in "don't care" state
|
||||
STM(xEmu, (1<<xEAX)|(1<<xECX)|(1<<xEDX)|(1<<xEBX)|(1<<xESP)|(1<<xEBP)|(1<<xESI)|(1<<xEDI)|(1<<xFlags));
|
||||
STR_IMM9(xEIP, xEmu, offsetof(x86emu_t, ip));
|
||||
CALL(arm_ud, -1, 0);
|
||||
LDR_IMM9(xEIP, xEmu, offsetof(x86emu_t, ip));
|
||||
jump_to_epilog(dyn, 0, xEIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("CLFLUSH Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization?\n");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL_(arm_clflush, -1, 0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
|
||||
@@ -313,7 +313,10 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 2: // CALL Ed
|
||||
INST_NAME("CALL FS:Ed");
|
||||
PASS2IF(ninst && dyn->insts[ninst-1].x86.set_flags, 1) {
|
||||
PASS2IF((box86_dynarec_safeflags>1) ||
|
||||
((ninst && dyn->insts[ninst-1].x86.set_flags)
|
||||
|| ((ninst>1) && dyn->insts[ninst-2].x86.set_flags)), 1)
|
||||
{
|
||||
READFLAGS(X_PEND); // that's suspicious
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET); //Hack to put flag in "don't care" state
|
||||
|
||||
@@ -230,7 +230,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
VLD1Q_32(v0, ed);
|
||||
VLD1Q_64(v0, ed);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
@@ -244,7 +244,23 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
VST1Q_32(v0, ed);
|
||||
VST1Q_64(v0, ed);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0x2B:
|
||||
INST_NAME("MOVNTPD Ex, Gx");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
VST1Q_64(v0, ed);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
@@ -2295,7 +2311,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VPADDLQ_U32(q0, q0);
|
||||
break;
|
||||
case 0xF7:
|
||||
INST_NAME("MASKMOVDQU Gx, Ex")
|
||||
INST_NAME("MASKMOVDQU Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0);
|
||||
|
||||
@@ -194,7 +194,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
|
||||
case 0xE8:
|
||||
INST_NAME("FLD1");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
v1 = x87_do_push(dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
VMOV_i_32(v1, 0b01110000);
|
||||
} else {
|
||||
@@ -204,7 +204,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xE9:
|
||||
INST_NAME("FLDL2T");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
v1 = x87_do_push(dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
MOV32(x2, (&f_l2t));
|
||||
VLDR_32(v1, x2, 0);
|
||||
@@ -216,7 +216,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xEA:
|
||||
INST_NAME("FLDL2E");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
v1 = x87_do_push(dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
MOV32(x2, (&f_l2e));
|
||||
VLDR_32(v1, x2, 0);
|
||||
@@ -228,7 +228,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xEB:
|
||||
INST_NAME("FLDPI");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
v1 = x87_do_push(dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
MOV32(x2, (&f_pi));
|
||||
VLDR_32(v1, x2, 0);
|
||||
@@ -240,7 +240,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xEC:
|
||||
INST_NAME("FLDLG2");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
v1 = x87_do_push(dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
MOV32(x2, (&f_lg2));
|
||||
VLDR_32(v1, x2, 0);
|
||||
@@ -252,7 +252,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xED:
|
||||
INST_NAME("FLDLN2");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
v1 = x87_do_push(dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
MOV32(x2, (&f_ln2));
|
||||
VLDR_32(v1, x2, 0);
|
||||
@@ -264,7 +264,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xEE:
|
||||
INST_NAME("FLDZ");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
v1 = x87_do_push(dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
VMOV_8(v1/2, 0); // float is *2...
|
||||
} else {
|
||||
@@ -309,7 +309,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xF2:
|
||||
INST_NAME("FPTAN");
|
||||
v2 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
v2 = x87_do_push(dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
VMOV_64(0, v1); // prepare call to tan
|
||||
CALL_1D(tan, 0);
|
||||
@@ -589,7 +589,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FST float[ED], ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0))
|
||||
s0 = v1;
|
||||
else {
|
||||
@@ -608,7 +608,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FSTP float[ED], ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0))
|
||||
s0 = v1;
|
||||
else {
|
||||
|
||||
@@ -161,7 +161,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ew");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
v1 = x87_do_push(dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0, NULL);
|
||||
LDRSH_IMM8(x1, wback, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
@@ -175,7 +175,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FISTTP Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0, 0, NULL);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
@@ -202,7 +202,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FIST Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
u8 = x87_setround_reset(dyn, ninst, x1, x2, x14);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0, 0, NULL);
|
||||
ed = x1;
|
||||
@@ -224,7 +224,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FISTP Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
u8 = x87_setround_reset(dyn, ninst, x1, x2, x14);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0, 0, NULL);
|
||||
ed = x1;
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "bridge.h"
|
||||
#include "arm_printer.h"
|
||||
#include "custommem.h"
|
||||
|
||||
void arm_fstp(x86emu_t* emu, void* p)
|
||||
{
|
||||
@@ -109,7 +111,7 @@ void arm_fistp64(x86emu_t* emu, int64_t* ed)
|
||||
memcpy(ed, &STll(0).sq, 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))
|
||||
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, -(double)(uint64_t)0x8000000000000000LL) || !isfinite(ST0.d))
|
||||
tmp = 0x8000000000000000LL;
|
||||
else
|
||||
tmp = fpu_round(emu, ST0.d);
|
||||
@@ -120,7 +122,7 @@ void arm_fistp64(x86emu_t* emu, int64_t* ed)
|
||||
int64_t arm_fist64_0(double d)
|
||||
{
|
||||
int64_t tmp;
|
||||
if(isgreater(d, (double)(int64_t)0x7fffffffffffffffLL) || isless(d, (double)(int64_t)0x8000000000000000LL) || !isfinite(d))
|
||||
if(isgreater(d, (double)(int64_t)0x7fffffffffffffffLL) || isless(d, -(double)(uint64_t)0x8000000000000000LL) || !isfinite(d))
|
||||
tmp = 0x8000000000000000LL;
|
||||
else
|
||||
tmp = nearbyint(d);
|
||||
@@ -129,7 +131,7 @@ int64_t arm_fist64_0(double d)
|
||||
int64_t arm_fist64_1(double d)
|
||||
{
|
||||
int64_t tmp;
|
||||
if(isgreater(d, (double)(int64_t)0x7fffffffffffffffLL) || isless(d, (double)(int64_t)0x8000000000000000LL) || !isfinite(d))
|
||||
if(isgreater(d, (double)(int64_t)0x7fffffffffffffffLL) || isless(d, -(double)(uint64_t)0x8000000000000000LL) || !isfinite(d))
|
||||
tmp = 0x8000000000000000LL;
|
||||
else
|
||||
tmp = floor(d);
|
||||
@@ -138,7 +140,7 @@ int64_t arm_fist64_1(double d)
|
||||
int64_t arm_fist64_2(double d)
|
||||
{
|
||||
int64_t tmp;
|
||||
if(isgreater(d, (double)(int64_t)0x7fffffffffffffffLL) || isless(d, (double)(int64_t)0x8000000000000000LL) || !isfinite(d))
|
||||
if(isgreater(d, (double)(int64_t)0x7fffffffffffffffLL) || isless(d, -(double)(uint64_t)0x8000000000000000LL) || !isfinite(d))
|
||||
tmp = 0x8000000000000000LL;
|
||||
else
|
||||
tmp = ceil(d);
|
||||
@@ -147,7 +149,7 @@ int64_t arm_fist64_2(double d)
|
||||
int64_t arm_fist64_3(double d)
|
||||
{
|
||||
int64_t tmp;
|
||||
if(isgreater(d, (double)(int64_t)0x7fffffffffffffffLL) || isless(d, (double)(int64_t)0x8000000000000000LL) || !isfinite(d))
|
||||
if(isgreater(d, (double)(int64_t)0x7fffffffffffffffLL) || isless(d, -(double)(uint64_t)0x8000000000000000LL) || !isfinite(d))
|
||||
tmp = 0x8000000000000000LL;
|
||||
else
|
||||
tmp = trunc(d);
|
||||
@@ -170,9 +172,22 @@ void arm_fld(x86emu_t* emu, uint8_t* ed)
|
||||
|
||||
void arm_ud(x86emu_t* emu)
|
||||
{
|
||||
emu->test.test = 0;
|
||||
emit_signal(emu, SIGILL, (void*)R_EIP, 0);
|
||||
}
|
||||
|
||||
void arm_priv(x86emu_t* emu)
|
||||
{
|
||||
emu->test.test = 0;
|
||||
emit_signal(emu, SIGSEGV, (void*)R_EIP, 0);
|
||||
}
|
||||
|
||||
void arm_singlestep(x86emu_t* emu)
|
||||
{
|
||||
emu->test.test = 0;
|
||||
emit_signal(emu, SIGTRAP, (void*)R_EIP, 1);
|
||||
}
|
||||
|
||||
void arm_fsave(x86emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_savenv(emu, (char*)ed, 0);
|
||||
@@ -208,6 +223,10 @@ void arm_fprem1(x86emu_t* emu)
|
||||
emu->sw.f.F87_C0 = ((tmp64s>>2)&1);
|
||||
}
|
||||
|
||||
void arm_clflush(x86emu_t* emu, void* p)
|
||||
{
|
||||
cleanDBFromAddressRange((uintptr_t)p, 8, 0);
|
||||
}
|
||||
|
||||
// Get a FPU single scratch reg
|
||||
int fpu_get_scratch_single(dynarec_arm_t* dyn)
|
||||
@@ -608,6 +627,7 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
case NEON_CACHE_XMMW:
|
||||
cache->ssecache[cache->neoncache[i].n].reg = i+FPUFIRST;
|
||||
cache->ssecache[cache->neoncache[i].n].write = (cache->neoncache[i].t==NEON_CACHE_XMMW)?1:0;
|
||||
cache->neoncache[i] = cache->neoncache[i+1];
|
||||
++cache->fpu_reg;
|
||||
++i; // next next
|
||||
break;
|
||||
@@ -702,13 +722,13 @@ int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int
|
||||
#define PK(a) *(uint8_t*)(addr+a)
|
||||
#define PK32(a) *(uint32_t*)(addr+a)
|
||||
|
||||
if(!addr)
|
||||
if(!addr || !getProtection(addr))
|
||||
return 0;
|
||||
if(PK(0)==0xff && PK(1)==0x25) { // absolute jump, maybe the GOT
|
||||
uintptr_t a1 = (PK32(2)); // need to add a check to see if the address is from the GOT !
|
||||
addr = (uintptr_t)getAlternate(*(void**)a1);
|
||||
}
|
||||
if(addr<0x10000) // too low, that is suspicious
|
||||
if(addr<0x10000 || !getProtection(addr)) // 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) {
|
||||
@@ -737,24 +757,6 @@ const char* getCacheName(int t, int n)
|
||||
return buff;
|
||||
}
|
||||
|
||||
// is inst clean for a son branch?
|
||||
int isInstClean(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
// check flags cache
|
||||
if(dyn->insts[ninst].f_entry.dfnone || dyn->insts[ninst].f_entry.pending)
|
||||
return 0;
|
||||
if(dyn->insts[ninst].x86.state_flags)
|
||||
return 0;
|
||||
// check neoncache
|
||||
neoncache_t* n = &dyn->insts[ninst].n;
|
||||
if(n->news || n->stack || n->stack_next)
|
||||
return 0;
|
||||
for(int i=0; i<24; ++i)
|
||||
if(n->neoncache[i].v)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int flagsCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
int jmp = dyn->insts[ninst].x86.jmp_insts;
|
||||
if(jmp<0)
|
||||
@@ -795,4 +797,58 @@ int CacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
if (fpuCacheNeedsTransform(dyn, ninst)) ret|=1;
|
||||
if (flagsCacheNeedsTransform(dyn, ninst)) ret|=2;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
void inst_name_pass3(dynarec_arm_t* dyn, int ninst, const char* name)
|
||||
{
|
||||
if(box86_dynarec_dump) {
|
||||
printf_x86_instruction(my_context->dec, &dyn->insts[ninst].x86, name);
|
||||
dynarec_log(LOG_NONE, "%s%p: %d emited opcodes, inst=%d, barrier=%d state=%d/%d(%d), %s=%X/%X, use=%X, need=%X/%X sm=%d/%d",
|
||||
(box86_dynarec_dump>1)?"\e[32m":"",
|
||||
(void*)(dyn->arm_start+dyn->insts[ninst].address),
|
||||
dyn->insts[ninst].size/4,
|
||||
ninst,
|
||||
dyn->insts[ninst].x86.barrier,
|
||||
dyn->insts[ninst].x86.state_flags,
|
||||
dyn->f.pending,
|
||||
dyn->f.dfnone,
|
||||
dyn->insts[ninst].x86.may_set?"may":"set",
|
||||
dyn->insts[ninst].x86.set_flags,
|
||||
dyn->insts[ninst].x86.gen_flags,
|
||||
dyn->insts[ninst].x86.use_flags,
|
||||
dyn->insts[ninst].x86.need_before,
|
||||
dyn->insts[ninst].x86.need_after,
|
||||
dyn->smread, dyn->smwrite);
|
||||
if(dyn->insts[ninst].pred_sz) {
|
||||
dynarec_log(LOG_NONE, ", pred=");
|
||||
for(int ii=0; ii<dyn->insts[ninst].pred_sz; ++ii)
|
||||
dynarec_log(LOG_NONE, "%s%d", ii?"/":"", dyn->insts[ninst].pred[ii]);
|
||||
}
|
||||
if(dyn->insts[ninst].x86.jmp && dyn->insts[ninst].x86.jmp_insts>=0)
|
||||
dynarec_log(LOG_NONE, ", jmp=%d", dyn->insts[ninst].x86.jmp_insts);
|
||||
if(dyn->insts[ninst].x86.jmp && dyn->insts[ninst].x86.jmp_insts==-1)
|
||||
dynarec_log(LOG_NONE, ", jmp=out");
|
||||
for(int ii=0; ii<24; ++ii) {
|
||||
switch(dyn->insts[ninst].n.neoncache[ii].t) {
|
||||
case NEON_CACHE_ST_D: dynarec_log(LOG_NONE, " D%d:%s", ii+8, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_ST_F: dynarec_log(LOG_NONE, " S%d:%s", (ii+8)*2, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_MM: dynarec_log(LOG_NONE, " D%d:%s", ii+8, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_XMMW: dynarec_log(LOG_NONE, " Q%d:%s", (ii+8)/2, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); ++ii; break;
|
||||
case NEON_CACHE_XMMR: dynarec_log(LOG_NONE, " Q%d:%s", (ii+8)/2, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); ++ii; break;
|
||||
case NEON_CACHE_SCR: dynarec_log(LOG_NONE, " D%d:%s", ii+8, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_NONE:
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if(dyn->n.stack || dyn->insts[ninst].n.stack_next || dyn->insts[ninst].n.x87stack)
|
||||
dynarec_log(LOG_NONE, " X87:%d/%d(+%d/-%d)%d", dyn->n.stack, dyn->insts[ninst].n.stack_next, dyn->insts[ninst].n.stack_push, dyn->insts[ninst].n.stack_pop, dyn->insts[ninst].n.x87stack);
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2)
|
||||
dynarec_log(LOG_NONE, " %s:%d/%d", dyn->insts[ninst].n.swapped?"SWP":"CMB", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2);
|
||||
dynarec_log(LOG_NONE, "%s\n", (box86_dynarec_dump>1)?"\e[m":"");
|
||||
}
|
||||
}
|
||||
|
||||
void print_opcode(dynarec_arm_t* dyn, int ninst, uint32_t opcode)
|
||||
{
|
||||
dynarec_log(LOG_NONE, "\t%08x\t%s\n", opcode, arm_print(opcode));
|
||||
}
|
||||
@@ -23,12 +23,16 @@ void arm_fsave(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_frstor(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fprem1(x86emu_t* emu);
|
||||
|
||||
void arm_clflush(x86emu_t* emu, void* p);
|
||||
|
||||
int64_t arm_fist64_0(double d);
|
||||
int64_t arm_fist64_1(double d);
|
||||
int64_t arm_fist64_2(double d);
|
||||
int64_t arm_fist64_3(double d);
|
||||
|
||||
void arm_ud(x86emu_t* emu);
|
||||
void arm_priv(x86emu_t* emu);
|
||||
void arm_singlestep(x86emu_t* emu);
|
||||
|
||||
#define FPUFIRST 8
|
||||
|
||||
@@ -71,9 +75,6 @@ int CacheNeedsTransform(dynarec_arm_t* dyn, int i1);
|
||||
// Undo the changes of a neoncache to get the status before the instruction
|
||||
void neoncacheUnwind(neoncache_t* cache);
|
||||
|
||||
// is inst clean for a son branch?
|
||||
int isInstClean(dynarec_arm_t* dyn, int ninst);
|
||||
|
||||
// predecessor access
|
||||
int isPred(dynarec_arm_t* dyn, int ninst, int pred);
|
||||
int getNominalPred(dynarec_arm_t* dyn, int ninst);
|
||||
@@ -88,4 +89,7 @@ int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int
|
||||
|
||||
const char* getCacheName(int t, int n);
|
||||
|
||||
void inst_name_pass3(dynarec_arm_t* dyn, int ninst, const char* name);
|
||||
void print_opcode(dynarec_arm_t* dyn, int ninst, uint32_t opcode);
|
||||
|
||||
#endif //__DYNAREC_ARM_FUNCTIONS_H__
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
@@ -176,8 +177,8 @@ uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
uint32_t m = nextop&0xC7;
|
||||
uint32_t n = (m>>6)&3;
|
||||
int32_t offset = 0;
|
||||
if(!n && m==6) {
|
||||
offset = F16;
|
||||
if(!n && (m&7)==6) {
|
||||
offset = F16S;
|
||||
MOVW(ret, offset);
|
||||
} else {
|
||||
switch(n) {
|
||||
@@ -185,7 +186,7 @@ uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
case 1: offset = F8S; break;
|
||||
case 2: offset = F16S; break;
|
||||
}
|
||||
if(offset && (abs(offset)>absmax || (offset&mask))) {
|
||||
if(offset && (abs(offset)<=absmax && !(offset&mask))) {
|
||||
*fixaddress = offset;
|
||||
offset = 0;
|
||||
}
|
||||
@@ -861,10 +862,29 @@ void x87_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int
|
||||
MESSAGE(LOG_DUMP, "\t---Purge x87 Cache and Synch Stackcount\n");
|
||||
}
|
||||
|
||||
#ifdef HAVE_TRACE
|
||||
static void x87_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
x87_stackcount(dyn, ninst, s1);
|
||||
// Synch top & stack counter
|
||||
int a = dyn->n.x87stack;
|
||||
if(a) {
|
||||
// Add x87stack to emu fpu_stack
|
||||
LDR_IMM9(s2, xEmu, offsetof(x86emu_t, fpu_stack));
|
||||
if(a>0) {
|
||||
ADD_IMM8(s2, s2, a);
|
||||
} else {
|
||||
SUB_IMM8(s2, s2, -a);
|
||||
}
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, fpu_stack));
|
||||
// Sub x87stack to top, with and 7
|
||||
LDR_IMM9(s2, xEmu, offsetof(x86emu_t, top));
|
||||
if(a>0) {
|
||||
SUB_IMM8(s2, s2, a);
|
||||
} else {
|
||||
ADD_IMM8(s2, s2, -a);
|
||||
}
|
||||
AND_IMM8(s2, s2, 7);
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, top));
|
||||
}
|
||||
int ret = 0;
|
||||
for (int i=0; (i<8) && (!ret); ++i)
|
||||
if(dyn->n.x87cache[i] != -1)
|
||||
@@ -872,13 +892,20 @@ static void x87_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
if(!ret) // nothing to do
|
||||
return;
|
||||
// Get top
|
||||
LDR_IMM9(s2, xEmu, offsetof(x86emu_t, top));
|
||||
if(!a) {
|
||||
// already there
|
||||
LDR_IMM9(s2, xEmu, offsetof(x86emu_t, top));
|
||||
}
|
||||
// loop all cache entries
|
||||
for (int i=0; i<8; ++i)
|
||||
if(dyn->n.x87cache[i]!=-1) {
|
||||
ADD_IMM8(s3, s2, dyn->n.x87cache[i]);
|
||||
AND_IMM8(s3, s3, 7); // (emu->top + i)&7
|
||||
ADD_REG_LSL_IMM5(s3, xEmu, s3, 3); // fpu[(emu->top+i)&7] lsl 3 because fpu are double, so 8 bytes
|
||||
if(dyn->n.x87cache[i]) {
|
||||
ADD_IMM8(s3, s2, dyn->n.x87cache[i]);
|
||||
AND_IMM8(s3, s3, 7); // (emu->top + i)&7
|
||||
ADD_REG_LSL_IMM5(s3, xEmu, s3, 3); // fpu[(emu->top+i)&7] lsl 3 because fpu are double, so 8 bytes
|
||||
} else {
|
||||
ADD_REG_LSL_IMM5(s3, xEmu, s2, 3);
|
||||
}
|
||||
if(ST_IS_F(dyn->n.x87cache[i])) {
|
||||
VCVT_F64_F32(0, dyn->n.x87reg[i]*2); // use D0 as scratch...
|
||||
VSTR_64(0, s3, offsetof(x86emu_t, x87));
|
||||
@@ -887,7 +914,31 @@ static void x87_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void x87_unreflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
// go back with the top & stack counter
|
||||
int a = dyn->n.x87stack;
|
||||
if(a) {
|
||||
// Add x87stack to emu fpu_stack
|
||||
LDR_IMM9(s1, xEmu, offsetof(x86emu_t, fpu_stack));
|
||||
if(a>0) {
|
||||
SUB_IMM8(s1, s1, a);
|
||||
} else {
|
||||
ADD_IMM8(s1, s1, -a);
|
||||
}
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, fpu_stack));
|
||||
// Sub x87stack to top, with and 7
|
||||
LDR_IMM9(s1, xEmu, offsetof(x86emu_t, top));
|
||||
if(a>0) {
|
||||
ADD_IMM8(s1, s1, a);
|
||||
} else {
|
||||
SUB_IMM8(s1, s1, -a);
|
||||
}
|
||||
AND_IMM8(s1, s1, 7);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, top));
|
||||
}
|
||||
}
|
||||
|
||||
int x87_get_current_cache(dynarec_arm_t* dyn, int ninst, int st, int t)
|
||||
{
|
||||
@@ -1223,7 +1274,6 @@ void mmx_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1)
|
||||
MESSAGE(LOG_DUMP, "\t------ Purge MMX Cache\n");
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_TRACE
|
||||
static void mmx_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
int old = -1;
|
||||
@@ -1241,7 +1291,6 @@ static void mmx_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
VST1_32_W(dyn->n.mmxcache[i], s1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// SSE / SSE2 helpers
|
||||
@@ -1321,7 +1370,6 @@ static void sse_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1)
|
||||
MESSAGE(LOG_DUMP, "\t------ Purge SSE Cache\n");
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_TRACE
|
||||
static void sse_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
int old = -1;
|
||||
@@ -1345,7 +1393,6 @@ static void sse_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
VST1Q_32_W(dyn->n.ssecache[i].reg, s1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void fpu_pushcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
@@ -1446,8 +1493,10 @@ static void swapCache(dynarec_arm_t* dyn, int ninst, int i, int j, neoncache_t *
|
||||
quad =1;
|
||||
if(cache->neoncache[j].t==NEON_CACHE_XMMR || cache->neoncache[j].t==NEON_CACHE_XMMW)
|
||||
quad =1;
|
||||
if(quad) // if quad, we need to swap the whole quad!
|
||||
if(quad) { // if quad, we need to swap the whole quad!
|
||||
i&=~1;
|
||||
j&=~1;
|
||||
}
|
||||
if(!cache->neoncache[i].v && ((quad && !cache->neoncache[i+1].v) || !quad)) {
|
||||
// a mov is enough, no need to swap
|
||||
MESSAGE(LOG_DUMP, "\t - Moving %d <- %d\n", i, j);
|
||||
@@ -1717,7 +1766,7 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
stack_cnt = cache_i2.stack;
|
||||
}
|
||||
neoncache_t cache = dyn->n;
|
||||
// sanitize XMM regs alocation
|
||||
// sanitize XMM regs alocation, cache_i2 has been sanitized in neoncacheUnwind already
|
||||
for(int i=0; i<24; i+=2) {
|
||||
if(cache.neoncache[i].t == NEON_CACHE_XMMR || cache.neoncache[i].t == NEON_CACHE_XMMW)
|
||||
cache.neoncache[i+1] = cache.neoncache[i];
|
||||
@@ -1825,11 +1874,11 @@ static void flagsCacheTransform(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
if(dyn->f.pending!=SF_PENDING) {
|
||||
LDR_IMM9(s1, xEmu, offsetof(x86emu_t, df));
|
||||
TSTS_REG_LSL_IMM5(s1, s1, 0);
|
||||
j32 = (GETMARK3)-(dyn->arm_size+8);
|
||||
j32 = (GETMARKF2)-(dyn->arm_size+8);
|
||||
Bcond(cEQ, j32);
|
||||
}
|
||||
CALL_(UpdateFlags, -1, 0);
|
||||
MARK3;
|
||||
MARKF2;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1841,16 +1890,17 @@ void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd, int s1, int s2,
|
||||
flagsCacheTransform(dyn, ninst, s1);
|
||||
}
|
||||
|
||||
#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);
|
||||
mmx_reflectcache(dyn, ninst, s1);
|
||||
sse_reflectcache(dyn, ninst, s1);
|
||||
}
|
||||
|
||||
void fpu_unreflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
x87_unreflectcache(dyn, ninst, s1, s2, s3);
|
||||
}
|
||||
#endif
|
||||
|
||||
void fpu_reset(dynarec_arm_t* dyn)
|
||||
{
|
||||
@@ -1887,3 +1937,64 @@ void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
|
||||
void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int reset_n)
|
||||
{
|
||||
MESSAGE(LOG_DEBUG, "Reset Caches with %d\n",reset_n);
|
||||
#if STEP > 1
|
||||
// for STEP 2 & 3, just need to refrest with current, and undo the changes (push & swap)
|
||||
dyn->n = dyn->insts[ninst].n;
|
||||
neoncacheUnwind(&dyn->n);
|
||||
#ifdef HAVE_TRACE
|
||||
if(box86_dynarec_dump)
|
||||
if(memcmp(&dyn->n, &dyn->insts[reset_n].n, sizeof(neon_cache_t))) {
|
||||
MESSAGE(LOG_DEBUG, "Warning, difference in neoncache: reset=");
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->insts[reset_n].n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->insts[reset_n].n.neoncache[i].t, dyn->insts[reset_n].n.neoncache[i].n));
|
||||
if(dyn->insts[reset_n].n.combined1 || dyn->insts[reset_n].n.combined2)
|
||||
MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->insts[reset_n].n.swapped?"SWP":"CMB", dyn->insts[reset_n].n.combined1, dyn->insts[reset_n].n.combined2);
|
||||
if(dyn->insts[reset_n].n.stack_push || dyn->insts[reset_n].n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->insts[reset_n].n.stack_push, -dyn->insts[reset_n].n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, " ==> ");
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->insts[ninst].n.neoncache[i].t, dyn->insts[ninst].n.neoncache[i].n));
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2)
|
||||
MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->insts[ninst].n.swapped?"SWP":"CMB", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2);
|
||||
if(dyn->insts[ninst].n.stack_push || dyn->insts[ninst].n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->insts[ninst].n.stack_push, -dyn->insts[ninst].n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, " -> ");
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->n.neoncache[i].t, dyn->n.neoncache[i].n));
|
||||
if(dyn->n.combined1 || dyn->n.combined2)
|
||||
MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->n.swapped?"SWP":"CMB", dyn->n.combined1, dyn->n.combined2);
|
||||
if(dyn->n.stack_push || dyn->n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->n.stack_push, -dyn->n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, "\n");
|
||||
}
|
||||
#endif //HAVE_TRACE
|
||||
#else
|
||||
dyn->n = dyn->insts[reset_n].n;
|
||||
#endif
|
||||
}
|
||||
|
||||
// propagate ST stack state, especial stack pop that are deferred
|
||||
void fpu_propagate_stack(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
if(dyn->n.stack_pop) {
|
||||
for(int j=0; j<24; ++j)
|
||||
if((dyn->n.neoncache[j].t == NEON_CACHE_ST_D || dyn->n.neoncache[j].t == NEON_CACHE_ST_F)) {
|
||||
if(dyn->n.neoncache[j].n<dyn->n.stack_pop)
|
||||
dyn->n.neoncache[j].v = 0;
|
||||
else
|
||||
dyn->n.neoncache[j].n-=dyn->n.stack_pop;
|
||||
}
|
||||
dyn->n.stack_pop = 0;
|
||||
}
|
||||
dyn->n.stack = dyn->n.stack_next;
|
||||
dyn->n.news = 0;
|
||||
dyn->n.stack_push = 0;
|
||||
dyn->n.swapped = 0;
|
||||
}
|
||||
@@ -260,17 +260,19 @@
|
||||
// CALL_1RD will use S as scratch. Return value in D0, 1 ARG in R
|
||||
#define CALL_1RD(F, R, S, M) call_rd(dyn, ninst, F, R, S, M, 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 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 MARKF2 if(dyn->insts) {dyn->insts[ninst].markf2 = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARKF2 ((dyn->insts)?dyn->insts[ninst].markf2:(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)
|
||||
@@ -547,12 +549,13 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
|
||||
#define fpu_pushcache STEPNAME(fpu_pushcache)
|
||||
#define fpu_popcache STEPNAME(fpu_popcache)
|
||||
#define fpu_reset STEPNAME(fpu_reset)
|
||||
#define fpu_reset_cache STEPNAME(fpu_reset_cache)
|
||||
#define fpu_propagate_stack STEPNAME(fpu_propagate_stack)
|
||||
#define fpu_purgecache STEPNAME(fpu_purgecache)
|
||||
#define x87_purgecache STEPNAME(x87_purgecache)
|
||||
#define mmx_purgecache STEPNAME(mmx_purgecache)
|
||||
#ifdef HAVE_TRACE
|
||||
#define fpu_reflectcache STEPNAME(fpu_reflectcache)
|
||||
#endif
|
||||
#define fpu_unreflectcache STEPNAME(fpu_unreflectcache)
|
||||
|
||||
// get the single reg that from the double "reg" (so Dx[idx])
|
||||
#define fpu_get_single_reg STEPNAME(fpu_get_single_reg)
|
||||
@@ -741,13 +744,16 @@ int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a);
|
||||
// common coproc helpers
|
||||
// reset the cache
|
||||
void fpu_reset(dynarec_arm_t* dyn);
|
||||
// reset the cache with n
|
||||
void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int reset_n);
|
||||
// propagate stack state
|
||||
void fpu_propagate_stack(dynarec_arm_t* dyn, int ninst);
|
||||
// purge the FPU cache (needs 3 scratch registers) next=1 if for a conditionnal branch jumping out of block (no tracking updated)
|
||||
void fpu_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int s3);
|
||||
void x87_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int s3);
|
||||
void mmx_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1);
|
||||
#ifdef HAVE_TRACE
|
||||
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
#endif
|
||||
void fpu_unreflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
void fpu_pushcache(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
void fpu_popcache(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
|
||||
@@ -794,4 +800,21 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
#define MAYUSE(A)
|
||||
#endif
|
||||
|
||||
#define NOTEST(s1) \
|
||||
if(box86_dynarec_test) { \
|
||||
MOVW(s1, 0); \
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, test.test)); \
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, test.clean)); \
|
||||
}
|
||||
#define SKIPTEST(s1) \
|
||||
if(box86_dynarec_test) { \
|
||||
MOVW(s1, 0); \
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, test.clean)); \
|
||||
}
|
||||
#define GOTEST(s1, s2) \
|
||||
if(box86_dynarec_test) { \
|
||||
MOVW(s2, 1); \
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, test.test)); \
|
||||
}
|
||||
|
||||
#endif //__DYNAREC_ARM_HELPER_H__
|
||||
@@ -0,0 +1,12 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "arm_emitter.h"
|
||||
|
||||
#define EMIT(A) *block = (A); ++block
|
||||
void CreateJmpNext(void* addr, void* next)
|
||||
{
|
||||
uint32_t* block = (uint32_t*)addr;
|
||||
LDR_literal(x2, ((intptr_t)next - (intptr_t)addr)-8);
|
||||
BX(x2);
|
||||
}
|
||||
@@ -36,7 +36,6 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
uintptr_t init_addr = addr;
|
||||
MAYUSE(init_addr);
|
||||
int need_epilog = 1;
|
||||
dyn->sons_size = 0;
|
||||
// Clean up (because there are multiple passes)
|
||||
dyn->f.pending = 0;
|
||||
dyn->f.dfnone = 0;
|
||||
@@ -57,44 +56,7 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
dyn->f.pending = 0;
|
||||
fpu_reset(dyn);
|
||||
} else {
|
||||
MESSAGE(LOG_DEBUG, "Reset Caches with %d\n",reset_n);
|
||||
#if STEP > 1
|
||||
// for STEP 2 & 3, just need to refrest with current, and undo the changes (push & swap)
|
||||
dyn->n = dyn->insts[ninst].n;
|
||||
neoncacheUnwind(&dyn->n);
|
||||
#ifdef HAVE_TRACE
|
||||
if(box86_dynarec_dump)
|
||||
if(memcmp(&dyn->n, &dyn->insts[reset_n].n, sizeof(neon_cache_t))) {
|
||||
MESSAGE(LOG_DEBUG, "Warning, difference in neoncache: reset=");
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->insts[reset_n].n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->insts[reset_n].n.neoncache[i].t, dyn->insts[reset_n].n.neoncache[i].n));
|
||||
if(dyn->insts[reset_n].n.combined1 || dyn->insts[reset_n].n.combined2)
|
||||
MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->insts[reset_n].n.swapped?"SWP":"CMB", dyn->insts[reset_n].n.combined1, dyn->insts[reset_n].n.combined2);
|
||||
if(dyn->insts[reset_n].n.stack_push || dyn->insts[reset_n].n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->insts[reset_n].n.stack_push, -dyn->insts[reset_n].n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, " ==> ");
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->insts[ninst].n.neoncache[i].t, dyn->insts[ninst].n.neoncache[i].n));
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2)
|
||||
MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->insts[ninst].n.swapped?"SWP":"CMB", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2);
|
||||
if(dyn->insts[ninst].n.stack_push || dyn->insts[ninst].n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->insts[ninst].n.stack_push, -dyn->insts[ninst].n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, " -> ");
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->n.neoncache[i].v)
|
||||
MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->n.neoncache[i].t, dyn->n.neoncache[i].n));
|
||||
if(dyn->n.combined1 || dyn->n.combined2)
|
||||
MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->n.swapped?"SWP":"CMB", dyn->n.combined1, dyn->n.combined2);
|
||||
if(dyn->n.stack_push || dyn->n.stack_pop)
|
||||
MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->n.stack_push, -dyn->n.stack_pop);
|
||||
MESSAGE(LOG_DEBUG, "\n");
|
||||
}
|
||||
#endif //HAVE_TRACE
|
||||
#else
|
||||
dyn->n = dyn->insts[reset_n].n;
|
||||
#endif
|
||||
fpu_reset_cache(dyn, ninst, reset_n);
|
||||
dyn->f = dyn->insts[reset_n].f_exit;
|
||||
if(dyn->insts[ninst].x86.barrier&BARRIER_FLOAT) {
|
||||
MESSAGE(LOG_DEBUG, "Apply Barrier Float\n");
|
||||
@@ -108,29 +70,29 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
}
|
||||
reset_n = -1;
|
||||
}
|
||||
// propagate ST stack state, especial stack pop that are defered
|
||||
if(dyn->n.stack_pop) {
|
||||
for(int j=0; j<24; ++j)
|
||||
if((dyn->n.neoncache[j].t == NEON_CACHE_ST_D || dyn->n.neoncache[j].t == NEON_CACHE_ST_F)) {
|
||||
if(dyn->n.neoncache[j].n<dyn->n.stack_pop)
|
||||
dyn->n.neoncache[j].v = 0;
|
||||
else
|
||||
dyn->n.neoncache[j].n-=dyn->n.stack_pop;
|
||||
}
|
||||
dyn->n.stack_pop = 0;
|
||||
}
|
||||
dyn->n.stack = dyn->n.stack_next;
|
||||
dyn->n.news = 0;
|
||||
dyn->n.stack_push = 0;
|
||||
dyn->n.swapped = 0;
|
||||
fpu_propagate_stack(dyn, ninst);
|
||||
NEW_INST;
|
||||
if(!ninst) {
|
||||
GOTEST(x1, x2);
|
||||
}
|
||||
if(dyn->insts[ninst].pred_sz>1) {SMSTART();}
|
||||
fpu_reset_scratch(dyn);
|
||||
if((dyn->insts[ninst].x86.need_before&~X_PEND) && !dyn->insts[ninst].pred_sz) {
|
||||
READFLAGS(dyn->insts[ninst].x86.need_before&~X_PEND);
|
||||
}
|
||||
if(box86_dynarec_test) {
|
||||
MESSAGE(LOG_DUMP, "TEST INIT ----\n");
|
||||
fpu_reflectcache(dyn, ninst, x1, x2, x3);
|
||||
MOV32(x1, ip);
|
||||
STM(xEmu, (1<<xEAX)|(1<<xEBX)|(1<<xECX)|(1<<xEDX)|(1<<xESI)|(1<<xEDI)|(1<<xESP)|(1<<xEBP));
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, ip));
|
||||
MOVW(x2, 1);
|
||||
CALL(x86test_init, -1, 0);
|
||||
fpu_unreflectcache(dyn, ninst, x1, x2, x3);
|
||||
MESSAGE(LOG_DUMP, "----------\n");
|
||||
}
|
||||
#ifdef HAVE_TRACE
|
||||
if(my_context->dec && box86_dynarec_trace) {
|
||||
else if(my_context->dec && box86_dynarec_trace) {
|
||||
if((trace_end == 0)
|
||||
|| ((ip >= trace_start) && (ip < trace_end))) {
|
||||
MESSAGE(LOG_DUMP, "TRACE ----\n");
|
||||
@@ -140,6 +102,7 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, ip));
|
||||
MOVW(x2, 1);
|
||||
CALL(PrintTrace, -1, 0);
|
||||
fpu_unreflectcache(dyn, ninst, x1, x2, x3);
|
||||
MESSAGE(LOG_DUMP, "----------\n");
|
||||
}
|
||||
}
|
||||
@@ -162,13 +125,26 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
dyn->f.dfnone = 0;
|
||||
}
|
||||
}
|
||||
#ifndef PROT_READ
|
||||
#define PROT_READ 1
|
||||
#endif
|
||||
#if STEP != 0
|
||||
if(!ok && !need_epilog && (addr < (dyn->start+dyn->isize))) {
|
||||
ok = 1;
|
||||
// we use the 1st predecessor here
|
||||
int ii = ninst+1;
|
||||
while(ii<dyn->size && !dyn->insts[ii].pred_sz)
|
||||
++ii;
|
||||
if(ii<dyn->size && !dyn->insts[ii].pred_sz) {
|
||||
while(ii<dyn->size && (!dyn->insts[ii].pred_sz || (dyn->insts[ii].pred_sz==1 && dyn->insts[ii].pred[0]==ii-1))) {
|
||||
// may need to skip opcodes to advance
|
||||
++ninst;
|
||||
NEW_INST;
|
||||
MESSAGE(LOG_DEBUG, "Skipping unused opcode\n");
|
||||
INST_NAME("Skipped opcode");
|
||||
INST_EPILOG;
|
||||
addr += dyn->insts[ii].x86.size;
|
||||
++ii;
|
||||
}
|
||||
}
|
||||
if((dyn->insts[ii].x86.barrier&BARRIER_FULL)==BARRIER_FULL)
|
||||
reset_n = -2; // hack to say Barrier!
|
||||
else {
|
||||
@@ -180,20 +156,18 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
}
|
||||
}
|
||||
#else
|
||||
#ifndef PROT_READ
|
||||
#define PROT_READ 1
|
||||
#endif
|
||||
if(dyn->forward) {
|
||||
if(dyn->forward_to == addr) {
|
||||
if(dyn->forward_to == addr && !need_epilog) {
|
||||
// we made it!
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Forward extend block %p -> %p\n", (void*)dyn->forward, (void*)dyn->forward_to);
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Forward extend block for %d bytes %p -> %p\n", dyn->forward_to-dyn->forward, (void*)dyn->forward, (void*)dyn->forward_to);
|
||||
dyn->forward = 0;
|
||||
dyn->forward_to = 0;
|
||||
dyn->forward_size = 0;
|
||||
dyn->forward_ninst = 0;
|
||||
ok = 1; // in case it was 0
|
||||
} else if ((dyn->forward_to < addr) || !ok) {
|
||||
// something when wrong! rollback
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Could not forward extend block %p -> %p\n", (void*)dyn->forward, (void*)dyn->forward_to);
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Could not forward extend block for %d bytes %p -> %p\n", dyn->forward_to-dyn->forward, (void*)dyn->forward, (void*)dyn->forward_to);
|
||||
ok = 0;
|
||||
dyn->size = dyn->forward_size;
|
||||
ninst = dyn->forward_ninst;
|
||||
@@ -204,12 +178,12 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
dyn->forward_ninst = 0;
|
||||
}
|
||||
// else just continue
|
||||
} else if(!ok && !need_epilog && box86_dynarec_bigblock && (getProtection(addr+3)&PROT_READ))
|
||||
} else if(!ok && !need_epilog && box86_dynarec_bigblock && (getProtection(addr+3)&~PROT_READ))
|
||||
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))
|
||||
/*&& box86_dynarec_bigblock*/))
|
||||
/*||(((next-addr)<30) && is_instructions(dyn, addr, next-addr))*/ ))
|
||||
{
|
||||
ok = 1;
|
||||
// need to find back that instruction to copy the caches, as previous version cannot be used anymore
|
||||
@@ -220,30 +194,73 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
ii=ninst;
|
||||
}
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Extend block %p, %p -> %p (ninst=%d, jump from %d)\n", dyn, (void*)addr, (void*)next, ninst, reset_n);
|
||||
} else if(next && (next-addr<box86_dynarec_forward)
|
||||
&& (getProtection(next)&PROT_READ)/*box86_dynarec_bigblock>=forwardblock*/) {
|
||||
dyn->forward = addr;
|
||||
dyn->forward_to = next;
|
||||
dyn->forward_size = dyn->size;
|
||||
dyn->forward_ninst = ninst;
|
||||
reset_n = -2;
|
||||
ok = 1;
|
||||
} else if(next && (next-addr)<box86_dynarec_forward && (getProtection(next)&PROT_READ)/*box86_dynarec_bigblock>=stopblock*/) {
|
||||
if(!((box86_dynarec_bigblock<stopblock) && !isJumpTableDefault((void*)next))) {
|
||||
if(dyn->forward) {
|
||||
if(next<dyn->forward_to)
|
||||
dyn->forward_to = next;
|
||||
reset_n = -2;
|
||||
ok = 1;
|
||||
} else {
|
||||
dyn->forward = addr;
|
||||
dyn->forward_to = next;
|
||||
dyn->forward_size = dyn->size;
|
||||
dyn->forward_ninst = ninst;
|
||||
reset_n = -2;
|
||||
ok = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(ok<0) {ok = 0; need_epilog=1;}
|
||||
if(ok<0) {
|
||||
ok = 0; need_epilog=1;
|
||||
#if STEP == 0
|
||||
if(ninst) {
|
||||
--ninst;
|
||||
if(!dyn->insts[ninst].x86.barrier) {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
}
|
||||
dyn->insts[ninst].x86.need_after |= X_PEND;
|
||||
++ninst;
|
||||
}
|
||||
if(dyn->forward) {
|
||||
// stopping too soon
|
||||
dyn->size = dyn->forward_size;
|
||||
ninst = dyn->forward_ninst+1;
|
||||
addr = dyn->forward;
|
||||
dyn->forward = 0;
|
||||
dyn->forward_to = 0;
|
||||
dyn->forward_size = 0;
|
||||
dyn->forward_ninst = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
++ninst;
|
||||
#if STEP == 0
|
||||
if(ok && (((box86_dynarec_bigblock<stopblock) && !isJumpTableDefault((void*)addr))
|
||||
|| (addr>=box86_nodynarec_start && addr<box86_nodynarec_end)
|
||||
/*|| (dyn->size >= 2000)*/)) // is this still needed? maybe it should be a parameter?
|
||||
|| (addr>=box86_nodynarec_start && addr<box86_nodynarec_end)))
|
||||
#else
|
||||
if(ok && (ninst==dyn->size))
|
||||
#endif
|
||||
{
|
||||
#if STEP == 0
|
||||
if(dyn->forward) {
|
||||
// stopping too soon
|
||||
dyn->size = dyn->forward_size;
|
||||
ninst = dyn->forward_ninst+1;
|
||||
addr = dyn->forward;
|
||||
dyn->forward = 0;
|
||||
dyn->forward_to = 0;
|
||||
dyn->forward_size = 0;
|
||||
dyn->forward_ninst = 0;
|
||||
}
|
||||
#endif
|
||||
int j32;
|
||||
MAYUSE(j32);
|
||||
MESSAGE(LOG_DEBUG, "Stopping block %p (%d / %d)\n",(void*)init_addr, ninst, dyn->size);
|
||||
MESSAGE(LOG_DEBUG, "Stopping block %p (%d / %d)\n",(void*)init_addr, ninst, dyn->size);
|
||||
if(!box86_dynarec_dump && addr>=box86_nodynarec_start && addr<box86_nodynarec_end)
|
||||
dynarec_log(LOG_INFO, "Stopping block in no-dynarec zone\n");
|
||||
--ninst;
|
||||
if(!dyn->insts[ninst].x86.barrier) {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
@@ -252,16 +269,18 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
dyn->insts[ninst].x86.need_after |= X_PEND;
|
||||
#endif
|
||||
++ninst;
|
||||
NOTEST(x3);
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
jump_to_next(dyn, addr, 0, ninst);
|
||||
ok=0; need_epilog=0;
|
||||
}
|
||||
}
|
||||
if(need_epilog) {
|
||||
NOTEST(x3);
|
||||
fpu_purgecache(dyn, ninst, 0, 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);
|
||||
MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d)\n", dyn->size);
|
||||
return addr;
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
dyn->isize = addr-sav_addr;\
|
||||
dyn->insts[ninst].x86.addr = addr;\
|
||||
if(ninst) dyn->insts[ninst-1].x86.size = dyn->insts[ninst].x86.addr - dyn->insts[ninst-1].x86.addr
|
||||
|
||||
#define MESSAGE(A, ...)
|
||||
#define MAYSETFLAGS() dyn->insts[ninst].x86.may_set = 1
|
||||
#define READFLAGS(A) \
|
||||
@@ -15,13 +16,13 @@
|
||||
dyn->f.pending=(B)&SF_SET_PENDING; \
|
||||
dyn->f.dfnone=((B)&SF_SET)?1:0;
|
||||
#define EMIT(A)
|
||||
#define JUMP(A, C) if((A)>addr) add_next(dyn, (uintptr_t)(A)); dyn->insts[ninst].x86.jmp = A; dyn->insts[ninst].x86.jmp_cond = C
|
||||
#define JUMP(A, C) add_next(dyn, (uintptr_t)A); dyn->insts[ninst].x86.jmp = A; dyn->insts[ninst].x86.jmp_cond = C
|
||||
#define BARRIER(A) if(A!=BARRIER_MAYBE) {fpu_purgecache(dyn, ninst, 0, x1, x2, x3); dyn->insts[ninst].x86.barrier = A;} else dyn->insts[ninst].barrier_maybe = 1
|
||||
#define BARRIER_NEXT(A) dyn->insts[ninst+1].x86.barrier = A
|
||||
#define NEW_INST \
|
||||
++dyn->size; \
|
||||
if(dyn->size+3>=dyn->cap) { \
|
||||
dyn->insts = (instruction_arm_t*)box_realloc(dyn->insts, sizeof(instruction_arm_t)*dyn->cap*2); \
|
||||
dyn->insts = (instruction_arm_t*)dynaRealloc(dyn->insts, sizeof(instruction_arm_t)*dyn->cap*2);\
|
||||
memset(&dyn->insts[dyn->cap], 0, sizeof(instruction_arm_t)*dyn->cap); \
|
||||
dyn->cap *= 2; \
|
||||
} \
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#define FINI
|
||||
#define MESSAGE(A, ...)
|
||||
#define EMIT(A)
|
||||
|
||||
#define NEW_INST \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
dyn->n.combined1 = dyn->n.combined2 = 0;\
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
#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 FINI \
|
||||
if(ninst) { \
|
||||
dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size); \
|
||||
dyn->insts_size += 1+((dyn->insts[ninst].x86.size>dyn->insts[ninst].size)?dyn->insts[ninst].x86.size:dyn->insts[ninst].size)/15; \
|
||||
}
|
||||
|
||||
#define MESSAGE(A, ...)
|
||||
#define EMIT(A) dyn->insts[ninst].size+=4; dyn->arm_size+=4
|
||||
#define EMIT(A) do{dyn->insts[ninst].size+=4; dyn->arm_size+=4;}while(0)
|
||||
#define NEW_INST \
|
||||
if(ninst) { \
|
||||
dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size); \
|
||||
if(ninst && isInstClean(dyn, ninst)) \
|
||||
++dyn->sons_size; \
|
||||
dyn->insts_size += 1+((dyn->insts[ninst-1].x86.size>dyn->insts[ninst-1].size)?dyn->insts[ninst-1].x86.size:dyn->insts[ninst-1].size)/15; \
|
||||
}
|
||||
#define INST_EPILOG dyn->insts[ninst].epilog = dyn->arm_size;
|
||||
#define INST_NAME(name)
|
||||
@@ -1,65 +1,20 @@
|
||||
#define INIT
|
||||
#define FINI
|
||||
#define EMIT(A) \
|
||||
if(box86_dynarec_dump) {dynarec_log(LOG_NONE, "\t%08x\t%s\n", (A), arm_print(A));} \
|
||||
*(uint32_t*)(dyn->block) = A; \
|
||||
dyn->block += 4; dyn->arm_size += 4;\
|
||||
dyn->insts[ninst].size2 += 4
|
||||
#define FINI \
|
||||
if(ninst) \
|
||||
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst].x86.size, dyn->insts[ninst].size/4); \
|
||||
addInst(dyn->instsize, &dyn->insts_size, 0, 0);
|
||||
#define EMIT(A) \
|
||||
do{ \
|
||||
if(box86_dynarec_dump) print_opcode(dyn, ninst, (uint32_t)(A)); \
|
||||
if((uintptr_t)dyn->block<(uintptr_t)dyn->next-sizeof(void*))\
|
||||
*(uint32_t*)(dyn->block) = (uint32_t)(A); \
|
||||
dyn->block += 4; dyn->arm_size += 4; \
|
||||
dyn->insts[ninst].size2 += 4; \
|
||||
}while(0)
|
||||
|
||||
#define MESSAGE(A, ...) if(box86_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__)
|
||||
#define NEW_INST \
|
||||
if(ninst && isInstClean(dyn, ninst)) { \
|
||||
dyn->sons_x86[dyn->sons_size] = (uintptr_t)ip; \
|
||||
dyn->sons_arm[dyn->sons_size] = dyn->block; \
|
||||
MESSAGE(LOG_DUMP, "----> potential Son here %p/%p\n", (void*)ip, dyn->block); \
|
||||
++dyn->sons_size; \
|
||||
}
|
||||
|
||||
if(ninst) \
|
||||
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst-1].x86.size, dyn->insts[ninst-1].size/4);
|
||||
#define INST_EPILOG
|
||||
#define INST_NAME(name) \
|
||||
if(box86_dynarec_dump) {\
|
||||
printf_x86_instruction(my_context->dec, &dyn->insts[ninst].x86, name); \
|
||||
dynarec_log(LOG_NONE, "%s%p: %d emited opcodes, inst=%d, barrier=%d state=%d/%d(%d), %s=%X/%X, use=%X, need=%X/%X sm=%d/%d", \
|
||||
(box86_dynarec_dump>1)?"\e[32m":"", \
|
||||
(void*)(dyn->arm_start+dyn->insts[ninst].address), \
|
||||
dyn->insts[ninst].size/4, \
|
||||
ninst, \
|
||||
dyn->insts[ninst].x86.barrier, \
|
||||
dyn->insts[ninst].x86.state_flags, \
|
||||
dyn->f.pending, \
|
||||
dyn->f.dfnone, \
|
||||
dyn->insts[ninst].x86.may_set?"may":"set", \
|
||||
dyn->insts[ninst].x86.set_flags, \
|
||||
dyn->insts[ninst].x86.gen_flags, \
|
||||
dyn->insts[ninst].x86.use_flags, \
|
||||
dyn->insts[ninst].x86.need_before, \
|
||||
dyn->insts[ninst].x86.need_after, \
|
||||
dyn->smread, dyn->smwrite); \
|
||||
if(dyn->insts[ninst].pred_sz) { \
|
||||
dynarec_log(LOG_NONE, ", pred="); \
|
||||
for(int ii=0; ii<dyn->insts[ninst].pred_sz; ++ii)\
|
||||
dynarec_log(LOG_NONE, "%s%d", ii?"/":"", dyn->insts[ninst].pred[ii]);\
|
||||
} \
|
||||
if(dyn->insts[ninst].x86.jmp && dyn->insts[ninst].x86.jmp_insts>=0)\
|
||||
dynarec_log(LOG_NONE, ", jmp=%d", dyn->insts[ninst].x86.jmp_insts);\
|
||||
if(dyn->insts[ninst].x86.jmp && dyn->insts[ninst].x86.jmp_insts==-1)\
|
||||
dynarec_log(LOG_NONE, ", jmp=out");\
|
||||
for(int ii=0; ii<24; ++ii) { \
|
||||
switch(dyn->insts[ninst].n.neoncache[ii].t) { \
|
||||
case NEON_CACHE_ST_D: dynarec_log(LOG_NONE, " D%d:%s", ii+8, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break; \
|
||||
case NEON_CACHE_ST_F: dynarec_log(LOG_NONE, " S%d:%s", (ii+8)*2, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break; \
|
||||
case NEON_CACHE_MM: dynarec_log(LOG_NONE, " D%d:%s", ii+8, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break; \
|
||||
case NEON_CACHE_XMMW: dynarec_log(LOG_NONE, " Q%d:%s", (ii+8)/2, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); ++ii; break; \
|
||||
case NEON_CACHE_XMMR: dynarec_log(LOG_NONE, " Q%d:%s", (ii+8)/2, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); ++ii; break; \
|
||||
case NEON_CACHE_SCR: dynarec_log(LOG_NONE, " D%d:%s", ii+8, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break; \
|
||||
case NEON_CACHE_NONE: \
|
||||
default: break; \
|
||||
} \
|
||||
} \
|
||||
if(dyn->n.stack || dyn->insts[ninst].n.stack_next || dyn->insts[ninst].n.x87stack) \
|
||||
dynarec_log(LOG_NONE, " X87:%d/%d(+%d/-%d)%d", dyn->n.stack, dyn->insts[ninst].n.stack_next, dyn->insts[ninst].n.stack_push, dyn->insts[ninst].n.stack_pop, dyn->insts[ninst].n.x87stack); \
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) \
|
||||
dynarec_log(LOG_NONE, " %s:%d/%d", dyn->insts[ninst].n.swapped?"SWP":"CMB", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2); \
|
||||
dynarec_log(LOG_NONE, "%s\n", (box86_dynarec_dump>1)?"\e[m":""); \
|
||||
}
|
||||
|
||||
#define INST_NAME(name) inst_name_pass3(dyn, ninst, name)
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
typedef struct instsize_s instsize_t;
|
||||
|
||||
#define BARRIER_MAYBE 8
|
||||
|
||||
@@ -68,7 +69,7 @@ typedef struct instruction_arm_s {
|
||||
int pred_sz; // size of predecessor list
|
||||
int *pred; // predecessor array
|
||||
uintptr_t mark, mark2, mark3;
|
||||
uintptr_t markf;
|
||||
uintptr_t markf, markf2;
|
||||
uintptr_t markseg;
|
||||
uintptr_t marklock;
|
||||
int pass2choice;// value for choices that are fixed on pass2 for pass3
|
||||
@@ -90,22 +91,23 @@ typedef struct dynarec_arm_s {
|
||||
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
|
||||
uintptr_t jmp_next; // address of the jump_next address
|
||||
flagcache_t f;
|
||||
neoncache_t n; // cache for the 8..31 double reg from fpu, plus x87 stack delta
|
||||
uintptr_t* next; // variable array of "next" jump address
|
||||
int next_sz;
|
||||
int next_cap;
|
||||
uintptr_t* sons_x86; // the x86 address of potential dynablock sons
|
||||
void** sons_arm; // the arm address of potential dynablock sons
|
||||
int sons_size; // number of potential dynablock sons
|
||||
int* predecessor;// single array of all predecessor
|
||||
dynablock_t* dynablock;
|
||||
instsize_t* instsize;
|
||||
size_t insts_size; // size of the instruction size array (calculated)
|
||||
uint8_t smread; // for strongmem model emulation
|
||||
uint8_t smwrite; // for strongmem model emulation
|
||||
uintptr_t forward; // address of the last end of code while testing forward
|
||||
uintptr_t forward_to; // address of the next jump to (to check if everything is ok)
|
||||
int32_t forward_size; // size at the forward point
|
||||
int forward_ninst; // ninst at the forward point
|
||||
uint8_t always_test;
|
||||
} dynarec_arm_t;
|
||||
|
||||
void add_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
@@ -113,4 +115,6 @@ 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);
|
||||
|
||||
void CreateJmpNext(void* addr, void* next);
|
||||
|
||||
#endif //__DYNAREC_ARM_PRIVATE_H_
|
||||
@@ -44,4 +44,17 @@ typedef struct instruction_x86_s {
|
||||
|
||||
void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const char* name);
|
||||
|
||||
//#define USE_CUSTOM_MEM
|
||||
#ifdef USE_CUSTOM_MEM
|
||||
#define dynaMalloc customMalloc
|
||||
#define dynaCalloc customCalloc
|
||||
#define dynaRealloc customRealloc
|
||||
#define dynaFree customFree
|
||||
#else
|
||||
#define dynaMalloc box_malloc
|
||||
#define dynaCalloc box_calloc
|
||||
#define dynaRealloc box_realloc
|
||||
#define dynaFree box_free
|
||||
#endif
|
||||
|
||||
#endif //__DYNAREC_PRIVATE_H_
|
||||
@@ -233,9 +233,9 @@ NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 1 @<1> Rm @ param=1 char align[4
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> 1 1 0 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> 1 1 1 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> Rm @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 0 1 @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 1 1 @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> Rm @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 0 1 @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 1 1 @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> Rm @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
|
||||
|
||||
+326
-162
@@ -60,11 +60,14 @@ elfheader_t* LoadAndCheckElfHeader(FILE* f, const char* name, int exec)
|
||||
h->path = (char*)box_malloc(1);
|
||||
h->path[0] = '\0';
|
||||
}
|
||||
|
||||
|
||||
h->mapsymbols = NewMapSymbols();
|
||||
h->weaksymbols = NewMapSymbols();
|
||||
h->localsymbols = NewMapSymbols();
|
||||
|
||||
h->globaldefver = NewDefaultVersion();
|
||||
h->weakdefver = NewDefaultVersion();
|
||||
h->refcnt = 1;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
@@ -73,14 +76,9 @@ void FreeElfHeader(elfheader_t** head)
|
||||
if(!head || !*head)
|
||||
return;
|
||||
elfheader_t *h = *head;
|
||||
#ifdef DYNAREC
|
||||
/*if(h->text) {
|
||||
dynarec_log(LOG_INFO, "Free Dynarec block for %s\n", h->path);
|
||||
cleanDBFromAddressRange(my_context, h->text, h->textsz, 1);
|
||||
}*/ // will be free at the end, no need to free it now
|
||||
#endif
|
||||
box_free(h->name);
|
||||
box_free(h->path);
|
||||
if(my_context)
|
||||
RemoveElfHeader(my_context, h);
|
||||
|
||||
box_free(h->PHEntries);
|
||||
box_free(h->SHEntries);
|
||||
box_free(h->SHStrTab);
|
||||
@@ -93,8 +91,13 @@ void FreeElfHeader(elfheader_t** head)
|
||||
FreeMapSymbols(&h->mapsymbols);
|
||||
FreeMapSymbols(&h->weaksymbols);
|
||||
FreeMapSymbols(&h->localsymbols);
|
||||
|
||||
FreeDefaultVersion(&h->globaldefver);
|
||||
FreeDefaultVersion(&h->weakdefver);
|
||||
|
||||
FreeElfMemory(h);
|
||||
|
||||
box_free(h->name);
|
||||
box_free(h->path);
|
||||
box_free(h);
|
||||
|
||||
*head = NULL;
|
||||
@@ -158,12 +161,17 @@ const char* ElfName(elfheader_t* head)
|
||||
return "(noelf)";
|
||||
return head->name;
|
||||
}
|
||||
|
||||
const char* ElfPath(elfheader_t* head)
|
||||
{
|
||||
if(!head)
|
||||
return NULL;
|
||||
return head->path;
|
||||
}
|
||||
int AllocElfMemory(box86context_t* context, elfheader_t* head, int mainbin)
|
||||
{
|
||||
uintptr_t offs = 0;
|
||||
if(!head->vaddr && box86_load_addr) {
|
||||
offs = box86_load_addr;
|
||||
offs = (uintptr_t)findBlockNearHint((void*)box86_load_addr, head->memsz);
|
||||
box86_load_addr += head->memsz*(1+mainbin);
|
||||
box86_load_addr = (box86_load_addr+0xffffffLL)&~0xffffffLL;
|
||||
}
|
||||
@@ -296,6 +304,13 @@ void FreeElfMemory(elfheader_t* head)
|
||||
else
|
||||
for(int i=0; i<head->multiblock_n; ++i)
|
||||
munmap(head->multiblock[i], head->multiblock_size[i]);
|
||||
#ifdef DYNAREC
|
||||
for(int i=0; i<head->multiblock_n; ++i) {
|
||||
dynarec_log(LOG_INFO, "Free DynaBlocks for %s\n", head->path);
|
||||
cleanDBFromAddressRange((uintptr_t)head->multiblock[i], head->multiblock_size[i], 1);
|
||||
freeProtection((uintptr_t)head->multiblock[i], head->multiblock_size[i]);
|
||||
}
|
||||
#endif
|
||||
box_free(head->multiblock);
|
||||
box_free(head->multiblock_size);
|
||||
box_free(head->multiblock_offs);
|
||||
@@ -353,6 +368,23 @@ int LoadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int isElfHasNeededVer(elfheader_t* head, const char* libname, elfheader_t* verneeded)
|
||||
{
|
||||
if(!verneeded || !head)
|
||||
return 1;
|
||||
if(!head->VerDef || !verneeded->VerNeed)
|
||||
return 1;
|
||||
int cnt = GetNeededVersionCnt(verneeded, libname);
|
||||
for (int i=0; i<cnt; ++i) {
|
||||
const char* vername = GetNeededVersionString(verneeded, libname, i);
|
||||
if(vername && !GetVersionIndice(head, vername)) {
|
||||
printf_log(/*LOG_DEBUG*/LOG_INFO, "Discarding %s for missing version %s\n", head->path, vername);
|
||||
return 0; // missing version
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ReloadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
|
||||
{
|
||||
(void)context;
|
||||
@@ -402,7 +434,7 @@ int FindR386COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint32_t*
|
||||
if(version2!=-1) version2 &= 0x7fff;
|
||||
if(version && !version2) version2=-1; // match a versionned symbol against a global "local" symbol
|
||||
const char* vername2 = GetSymbolVersion(h, version2);
|
||||
if(SameVersionnedSymbol(name, version, vername, symname, version2, vername2)) {
|
||||
if(SameVersionedSymbol(name, version, vername, symname, version2, vername2)) {
|
||||
*offs = sym->st_value + h->delta;
|
||||
*p = (uint32_t*)(rel[i].r_offset + h->delta);
|
||||
return 1;
|
||||
@@ -422,7 +454,7 @@ int FindR386COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint32_t*
|
||||
if(version2!=-1) version2 &= 0x7fff;
|
||||
if(version && !version2) version2=-1; // match a versionned symbol against a global "local" symbol
|
||||
const char* vername2 = GetSymbolVersion(h, version2);
|
||||
if(SameVersionnedSymbol(name, version, vername, symname, version2, vername2)) {
|
||||
if(SameVersionedSymbol(name, version, vername, symname, version2, vername2)) {
|
||||
*offs = sym->st_value + h->delta;
|
||||
*p = (uint32_t*)(rela[i].r_offset + h->delta + rela[i].r_addend);
|
||||
return 1;
|
||||
@@ -436,6 +468,13 @@ int FindR386COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint32_t*
|
||||
int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t* head, int cnt, Elf32_Rel *rel, int* need_resolv)
|
||||
{
|
||||
int ret_ok = 0;
|
||||
const char* old_globdefver = NULL;
|
||||
const char* old_weakdefver = NULL;
|
||||
int old_bind = -1;
|
||||
const char* old_symname = NULL;
|
||||
uintptr_t old_offs = 0;
|
||||
uintptr_t old_end = 0;
|
||||
int old_version = -1;
|
||||
for (int i=0; i<cnt; ++i) {
|
||||
int t = ELF32_R_TYPE(rel[i].r_info);
|
||||
Elf32_Sym *sym = &head->DynSym[ELF32_R_SYM(rel[i].r_info)];
|
||||
@@ -450,32 +489,62 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t*
|
||||
int version = head->VerSym?((Elf32_Half*)((uintptr_t)head->VerSym+head->delta))[ELF32_R_SYM(rel[i].r_info)]:-1;
|
||||
if(version!=-1) version &=0x7fff;
|
||||
const char* vername = GetSymbolVersion(head, version);
|
||||
const char* defver = GetDefaultVersion((bind==STB_WEAK)?my_context->weakdefver:my_context->globaldefver, symname);
|
||||
const char* globdefver = NULL;
|
||||
const char* weakdefver = NULL;
|
||||
if(old_bind==bind && old_symname==symname) {
|
||||
globdefver = old_globdefver;
|
||||
weakdefver = old_weakdefver;
|
||||
} else {
|
||||
old_globdefver = globdefver = (bind==STB_WEAK)?NULL:GetMaplibDefaultVersion(maplib, local_maplib, 0, symname);
|
||||
old_weakdefver = weakdefver = (bind==STB_WEAK)?GetMaplibDefaultVersion(maplib, local_maplib, 1, symname):NULL;
|
||||
}
|
||||
if(bind==STB_LOCAL) {
|
||||
if(!symname || !symname[0]) {
|
||||
offs = sym->st_value + head->delta;
|
||||
end = offs + sym->st_size;
|
||||
} else {
|
||||
if(!offs && !end && local_maplib)
|
||||
GetLocalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername);
|
||||
if(!offs && !end)
|
||||
GetLocalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername);
|
||||
if(old_version==version && old_bind==bind && old_symname==symname) {
|
||||
offs = old_offs;
|
||||
end = old_end;
|
||||
} else {
|
||||
if(local_maplib)
|
||||
GetLocalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver);
|
||||
if(!offs && !end)
|
||||
GetLocalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// this is probably very very wrong. A proprer way to get reloc need to be writen, but this hack seems ok for now
|
||||
// this is probably very very wrong. A proprer way to get reloc need to be written, but this hack seems ok for now
|
||||
// at least it work for half-life, unreal, ut99, zsnes, Undertale, ColinMcRae Remake, FTL, ShovelKnight...
|
||||
/*if(bind==STB_GLOBAL && (ndx==10 || ndx==19) && t!=R_386_GLOB_DAT) {
|
||||
offs = sym->st_value + head->delta;
|
||||
end = offs + sym->st_size;
|
||||
}*/
|
||||
// so weak symbol are the one left
|
||||
if(!offs && !end) {
|
||||
if(!offs && !end && local_maplib)
|
||||
GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername);
|
||||
if(!offs && !end)
|
||||
GetGlobalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername);
|
||||
if(bind==STB_WEAK) {
|
||||
if(old_version==version && old_bind==bind && old_symname==symname) {
|
||||
offs = old_offs;
|
||||
end = old_end;
|
||||
} else {
|
||||
GetGlobalWeakSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver);
|
||||
if(!offs && !end && local_maplib)
|
||||
GetGlobalWeakSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver);
|
||||
}
|
||||
} else {
|
||||
if(old_version==version && old_bind==bind && old_symname==symname) {
|
||||
offs = old_offs;
|
||||
end = old_end;
|
||||
} else {
|
||||
GetGlobalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver);
|
||||
if(!offs && !end && local_maplib)
|
||||
GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver);
|
||||
}
|
||||
}
|
||||
}
|
||||
old_bind = bind;
|
||||
old_symname = symname;
|
||||
old_offs = offs;
|
||||
old_end = end;
|
||||
uintptr_t globoffs, globend;
|
||||
uint32_t* globp;
|
||||
uintptr_t tmp = 0;
|
||||
@@ -503,23 +572,23 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t*
|
||||
globoffs = offs;
|
||||
globend = end;
|
||||
offs = end = 0;
|
||||
GetSizedSymbolStartEnd(GetGlobalData(maplib), symname, &offs, &end, size, version, vername, 1, defver); // try globaldata symbols first
|
||||
GetSizedSymbolStartEnd(my_context->globdata, symname, &offs, &end, size, version, vername, 1, globdefver); // try globaldata symbols first
|
||||
if(!offs && local_maplib)
|
||||
GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head, size, version, vername);
|
||||
GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head, size, version, vername, globdefver, weakdefver);
|
||||
if(!offs)
|
||||
GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head, size, version, vername);
|
||||
GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head, size, version, vername, globdefver, weakdefver);
|
||||
if(!offs) {offs = globoffs; end = globend;}
|
||||
if(offs) {
|
||||
// add r_addend to p?
|
||||
printf_dump(LOG_NEVER, "Apply R_386_COPY @%p with sym=%s (ver=%d/%s), @%p size=%zd\n", p, symname, version, vername?vername:"(none)", (void*)offs, sym->st_size);
|
||||
if(p!=(void*)(offs))
|
||||
memmove(p, (void*)(offs), sym->st_size);
|
||||
if(p!=(void*)offs)
|
||||
memmove(p, (void*)offs, sym->st_size);
|
||||
} else {
|
||||
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply RELA R_386_COPY @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
|
||||
}
|
||||
break;
|
||||
case R_386_GLOB_DAT:
|
||||
if(head!=my_context->elfs[0] && !IsGlobalNoWeakSymbolInNative(maplib, symname, version, vername) && FindR386COPYRel(my_context->elfs[0], symname, &globoffs, &globp, size, version, vername)) {
|
||||
if(head!=my_context->elfs[0] && !IsGlobalNoWeakSymbolInNative(maplib, symname, version, vername, globdefver) && FindR386COPYRel(my_context->elfs[0], symname, &globoffs, &globp, size, version, vername)) {
|
||||
// set global offs / size for the symbol
|
||||
offs = sym->st_value + head->delta;
|
||||
end = offs + sym->st_size;
|
||||
@@ -528,7 +597,8 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t*
|
||||
(bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), p, globp, (void*)(p?(*p):0),
|
||||
(void*)(globp?(*globp):0), (void*)offs, (void*)globoffs, sym->st_size, symname, version, vername?vername:"(none)");
|
||||
//memmove((void*)globoffs, (void*)offs, sym->st_size); // preapply to copy part from lib to main elf
|
||||
AddUniqueSymbol(GetGlobalData(maplib), symname, offs, sym->st_size, version, vername);
|
||||
AddUniqueSymbol(GetGlobalData(maplib), symname, globoffs, sym->st_size, version, vername);
|
||||
AddUniqueSymbol(my_context->globdata, symname, offs, sym->st_size, version, vername);
|
||||
} else {
|
||||
printf_dump(LOG_NEVER, "Apply %s R_386_GLOB_DAT with R_386_COPY @%p/%p (%p/%p -> %p/%p) null sized on sym=%s (ver=%d/%s)\n",
|
||||
(bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), p, globp, (void*)(p?(*p):0),
|
||||
@@ -537,7 +607,7 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t*
|
||||
*p = globoffs;
|
||||
} else {
|
||||
// Look for same symbol already loaded but not in self (so no need for local_maplib here)
|
||||
if (GetGlobalNoWeakSymbolStartEnd(local_maplib?local_maplib:maplib, symname, &globoffs, &globend, version, vername)) {
|
||||
if (GetGlobalNoWeakSymbolStartEnd(local_maplib?local_maplib:maplib, symname, &globoffs, &globend, version, vername, globdefver)) {
|
||||
offs = globoffs;
|
||||
end = globend;
|
||||
}
|
||||
@@ -687,6 +757,13 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t*
|
||||
int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t* head, int cnt, Elf32_Rela *rela, int* need_resolv)
|
||||
{
|
||||
int ret_ok = 0;
|
||||
const char* old_globdefver = NULL;
|
||||
const char* old_weakdefver = NULL;
|
||||
int old_bind = -1;
|
||||
const char* old_symname = NULL;
|
||||
uintptr_t old_offs = 0;
|
||||
uintptr_t old_end = 0;
|
||||
int old_version = -1;
|
||||
for (int i=0; i<cnt; ++i) {
|
||||
int t = ELF32_R_TYPE(rela[i].r_info);
|
||||
Elf32_Sym *sym = &head->DynSym[ELF32_R_SYM(rela[i].r_info)];
|
||||
@@ -701,16 +778,29 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
|
||||
int version = head->VerSym?((Elf32_Half*)((uintptr_t)head->VerSym+head->delta))[ELF32_R_SYM(rela[i].r_info)]:-1;
|
||||
if(version!=-1) version &=0x7fff;
|
||||
const char* vername = GetSymbolVersion(head, version);
|
||||
const char* defver = GetDefaultVersion((bind==STB_WEAK)?my_context->weakdefver:my_context->globaldefver, symname);
|
||||
const char* globdefver = NULL;
|
||||
const char* weakdefver = NULL;
|
||||
if(old_bind==bind && old_symname==symname) {
|
||||
globdefver = old_globdefver;
|
||||
weakdefver = old_weakdefver;
|
||||
} else {
|
||||
old_globdefver = globdefver = (bind==STB_WEAK)?NULL:GetMaplibDefaultVersion(maplib, local_maplib, 0, symname);
|
||||
old_weakdefver = weakdefver = (bind==STB_WEAK)?GetMaplibDefaultVersion(maplib, local_maplib, 1, symname):NULL;
|
||||
}
|
||||
if(bind==STB_LOCAL) {
|
||||
if(!symname || !symname[0]) {
|
||||
offs = sym->st_value + head->delta;
|
||||
end = offs + sym->st_size;
|
||||
} else {
|
||||
if(!offs && !end && local_maplib)
|
||||
GetLocalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername);
|
||||
if(!offs && !end)
|
||||
GetLocalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername);
|
||||
if(old_version==version && old_bind==bind && old_symname==symname) {
|
||||
offs = old_offs;
|
||||
end = old_end;
|
||||
} else {
|
||||
if(local_maplib)
|
||||
GetLocalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver);
|
||||
if(!offs && !end)
|
||||
GetLocalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// this is probably very very wrong. A proprer way to get reloc need to be writen, but this hack seems ok for now
|
||||
@@ -720,18 +810,35 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
|
||||
end = offs + sym->st_size;
|
||||
}*/
|
||||
// so weak symbol are the one left
|
||||
if(!offs && !end) {
|
||||
GetGlobalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername);
|
||||
if(!offs && !end && local_maplib) {
|
||||
GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername);
|
||||
if(bind==STB_WEAK) {
|
||||
if(old_version==version && old_bind==bind && old_symname==symname) {
|
||||
offs = old_offs;
|
||||
end = old_end;
|
||||
} else {
|
||||
GetGlobalWeakSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver);
|
||||
if(!offs && !end && local_maplib)
|
||||
GetGlobalWeakSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver);
|
||||
}
|
||||
} else {
|
||||
if(old_version==version && old_bind==bind && old_symname==symname) {
|
||||
offs = old_offs;
|
||||
end = old_end;
|
||||
} else {
|
||||
GetGlobalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver);
|
||||
if(!offs && !end && local_maplib)
|
||||
GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, globdefver, weakdefver);
|
||||
}
|
||||
}
|
||||
}
|
||||
old_bind = bind;
|
||||
old_symname = symname;
|
||||
old_offs = offs;
|
||||
old_end = end;
|
||||
uintptr_t globoffs, globend;
|
||||
uint32_t* globp;
|
||||
uintptr_t tmp = 0;
|
||||
intptr_t delta;
|
||||
switch(ELF32_R_TYPE(rela[i].r_info)) {
|
||||
switch(t) {
|
||||
case R_386_NONE:
|
||||
// can be ignored
|
||||
printf_dump(LOG_NEVER, "Ignoring [%d] %s %p (%p)\n", i, DumpRelType(t), p, (void*)(p?(*p):0));
|
||||
@@ -753,11 +860,11 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
|
||||
globoffs = offs;
|
||||
globend = end;
|
||||
offs = end = 0;
|
||||
GetSymbolStartEnd(GetGlobalData(maplib), symname, &offs, &end, version, vername, 1, defver); // try globaldata symbols first
|
||||
GetSizedSymbolStartEnd(my_context->globdata, symname, &offs, &end, size, version, vername, 1, globdefver); // try globaldata symbols first
|
||||
if(!offs && local_maplib)
|
||||
GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head, size, version, vername);
|
||||
GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head, size, version, vername, globdefver, weakdefver);
|
||||
if(!offs)
|
||||
GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head, size, version, vername);
|
||||
GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head, size, version, vername, globdefver, weakdefver);
|
||||
if(!offs) {offs = globoffs; end = globend;}
|
||||
if(offs) {
|
||||
// add r_addend to p?
|
||||
@@ -769,7 +876,7 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
|
||||
}
|
||||
break;
|
||||
case R_386_GLOB_DAT:
|
||||
if(head!=my_context->elfs[0] && !IsGlobalNoWeakSymbolInNative(maplib, symname, version, vername) && FindR386COPYRel(my_context->elfs[0], symname, &globoffs, &globp, size, version, vername)) {
|
||||
if(head!=my_context->elfs[0] && !IsGlobalNoWeakSymbolInNative(maplib, symname, version, vername, globdefver) && FindR386COPYRel(my_context->elfs[0], symname, &globoffs, &globp, size, version, vername)) {
|
||||
// set global offs / size for the symbol
|
||||
offs = sym->st_value + head->delta;
|
||||
end = offs + sym->st_size;
|
||||
@@ -778,7 +885,8 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
|
||||
(bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), p, globp, (void*)(p?(*p):0),
|
||||
(void*)(globp?(*globp):0), (void*)offs, (void*)globoffs, sym->st_size, symname, version, vername?vername:"(none)");
|
||||
//memmove((void*)globoffs, (void*)offs, sym->st_size); // preapply to copy part from lib to main elf
|
||||
AddUniqueSymbol(GetGlobalData(maplib), symname, offs, sym->st_size, version, vername);
|
||||
AddUniqueSymbol(GetGlobalData(maplib), symname, globoffs, sym->st_size, version, vername);
|
||||
AddUniqueSymbol(my_context->globdata, symname, offs, sym->st_size, version, vername);
|
||||
} else {
|
||||
printf_dump(LOG_NEVER, "Apply %s R_386_GLOB_DAT with R_386_COPY @%p/%p (%p/%p -> %p/%p) null sized on sym=%s (ver=%d/%s)\n",
|
||||
(bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), p, globp, (void*)(p?(*p):0),
|
||||
@@ -787,7 +895,7 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
|
||||
*p = globoffs;
|
||||
} else {
|
||||
// Look for same symbol already loaded but not in self (so no need for local_maplib here)
|
||||
if (GetGlobalNoWeakSymbolStartEnd(local_maplib?local_maplib:maplib, symname, &globoffs, &globend, version, vername)) {
|
||||
if (GetGlobalNoWeakSymbolStartEnd(local_maplib?local_maplib:maplib, symname, &globoffs, &globend, version, vername, globdefver)) {
|
||||
offs = globoffs;
|
||||
end = globend;
|
||||
}
|
||||
@@ -932,9 +1040,13 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
|
||||
}
|
||||
return bindnow?ret_ok:0;
|
||||
}
|
||||
void checkHookedSymbols(lib_t *maplib, elfheader_t* h); // in mallochook.c
|
||||
|
||||
int RelocateElf(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t* head)
|
||||
{
|
||||
if(0 && (head->flags&DF_BIND_NOW) && !bindnow) { // disable for now, needs more symbol in a fow libs like gtk and nss3
|
||||
bindnow = 1;
|
||||
printf_log(LOG_DEBUG, "Forcing %s to Bind Now\n", head->name);
|
||||
}
|
||||
if(head->rel) {
|
||||
int cnt = head->relsz / head->relent;
|
||||
DumpRelTable(head, cnt, (Elf32_Rel *)(head->rel + head->delta), "Rel");
|
||||
@@ -949,13 +1061,16 @@ int RelocateElf(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t* he
|
||||
if(RelocateElfRELA(maplib, local_maplib, bindnow, head, cnt, (Elf32_Rela *)(head->rela + head->delta), NULL))
|
||||
return -1;
|
||||
}
|
||||
checkHookedSymbols(maplib, head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RelocateElfPlt(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t* head)
|
||||
{
|
||||
int need_resolver = 0;
|
||||
if(0 && (head->flags&DF_BIND_NOW) && !bindnow) { // disable for now, needs more symbol in a fow libs like gtk and nss3
|
||||
bindnow = 1;
|
||||
printf_log(LOG_DEBUG, "Forcing %s to Bind Now\n", head->name);
|
||||
}
|
||||
if(head->pltrel) {
|
||||
int cnt = head->pltsz / head->pltent;
|
||||
if(head->pltrel==DT_REL) {
|
||||
@@ -1058,6 +1173,7 @@ uintptr_t GetLastByte(elfheader_t* h)
|
||||
#define STB_GNU_UNIQUE 10
|
||||
#endif
|
||||
|
||||
void checkHookedSymbols(elfheader_t* h); // in mallochook.c
|
||||
void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* weaksymbols, kh_mapsymbols_t* localsymbols, elfheader_t* h)
|
||||
{
|
||||
if(box86_dump && h->DynSym) DumpDynSym(h);
|
||||
@@ -1068,41 +1184,29 @@ void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* wea
|
||||
int type = ELF32_ST_TYPE(h->SymTab[i].st_info);
|
||||
int vis = h->SymTab[i].st_other&0x3;
|
||||
size_t sz = h->SymTab[i].st_size;
|
||||
// check "@@" default version symbol to add that information, regardless of size or type
|
||||
if(symname && strstr(symname, "@@")) {
|
||||
char symnameversionned[strlen(symname)+1];
|
||||
strcpy(symnameversionned, symname);
|
||||
// extract symname@@vername
|
||||
char* p = strchr(symnameversionned, '@');
|
||||
*p=0;
|
||||
p+=2;
|
||||
symname = AddDictionnary(my_context->versym, symnameversionned);
|
||||
const char* vername = AddDictionnary(my_context->versym, p);
|
||||
AddDefaultVersion((bind==STB_WEAK)?my_context->weakdefver:my_context->globaldefver, symname, vername);
|
||||
printf_dump(LOG_NEVER, "Adding %s Default Version \"%s\" for Symbol\"%s\"\n", (bind==STB_WEAK)?"Weak":"Global", vername, symname);
|
||||
}
|
||||
if((type==STT_OBJECT || type==STT_FUNC || type==STT_COMMON || type==STT_TLS || type==STT_NOTYPE)
|
||||
&& (vis==STV_DEFAULT || vis==STV_PROTECTED || (vis==STV_HIDDEN && bind==STB_LOCAL)) && (h->SymTab[i].st_shndx!=0)) {
|
||||
if(strstr(symname, "@@")) {
|
||||
char symnameversionned[strlen(symname)+1];
|
||||
strcpy(symnameversionned, symname);
|
||||
// extract symname@@vername
|
||||
char* p = strchr(symnameversionned, '@');
|
||||
if(sz && strstr(symname, "@@")) {
|
||||
char symnameversioned[strlen(symname)+1];
|
||||
strcpy(symnameversioned, symname);
|
||||
// extact symname@@vername
|
||||
char* p = strchr(symnameversioned, '@');
|
||||
*p=0;
|
||||
p+=2;
|
||||
symname = AddDictionnary(my_context->versym, symnameversionned);
|
||||
symname = AddDictionnary(my_context->versym, symnameversioned);
|
||||
const char* vername = AddDictionnary(my_context->versym, p);
|
||||
if(!sz || ((bind==STB_GNU_UNIQUE /*|| (bind==STB_GLOBAL && type==STT_FUNC)*/) && FindGlobalSymbol(maplib, symname, 2, p)))
|
||||
AddDefaultVersion((bind==STB_WEAK)?h->weakdefver:h->globaldefver, symname, vername);
|
||||
if((bind==STB_GNU_UNIQUE /*|| (bind==STB_GLOBAL && type==STT_FUNC)*/) && FindGlobalSymbol(maplib, symname, 2, p))
|
||||
continue;
|
||||
uintptr_t offs = (type==STT_TLS)?h->SymTab[i].st_value:(h->SymTab[i].st_value + h->delta);
|
||||
printf_dump(LOG_NEVER, "Adding Default Versionned Symbol(bind=%s) \"%s@%s\" with offset=%p sz=%zu\n", (bind==STB_LOCAL)?"LOCAL":((bind==STB_WEAK)?"WEAK":"GLOBAL"), symname, vername, (void*)offs, sz);
|
||||
printf_dump(LOG_NEVER, "Adding Default Versioned Symbol(bind=%s) \"%s@%s\" with offset=%p sz=%zu\n", (bind==STB_LOCAL)?"LOCAL":((bind==STB_WEAK)?"WEAK":"GLOBAL"), symname, vername, (void*)offs, sz);
|
||||
if(bind==STB_LOCAL)
|
||||
AddSymbol(localsymbols, symname, offs, sz, 0, vername);
|
||||
AddSymbol(localsymbols, symname, offs, sz, 2, vername);
|
||||
else // add in local and global map
|
||||
if(bind==STB_WEAK) {
|
||||
AddSymbol(weaksymbols, symname, offs, sz, 0, vername);
|
||||
AddSymbol(weaksymbols, symname, offs, sz, 2, vername);
|
||||
} else {
|
||||
AddSymbol(mapsymbols, symname, offs, sz, 0, vername);
|
||||
AddSymbol(mapsymbols, symname, offs, sz, 2, vername);
|
||||
}
|
||||
} else {
|
||||
int to_add = 1;
|
||||
@@ -1133,17 +1237,17 @@ void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* wea
|
||||
uintptr_t offs = (type==STT_TLS)?h->DynSym[i].st_value:(h->DynSym[i].st_value + h->delta);
|
||||
size_t sz = h->DynSym[i].st_size;
|
||||
int version = h->VerSym?((Elf32_Half*)((uintptr_t)h->VerSym+h->delta))[i]:-1;
|
||||
int add_default = (version!=-1 && (version&0x7fff)>1 && !(version&0x8000) && !GetDefaultVersion((bind==STB_WEAK)?my_context->weakdefver:my_context->globaldefver, symname))?1:0;
|
||||
int add_default = (version!=-1 && (version&0x7fff)>1 && !(version&0x8000) && !GetMaplibDefaultVersion(my_context->maplib, (maplib==my_context->maplib)?NULL:maplib, (bind==STB_WEAK)?1:0, symname))?1:0;
|
||||
if(version!=-1) version &= 0x7fff;
|
||||
const char* vername = GetSymbolVersion(h, version);
|
||||
if(add_default) {
|
||||
AddDefaultVersion((bind==STB_WEAK)?my_context->weakdefver:my_context->globaldefver, symname, vername);
|
||||
AddDefaultVersion((bind==STB_WEAK)?h->weakdefver:h->globaldefver, symname, vername);
|
||||
printf_dump(LOG_NEVER, "Adding Default Version \"%s\" for Symbol\"%s\"\n", vername, symname);
|
||||
}
|
||||
int to_add = 1;
|
||||
if(!to_add || (bind==STB_GNU_UNIQUE && FindGlobalSymbol(maplib, symname, version, vername)))
|
||||
continue;
|
||||
printf_dump(LOG_NEVER, "Adding Versionned Symbol(bind=%s) \"%s\" (ver=%d/%s) with offset=%p sz=%zu\n", (bind==STB_LOCAL)?"LOCAL":((bind==STB_WEAK)?"WEAK":"GLOBAL"), symname, version, vername?vername:"(none)", (void*)offs, sz);
|
||||
printf_dump(LOG_NEVER, "Adding Versioned Symbol(bind=%s) \"%s\" (ver=%d/%s) with offset=%p sz=%zu\n", (bind==STB_LOCAL)?"LOCAL":((bind==STB_WEAK)?"WEAK":"GLOBAL"), symname, version, vername?vername:"(none)", (void*)offs, sz);
|
||||
if(bind==STB_LOCAL)
|
||||
AddSymbol(localsymbols, symname, offs, sz, version, vername);
|
||||
else // add in local and global map
|
||||
@@ -1154,7 +1258,7 @@ void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* wea
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkHookedSymbols(h);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1171,8 +1275,10 @@ $PLATFORM – Expands to the processor type of the current machine (see the
|
||||
uname(1) man page description of the -i option). For more details of this token
|
||||
expansion, see “System Specific Shared Objects”
|
||||
*/
|
||||
int LoadNeededLibs(elfheader_t* h, lib_t* maplib, needed_libs_t* neededlibs, library_t* deplib, int local, int bindnow, box86context_t* box86, x86emu_t* emu)
|
||||
int LoadNeededLibs(elfheader_t* h, lib_t *maplib, int local, int bindnow, box86context_t *box86, x86emu_t* emu)
|
||||
{
|
||||
if(h->needed) // already done
|
||||
return 0;
|
||||
DumpDynamicRPath(h);
|
||||
// update RPATH first
|
||||
for (uint32_t i=0; i<h->numDynamic; ++i)
|
||||
@@ -1210,39 +1316,49 @@ int LoadNeededLibs(elfheader_t* h, lib_t* maplib, needed_libs_t* neededlibs, lib
|
||||
box_free(origin);
|
||||
is_origin = 1;
|
||||
}
|
||||
while(strstr(rpath, "${PLATFORM}")) {
|
||||
char* platform = box_strdup("i686");
|
||||
char* p = strrchr(platform, '/');
|
||||
if(p) *p = '\0'; // remove file name to have only full path, without last '/'
|
||||
char* tmp = (char*)box_calloc(1, strlen(rpath)-strlen("${PLATFORM}")+strlen(platform)+1);
|
||||
p = strstr(rpath, "${PLATFORM}");
|
||||
memcpy(tmp, rpath, p-rpath);
|
||||
strcat(tmp, platform);
|
||||
strcat(tmp, p+strlen("${PLATFORM}"));
|
||||
if(rpath!=rpathref)
|
||||
box_free(rpath);
|
||||
rpath = tmp;
|
||||
box_free(platform);
|
||||
}
|
||||
if(strchr(rpath, '$')) {
|
||||
printf_log(LOG_INFO, "BOX86: Warning, RPATH with $ variable not supported yet (%s)\n", rpath);
|
||||
} else {
|
||||
printf_log(LOG_DEBUG, "Prepending path \"%s\" to BOX86_LD_LIBRARY_PATH\n", rpath);
|
||||
if(is_origin) {
|
||||
// also add rpath/i686
|
||||
char tmp[strlen(rpath)+strlen("/i686")+1];
|
||||
strcpy(tmp, rpath);
|
||||
strcat(tmp, "/i686");
|
||||
PrependList(&box86->box86_ld_lib, tmp, 1);
|
||||
}
|
||||
PrependList(&box86->box86_ld_lib, rpath, 1);
|
||||
}
|
||||
if(rpath!=rpathref)
|
||||
box_free(rpath);
|
||||
}
|
||||
|
||||
if(!h->neededlibs && neededlibs)
|
||||
h->neededlibs = neededlibs;
|
||||
|
||||
DumpDynamicNeeded(h);
|
||||
int cnt = 0;
|
||||
for (uint32_t i=0; i<h->numDynamic; ++i)
|
||||
// count the number of needed libs, and also grab soname
|
||||
for (uint32_t i=0; i<h->numDynamic; ++i) {
|
||||
if(h->Dynamic[i].d_tag==DT_NEEDED)
|
||||
++cnt;
|
||||
const char* nlibs[cnt];
|
||||
if(h->Dynamic[i].d_tag==DT_SONAME)
|
||||
h->soname = h->DynStrTab+h->delta+h->Dynamic[i].d_un.d_val;
|
||||
}
|
||||
h->needed = new_neededlib(cnt);
|
||||
if(h == my_context->elfs[0])
|
||||
my_context->neededlibs = h->needed;
|
||||
int j=0;
|
||||
for (uint32_t i=0; i<h->numDynamic; ++i)
|
||||
if(h->Dynamic[i].d_tag==DT_NEEDED)
|
||||
nlibs[j++] = h->DynStrTab+h->delta+h->Dynamic[i].d_un.d_val;
|
||||
h->needed->names[j++] = h->DynStrTab+h->delta+h->Dynamic[i].d_un.d_val;
|
||||
|
||||
// TODO: Add LD_LIBRARY_PATH and RPATH handling
|
||||
if(AddNeededLib(maplib, neededlibs, deplib, local, bindnow, nlibs, cnt, box86, emu)) {
|
||||
if(AddNeededLib(maplib, local, bindnow, h->needed, h, box86, emu)) {
|
||||
printf_log(LOG_INFO, "Error loading one of needed lib\n");
|
||||
if(!allow_missing_libs)
|
||||
return 1; //error...
|
||||
@@ -1289,30 +1405,35 @@ void MarkElfInitDone(elfheader_t* h)
|
||||
if(h)
|
||||
h->init_done = 1;
|
||||
}
|
||||
void startMallocHook();
|
||||
void RunElfInitPltResolver(elfheader_t* h, x86emu_t *emu)
|
||||
{
|
||||
if(!h || h->init_done)
|
||||
return;
|
||||
|
||||
uintptr_t p = h->initentry + h->delta;
|
||||
h->init_done = 1;
|
||||
for(int i=0; i<h->neededlibs->size; ++i) {
|
||||
library_t *lib = h->neededlibs->libs[i];
|
||||
for(int i=0; i<h->needed->size; ++i) {
|
||||
library_t *lib = h->needed->libs[i];
|
||||
elfheader_t *lib_elf = GetElf(lib);
|
||||
if(lib_elf)
|
||||
RunElfInitPltResolver(lib_elf, emu);
|
||||
}
|
||||
printf_log(LOG_DEBUG, "Calling Init for %s %p\n", ElfName(h), (void*)p);
|
||||
if(h->initentry)
|
||||
RunSafeFunction(my_context, p, 3, my_context->argc, my_context->argv, my_context->envv);
|
||||
RunSafeFunction(p, 3, my_context->argc, my_context->argv, my_context->envv);
|
||||
printf_log(LOG_DEBUG, "Done Init for %s\n", ElfName(h));
|
||||
// and check init array now
|
||||
Elf32_Addr *addr = (Elf32_Addr*)(h->initarray + h->delta);
|
||||
for (int i=0; i<h->initarray_sz; ++i) {
|
||||
printf_log(LOG_DEBUG, "Calling Init[%d] for %s %p\n", i, ElfName(h), (void*)addr[i]);
|
||||
RunSafeFunction(my_context, (uintptr_t)addr[i], 3, my_context->argc, my_context->argv, my_context->envv);
|
||||
if(addr[i]) {
|
||||
printf_log(LOG_DEBUG, "Calling Init[%d] for %s %p\n", i, ElfName(h), (void*)addr[i]);
|
||||
RunSafeFunction((uintptr_t)addr[i], 3, my_context->argc, my_context->argv, my_context->envv);
|
||||
}
|
||||
}
|
||||
|
||||
if(h->malloc_hook_2)
|
||||
startMallocHook();
|
||||
|
||||
h->fini_done = 0; // can be fini'd now (in case it was re-inited)
|
||||
printf_log(LOG_DEBUG, "All Init Done for %s\n", ElfName(h));
|
||||
return;
|
||||
@@ -1328,44 +1449,55 @@ void RunElfInit(elfheader_t* h, x86emu_t *emu)
|
||||
// Refresh no-file part of TLS in case default value changed
|
||||
RefreshElfTLS(h);
|
||||
// check if in deferedInit
|
||||
if(context->deferedInit) {
|
||||
if(context->deferedInitSz==context->deferedInitCap) {
|
||||
context->deferedInitCap += 4;
|
||||
context->deferedInitList = (elfheader_t**)box_realloc(context->deferedInitList, context->deferedInitCap*sizeof(elfheader_t*));
|
||||
if(context->deferredInit) {
|
||||
if(context->deferredInitSz==context->deferredInitCap) {
|
||||
context->deferredInitCap += 4;
|
||||
context->deferredInitList = (elfheader_t**)box_realloc(context->deferredInitList, context->deferredInitCap*sizeof(elfheader_t*));
|
||||
}
|
||||
context->deferedInitList[context->deferedInitSz++] = h;
|
||||
context->deferredInitList[context->deferredInitSz++] = h;
|
||||
return;
|
||||
}
|
||||
printf_log(LOG_DEBUG, "Calling Init for %s %p\n", ElfName(h), (void*)p);
|
||||
h->init_done = 1;
|
||||
for(int i=0; i<h->needed->size; ++i) {
|
||||
library_t *lib = h->needed->libs[i];
|
||||
elfheader_t *lib_elf = GetElf(lib);
|
||||
if(lib_elf)
|
||||
RunElfInit(lib_elf, emu);
|
||||
}
|
||||
printf_dump(LOG_DEBUG, "Calling Init for %s @%p\n", ElfName(h), (void*)p);
|
||||
if(h->initentry)
|
||||
RunFunctionWithEmu(emu, 0, p, 3, context->argc, context->argv, context->envv);
|
||||
printf_log(LOG_DEBUG, "Done Init for %s\n", ElfName(h));
|
||||
printf_dump(LOG_DEBUG, "Done Init for %s\n", ElfName(h));
|
||||
// and check init array now
|
||||
Elf32_Addr *addr = (Elf32_Addr*)(h->initarray + h->delta);
|
||||
for (int i=0; i<h->initarray_sz; ++i) {
|
||||
printf_log(LOG_DEBUG, "Calling Init[%d] for %s %p\n", i, ElfName(h), (void*)addr[i]);
|
||||
RunFunctionWithEmu(emu, 0, (uintptr_t)addr[i], 3, context->argc, context->argv, context->envv);
|
||||
for (size_t i=0; i<h->initarray_sz; ++i) {
|
||||
if(addr[i]) {
|
||||
printf_dump(LOG_DEBUG, "Calling Init[%zu] for %s @%p\n", i, ElfName(h), (void*)addr[i]);
|
||||
RunFunctionWithEmu(emu, 0, (uintptr_t)addr[i], 3, context->argc, context->argv, context->envv);
|
||||
}
|
||||
}
|
||||
|
||||
if(h->malloc_hook_2)
|
||||
startMallocHook();
|
||||
|
||||
h->fini_done = 0; // can be fini'd now (in case it was re-inited)
|
||||
printf_log(LOG_DEBUG, "All Init Done for %s\n", ElfName(h));
|
||||
printf_dump(LOG_DEBUG, "All Init Done for %s\n", ElfName(h));
|
||||
return;
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
void RunDeferedElfInit(x86emu_t *emu)
|
||||
void RunDeferredElfInit(x86emu_t *emu)
|
||||
{
|
||||
box86context_t* context = GetEmuContext(emu);
|
||||
if(!context->deferedInit)
|
||||
if(!context->deferredInit)
|
||||
return;
|
||||
context->deferedInit = 0;
|
||||
if(!context->deferedInitList)
|
||||
context->deferredInit = 0;
|
||||
if(!context->deferredInitList)
|
||||
return;
|
||||
int Sz = context->deferedInitSz;
|
||||
elfheader_t** List = context->deferedInitList;
|
||||
context->deferedInitList = NULL;
|
||||
context->deferedInitCap = context->deferedInitSz = 0;
|
||||
int Sz = context->deferredInitSz;
|
||||
elfheader_t** List = context->deferredInitList;
|
||||
context->deferredInitList = NULL;
|
||||
context->deferredInitCap = context->deferredInitSz = 0;
|
||||
for (int i=0; i<Sz; ++i)
|
||||
RunElfInit(List[i], emu);
|
||||
box_free(List);
|
||||
@@ -1373,7 +1505,7 @@ void RunDeferedElfInit(x86emu_t *emu)
|
||||
|
||||
void RunElfFini(elfheader_t* h, x86emu_t *emu)
|
||||
{
|
||||
if(!h || h->fini_done)
|
||||
if(!h || h->fini_done || !h->init_done)
|
||||
return;
|
||||
h->fini_done = 1;
|
||||
#ifdef ANDROID
|
||||
@@ -1420,7 +1552,7 @@ uint32_t GetBaseSize(elfheader_t* h)
|
||||
return h->memsz;
|
||||
}
|
||||
|
||||
int IsAddressInElfSpace(elfheader_t* h, uintptr_t addr)
|
||||
int IsAddressInElfSpace(const elfheader_t* h, uintptr_t addr)
|
||||
{
|
||||
if(!h)
|
||||
return 0;
|
||||
@@ -1450,7 +1582,23 @@ const char* FindNearestSymbolName(elfheader_t* h, void* p, uintptr_t* start, uin
|
||||
const char* ret = NULL;
|
||||
uintptr_t s = 0;
|
||||
uint32_t size = 0;
|
||||
if(!h)
|
||||
#ifdef HAVE_TRACE
|
||||
if(!h) {
|
||||
if(getProtection((uintptr_t)p)&(PROT_READ)) {
|
||||
if(*(uint8_t*)(p)==0xCC && *(uint8_t*)(p+1)=='S' && *(uint8_t*)(p+2)=='C') {
|
||||
ret = getBridgeName(*(void**)(p+3+4));
|
||||
if(ret) {
|
||||
if(start)
|
||||
*start = (uintptr_t)p;
|
||||
if(sz)
|
||||
*sz = 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
if(!h || h->fini_done)
|
||||
return ret;
|
||||
|
||||
for (uint32_t i=0; (i<h->numSymTab) && (distance!=0); ++i) {
|
||||
@@ -1488,7 +1636,7 @@ const char* FindNearestSymbolName(elfheader_t* h, void* p, uintptr_t* start, uin
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char* VersionnedName(const char* name, int ver, const char* vername)
|
||||
const char* VersionedName(const char* name, int ver, const char* vername)
|
||||
{
|
||||
if(ver<0)
|
||||
return name;
|
||||
@@ -1508,7 +1656,7 @@ const char* VersionnedName(const char* name, int ver, const char* vername)
|
||||
return AddDictionnary(my_context->versym, buf);
|
||||
}
|
||||
|
||||
int SameVersionnedSymbol(const char* name1, int ver1, const char* vername1, const char* name2, int ver2, const char* vername2)
|
||||
int SameVersionedSymbol(const char* name1, int ver1, const char* vername1, const char* name2, int ver2, const char* vername2)
|
||||
{
|
||||
if(strcmp(name1, name2)) //name are different, no need to go further
|
||||
return 0;
|
||||
@@ -1532,12 +1680,12 @@ void* GetDTatOffset(box86context_t* context, int index, int offset)
|
||||
|
||||
int32_t GetTLSBase(elfheader_t* h)
|
||||
{
|
||||
return h->tlsbase;
|
||||
return h?h->tlsbase:0;
|
||||
}
|
||||
|
||||
uint32_t GetTLSSize(elfheader_t* h)
|
||||
{
|
||||
return h->tlssize;
|
||||
return h?h->tlssize:0;
|
||||
}
|
||||
|
||||
void* GetTLSPointer(box86context_t* context, elfheader_t* h)
|
||||
@@ -1607,8 +1755,9 @@ void* ElfSetBrk(void* newbrk)
|
||||
}
|
||||
|
||||
#ifdef DYNAREC
|
||||
dynablocklist_t* GetDynablocksFromAddress(box86context_t *context, uintptr_t addr)
|
||||
dynablock_t* GetDynablocksFromAddress(box86context_t *context, uintptr_t addr)
|
||||
{
|
||||
(void)context;
|
||||
// if we are here, the there is not block in standard "space"
|
||||
/*dynablocklist_t* ret = getDBFromAddress(addr);
|
||||
if(ret) {
|
||||
@@ -1616,7 +1765,7 @@ dynablocklist_t* GetDynablocksFromAddress(box86context_t *context, uintptr_t add
|
||||
}*/
|
||||
if(box86_dynarec_forced) {
|
||||
addDBFromAddressRange(addr, 1);
|
||||
return getDB(addr>>DYNAMAP_SHIFT);
|
||||
return getDB(addr);
|
||||
}
|
||||
//check if address is in an elf... if yes, grant a block (should I warn)
|
||||
Dl_info info;
|
||||
@@ -1629,26 +1778,6 @@ dynablocklist_t* GetDynablocksFromAddress(box86context_t *context, uintptr_t add
|
||||
}
|
||||
#endif
|
||||
|
||||
kh_mapsymbols_t* GetMapSymbols(elfheader_t* h)
|
||||
{
|
||||
if(!h)
|
||||
return NULL;
|
||||
return h->mapsymbols;
|
||||
}
|
||||
kh_mapsymbols_t* GetWeakSymbols(elfheader_t* h)
|
||||
{
|
||||
if(!h)
|
||||
return NULL;
|
||||
return h->weaksymbols;
|
||||
}
|
||||
kh_mapsymbols_t* GetLocalSymbols(elfheader_t* h)
|
||||
{
|
||||
if(!h)
|
||||
return NULL;
|
||||
return h->localsymbols;
|
||||
}
|
||||
|
||||
|
||||
typedef struct my_dl_phdr_info_s {
|
||||
void* dlpi_addr;
|
||||
const char* dlpi_name;
|
||||
@@ -1671,14 +1800,14 @@ GO(4)
|
||||
|
||||
// dl_iterate_phdr ...
|
||||
#define GO(A) \
|
||||
static uintptr_t my_dl_iterate_phdr_fct_##A = 0; \
|
||||
static int my_dl_iterate_phdr_##A(struct dl_phdr_info* a, size_t b, void* c)\
|
||||
{ \
|
||||
if(!a->dlpi_name) \
|
||||
return 0; \
|
||||
if(!a->dlpi_name[0]) /*don't send informations about box86 itself*/ \
|
||||
return 0; \
|
||||
return RunFunction(my_context, my_dl_iterate_phdr_fct_##A, 3, a, b, c); \
|
||||
static uintptr_t my_dl_iterate_phdr_fct_##A = 0; \
|
||||
static int my_dl_iterate_phdr_##A(struct dl_phdr_info* a, size_t b, void* c) \
|
||||
{ \
|
||||
if(!a->dlpi_name) \
|
||||
return 0; \
|
||||
if(!a->dlpi_name[0]) /*don't send informations about box86 itself*/ \
|
||||
return 0; \
|
||||
return RunFunctionFmt(my_dl_iterate_phdr_fct_##A, "pLp", a, b, c); \
|
||||
}
|
||||
SUPER()
|
||||
#undef GO
|
||||
@@ -1801,6 +1930,25 @@ void ElfAttachLib(elfheader_t* head, library_t* lib)
|
||||
head->lib = lib;
|
||||
}
|
||||
|
||||
kh_mapsymbols_t* GetMapSymbols(elfheader_t* h)
|
||||
{
|
||||
if(!h)
|
||||
return NULL;
|
||||
return h->mapsymbols;
|
||||
}
|
||||
kh_mapsymbols_t* GetWeakSymbols(elfheader_t* h)
|
||||
{
|
||||
if(!h)
|
||||
return NULL;
|
||||
return h->weaksymbols;
|
||||
}
|
||||
kh_mapsymbols_t* GetLocalSymbols(elfheader_t* h)
|
||||
{
|
||||
if(!h)
|
||||
return NULL;
|
||||
return h->localsymbols;
|
||||
}
|
||||
|
||||
typedef struct search_symbol_s{
|
||||
const char* name;
|
||||
void* addr;
|
||||
@@ -1858,7 +2006,7 @@ int dl_iterate_phdr_findsymbol(struct dl_phdr_info* info, size_t size, void* dat
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* GetNativeSymbolUnversionned(void* lib, const char* name)
|
||||
void* GetNativeSymbolUnversioned(void* lib, const char* name)
|
||||
{
|
||||
// try to find "name" in loaded elf, whithout checking for the symbol version (like dlsym, but no version check)
|
||||
search_symbol_t s;
|
||||
@@ -1873,6 +2021,16 @@ void* GetNativeSymbolUnversionned(void* lib, const char* name)
|
||||
return s.addr;
|
||||
}
|
||||
|
||||
kh_defaultversion_t* GetGlobalDefaultVersion(elfheader_t* h)
|
||||
{
|
||||
return h?h->globaldefver:NULL;
|
||||
}
|
||||
kh_defaultversion_t* GetWeakDefaultVersion(elfheader_t* h)
|
||||
{
|
||||
return h?h->weakdefver:NULL;
|
||||
}
|
||||
|
||||
|
||||
uintptr_t pltResolver = ~(uintptr_t)0;
|
||||
EXPORT void PltResolver(x86emu_t* emu)
|
||||
{
|
||||
@@ -1880,6 +2038,7 @@ EXPORT void PltResolver(x86emu_t* emu)
|
||||
int slot = (int)Pop32(emu);
|
||||
elfheader_t *h = (elfheader_t*)addr;
|
||||
printf_dump(LOG_DEBUG, "PltResolver: Addr=%p, Slot=%d Return=%p: elf is %s (VerSym=%p)\n", (void*)addr, slot, *(void**)(R_ESP), h->name, h->VerSym);
|
||||
|
||||
Elf32_Rel * rel = (Elf32_Rel *)(h->jmprel + h->delta + slot);
|
||||
|
||||
Elf32_Sym *sym = &h->DynSym[ELF32_R_SYM(rel->r_info)];
|
||||
@@ -1894,11 +2053,15 @@ EXPORT void PltResolver(x86emu_t* emu)
|
||||
|
||||
library_t* lib = h->lib;
|
||||
lib_t* local_maplib = GetMaplib(lib);
|
||||
GetGlobalSymbolStartEnd(my_context->maplib, symname, &offs, &end, h, version, vername);
|
||||
if(!offs && !end && local_maplib)
|
||||
GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, h, version, vername);
|
||||
const char* globdefver = (bind==STB_WEAK)?NULL:GetMaplibDefaultVersion(my_context->maplib, (my_context->maplib==local_maplib)?NULL:local_maplib, 0, symname);
|
||||
const char* weakdefver = (bind==STB_WEAK)?GetMaplibDefaultVersion(my_context->maplib, (my_context->maplib==local_maplib)?NULL:local_maplib, 1, symname):NULL;
|
||||
GetGlobalSymbolStartEnd(my_context->maplib, symname, &offs, &end, h, version, vername, globdefver, weakdefver);
|
||||
if(!offs && !end && local_maplib) {
|
||||
GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, h, version, vername, globdefver, weakdefver);
|
||||
}
|
||||
if(!offs && !end && !version)
|
||||
GetGlobalSymbolStartEnd(my_context->maplib, symname, &offs, &end, h, -1, NULL);
|
||||
GetGlobalSymbolStartEnd(my_context->maplib, symname, &offs, &end, h, -1, NULL, globdefver, weakdefver);
|
||||
|
||||
|
||||
if (!offs) {
|
||||
printf_log(LOG_NONE, "Error: PltResolver: Symbol %s(ver %d: %s%s%s) not found, cannot apply R_386_JMP_SLOT %p (%p) in %s\n", symname, version, symname, vername?"@":"", vername?vername:"", p, *(void**)p, h->name);
|
||||
@@ -1910,6 +2073,7 @@ EXPORT void PltResolver(x86emu_t* emu)
|
||||
printf_dump(LOG_DEBUG, "symbol %s from %s but elf not initialized yet, run Init now (from %s)\n", symname, ElfName(sym_elf), ElfName(h));
|
||||
RunElfInitPltResolver(sym_elf, emu);
|
||||
}
|
||||
offs = (uintptr_t)getAlternate((void*)offs);
|
||||
|
||||
if(p) {
|
||||
printf_dump(LOG_DEBUG, " Apply %s R_386_JMP_SLOT %p with sym=%s(ver %d: %s%s%s) (%p -> %p / %s)\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), p, symname, version, symname, vername?"@":"", vername?vername:"",*(void**)p, (void*)offs, ElfName(FindElfAddress(my_context, offs)));
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
#ifndef __ELFLOADER_PRIVATE_H_
|
||||
#define __ELFLOADER_PRIVATE_H_
|
||||
|
||||
#ifdef DYNAREC
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
#endif
|
||||
|
||||
typedef struct library_s library_t;
|
||||
typedef struct needed_libs_s needed_libs_t;
|
||||
typedef struct kh_mapsymbols_s kh_mapsymbols_t;
|
||||
@@ -15,6 +11,7 @@ typedef struct kh_mapsymbols_s kh_mapsymbols_t;
|
||||
struct elfheader_s {
|
||||
char* name;
|
||||
char* path; // Resolved path to file
|
||||
char* soname; // soname of the elf
|
||||
uint16_t numPHEntries;
|
||||
Elf32_Phdr *PHEntries;
|
||||
uint16_t numSHEntries;
|
||||
@@ -38,6 +35,7 @@ struct elfheader_s {
|
||||
Elf32_Verdef* VerDef;
|
||||
int szVerDef;
|
||||
int e_type;
|
||||
uint32_t flags;
|
||||
|
||||
intptr_t delta; // should be 0
|
||||
|
||||
@@ -70,6 +68,9 @@ struct elfheader_s {
|
||||
int textsz;
|
||||
uintptr_t bss;
|
||||
int bsssz;
|
||||
uintptr_t ehframe;
|
||||
uintptr_t ehframe_end;
|
||||
uintptr_t ehframehdr;
|
||||
|
||||
uintptr_t paddr;
|
||||
uintptr_t vaddr;
|
||||
@@ -87,6 +88,8 @@ struct elfheader_s {
|
||||
|
||||
int init_done;
|
||||
int fini_done;
|
||||
int refcnt; // ref count for the elf
|
||||
int malloc_hook_2; // this elf hook malloc, hacking it
|
||||
|
||||
char* memory; // char* and not void* to allow math on memory pointer
|
||||
void** multiblock;
|
||||
@@ -95,11 +98,13 @@ struct elfheader_s {
|
||||
int multiblock_n;
|
||||
|
||||
library_t *lib;
|
||||
needed_libs_t *neededlibs;
|
||||
needed_libs_t *needed;
|
||||
|
||||
kh_mapsymbols_t *mapsymbols;
|
||||
kh_mapsymbols_t *weaksymbols;
|
||||
kh_mapsymbols_t *localsymbols;
|
||||
kh_defaultversion_t *globaldefver; // the global default version for symbols (the XXX@@vvvv of symbols)
|
||||
kh_defaultversion_t *weakdefver; // the weak default version for symbols (the XXX@@vvvv of symbols)
|
||||
};
|
||||
|
||||
#define R_386_NONE 0
|
||||
|
||||
@@ -273,6 +273,10 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
h->VerDef = (Elf32_Verdef*)ptr;
|
||||
printf_dump(LOG_DEBUG, "The DT_VERDEF is at address %p\n", h->VerDef);
|
||||
break;
|
||||
case DT_FLAGS:
|
||||
h->flags = val;
|
||||
printf_dump(LOG_DEBUG, "The DT_FLAGS is 0x%x\n", h->flags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(h->rel) {
|
||||
@@ -351,6 +355,17 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
h->bsssz = h->SHEntries[ii].sh_size;
|
||||
printf_dump(LOG_DEBUG, "The .bss is at address %p, and is %d big\n", (void*)h->bss, h->bsssz);
|
||||
}
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".eh_frame");
|
||||
if(ii) {
|
||||
h->ehframe = (uintptr_t)(h->SHEntries[ii].sh_addr);
|
||||
h->ehframe_end = h->ehframe + h->SHEntries[ii].sh_size;
|
||||
printf_dump(LOG_DEBUG, "The .eh_frame section is at address %p..%p\n", (void*)h->ehframe, (void*)h->ehframe_end);
|
||||
}
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".eh_frame_hdr");
|
||||
if(ii) {
|
||||
h->ehframehdr = (uintptr_t)(h->SHEntries[ii].sh_addr);
|
||||
printf_dump(LOG_DEBUG, "The .eh_frame_hdr section is at address %p\n", (void*)h->ehframehdr);
|
||||
}
|
||||
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynstr", "DynSym Strings", SHT_STRTAB, (void**)&h->DynStr, NULL);
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynsym", "DynSym", SHT_DYNSYM, (void**)&h->DynSym, &h->numDynSym);
|
||||
@@ -399,3 +414,59 @@ const char* GetParentSymbolVersion(elfheader_t* h, int index)
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int GetVersionIndice(elfheader_t* h, const char* vername)
|
||||
{
|
||||
if(!vername)
|
||||
return 0;
|
||||
if(h->VerDef) {
|
||||
Elf32_Verdef *def = (Elf32_Verdef*)((uintptr_t)h->VerDef + h->delta);
|
||||
while(def) {
|
||||
Elf32_Verdaux *aux = (Elf32_Verdaux*)((uintptr_t)def + def->vd_aux);
|
||||
if(!strcmp(h->DynStr+aux->vda_name, vername))
|
||||
return def->vd_ndx;
|
||||
def = def->vd_next?((Elf32_Verdef*)((uintptr_t)def + def->vd_next)):NULL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GetNeededVersionCnt(elfheader_t* h, const char* libname)
|
||||
{
|
||||
if(!libname)
|
||||
return 0;
|
||||
if(h->VerNeed) {
|
||||
Elf32_Verneed *ver = (Elf32_Verneed*)((uintptr_t)h->VerNeed + h->delta);
|
||||
while(ver) {
|
||||
char *filename = h->DynStr + ver->vn_file;
|
||||
Elf32_Vernaux *aux = (Elf32_Vernaux*)((uintptr_t)ver + ver->vn_aux);
|
||||
if(!strcmp(filename, libname))
|
||||
return ver->vn_cnt;
|
||||
ver = ver->vn_next?((Elf32_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* GetNeededVersionString(elfheader_t* h, const char* libname, int idx)
|
||||
{
|
||||
if(!libname)
|
||||
return 0;
|
||||
if(h->VerNeed) {
|
||||
Elf32_Verneed *ver = (Elf32_Verneed*)((uintptr_t)h->VerNeed + h->delta);
|
||||
while(ver) {
|
||||
char *filename = h->DynStr + ver->vn_file;
|
||||
Elf32_Vernaux *aux = (Elf32_Vernaux*)((uintptr_t)ver + ver->vn_aux);
|
||||
if(!strcmp(filename, libname)) {
|
||||
for(int j=0; j<ver->vn_cnt; ++j) {
|
||||
if(j==idx)
|
||||
return h->DynStr+aux->vna_name;
|
||||
aux = (Elf32_Vernaux*)((uintptr_t)aux + aux->vna_next);
|
||||
}
|
||||
return NULL; // idx out of bound, return NULL...
|
||||
}
|
||||
ver = ver->vn_next?((Elf32_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
+95
-1
@@ -1,3 +1,25 @@
|
||||
#include <string.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 F64S *(int64_t*)(addr+=8, addr-8)
|
||||
#define PK(a) *(uint8_t*)(addr+a)
|
||||
#ifdef DYNAREC
|
||||
#define STEP if(step) return 0;
|
||||
#define STEP2 if(step) {R_EIP = addr; return 0;}
|
||||
#define STEP3 if(*step) (*step)++;
|
||||
#else
|
||||
#define STEP
|
||||
#define STEP2
|
||||
#define STEP3
|
||||
#endif
|
||||
|
||||
// ModRM utilities macros
|
||||
#define getecommon(A, T) \
|
||||
if(!(nextop&0xC0)) { \
|
||||
@@ -85,7 +107,7 @@
|
||||
case 7: base = R_BX; break; \
|
||||
} \
|
||||
switch((m>>6)&3) { \
|
||||
case 0: if(m==6) base = F16; break; \
|
||||
case 0: if(m&7==6) base = F16S; break; \
|
||||
case 1: base += F8S; break; \
|
||||
case 2: base += F16S; break; \
|
||||
} \
|
||||
@@ -97,6 +119,17 @@
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = (reg32_t*)&emu->regs[(nextop&3)].byte[((nextop&0x4)>>2)]; \
|
||||
} else getecommon(A, reg32_t)
|
||||
#define testeb(A, O) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = (reg32_t*)&emu->regs[(nextop&3)].byte[((nextop&0x4)>>2)]; \
|
||||
} else { \
|
||||
reg32_t* ret; \
|
||||
getecommono(ret, reg32_t, O);\
|
||||
test->memsize = 1; \
|
||||
test->memaddr = (uintptr_t)ret;\
|
||||
test->mem[0] = ret->byte[0];\
|
||||
A = (reg32_t*)test->mem;\
|
||||
}
|
||||
#define getebo(A, O) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = (reg32_t*)&emu->regs[(nextop&3)].byte[((nextop&0x4)>>2)]; \
|
||||
@@ -109,14 +142,47 @@
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = &emu->regs[(nextop&7)]; \
|
||||
} else getecommono(A, reg32_t, O)
|
||||
#define tested(A, SZ, O) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = &emu->regs[(nextop&7)]; \
|
||||
} else {\
|
||||
reg32_t* ret; \
|
||||
getecommono(ret, reg32_t, O);\
|
||||
test->memsize = SZ; \
|
||||
test->memaddr = (uintptr_t)ret;\
|
||||
memcpy(test->mem, ret->dword, SZ);\
|
||||
A = (reg32_t*)test->mem;\
|
||||
}
|
||||
#define getem(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = &emu->mmx[(nextop&7)]; \
|
||||
} else getecommon(A, mmx87_regs_t)
|
||||
#define testem(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = &emu->mmx[(nextop&7)]; \
|
||||
} else {\
|
||||
mmx87_regs_t* ret; \
|
||||
getecommon(ret, mmx87_regs_t) \
|
||||
test->memsize = 8; \
|
||||
test->memaddr = (uintptr_t)ret;\
|
||||
memcpy(test->mem, ret->ub, 8);\
|
||||
A = (mmx87_regs_t*)test->mem;\
|
||||
}
|
||||
#define getex(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = &emu->xmm[(nextop&7)]; \
|
||||
} else getecommon(A, sse_regs_t)
|
||||
#define testex(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = &emu->xmm[(nextop&7)]; \
|
||||
} else {\
|
||||
sse_regs_t* ret; \
|
||||
getecommon(ret, sse_regs_t);\
|
||||
test->memsize = 16; \
|
||||
test->memaddr = (uintptr_t)ret;\
|
||||
memcpy(test->mem, ret->ub, 16);\
|
||||
A = (sse_regs_t*)test->mem;\
|
||||
}
|
||||
#define getew16(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = &emu->regs[(nextop&7)]; \
|
||||
@@ -125,16 +191,44 @@
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = &emu->regs[(nextop&7)]; \
|
||||
} else getecommon16o(A, reg32_t, O)
|
||||
#define testtew16(A, O) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = &emu->regs[(nextop&7)]; \
|
||||
} else { \
|
||||
reg32_t* ret; \
|
||||
getecommon16o(A, reg32_t, O); \
|
||||
test->memsize = 2; \
|
||||
test->memaddr = (uintptr_t)ret; \
|
||||
*(uint16_t*)test->mem = ret->word[0];\
|
||||
A = (reg32_t*)test->mem; \
|
||||
}
|
||||
|
||||
// Macros for ModR/M gets
|
||||
#ifdef TEST_INTERPRETER
|
||||
#define GET_EB testeb(oped, 0)
|
||||
#define GET_ED tested(oped, 4, 0)
|
||||
#define GET_ED8 tested(oped, 8, 0)
|
||||
#define GET_EDT tested(oped, 10, 0)
|
||||
#define GET_ED_OFFS(o) tested(oped, 4, o)
|
||||
#define GET_EB_OFFS(o) testeb(oped, o)
|
||||
#define GET_EM testem(opem)
|
||||
#define GET_EX testex(opex)
|
||||
#define GET_EW16 testew16(oped, 0)
|
||||
#define GET_EW16_OFFS(o) testtew16(oped, o)
|
||||
#else
|
||||
#define GET_EB geteb(oped)
|
||||
#define GET_ED geted(oped)
|
||||
#define GET_ED8 geted(oped)
|
||||
#define GET_EDT geted(oped)
|
||||
#define GET_ED_OFFS(o) getedo(oped, o)
|
||||
#define GET_EB_OFFS(o) getebo(oped, o)
|
||||
#define GET_EM getem(opem)
|
||||
#define GET_EX getex(opex)
|
||||
#define GET_EW16 getew16(oped)
|
||||
#define GET_EW16_OFFS(o) getew16o(oped, o)
|
||||
#endif
|
||||
#define GET_ED_ geted(oped)
|
||||
#define GET_EW16_ getew16(oped)
|
||||
#define EB oped
|
||||
#define ED oped
|
||||
#define EM opem
|
||||
|
||||
-555
@@ -1,555 +0,0 @@
|
||||
opcode = F8;
|
||||
goto *opcodes66[opcode];
|
||||
|
||||
#define GO(B, OP) \
|
||||
_66_##B##_0: \
|
||||
nextop = F8; \
|
||||
GET_EB; \
|
||||
EB->byte[0] = OP##8(emu, EB->byte[0], GB); \
|
||||
NEXT; \
|
||||
_66_##B##_1: \
|
||||
nextop = F8; \
|
||||
GET_EW; \
|
||||
EW->word[0] = OP##16(emu, EW->word[0], GW.word[0]); \
|
||||
NEXT; \
|
||||
_66_##B##_2: \
|
||||
nextop = F8; \
|
||||
GET_EB; \
|
||||
GB = OP##8(emu, GB, EB->byte[0]); \
|
||||
NEXT; \
|
||||
_66_##B##_3: \
|
||||
nextop = F8; \
|
||||
GET_EW; \
|
||||
GW.word[0] = OP##16(emu, GW.word[0], EW->word[0]); \
|
||||
NEXT; \
|
||||
_66_##B##_4: \
|
||||
R_AL = OP##8(emu, R_AL, F8); \
|
||||
NEXT; \
|
||||
_66_##B##_5: \
|
||||
R_AX = OP##16(emu, R_AX, F16); \
|
||||
NEXT;
|
||||
|
||||
GO(0x00, add) /* ADD 0x01 ~> 0x05 */
|
||||
GO(0x08, or) /* OR 0x09 ~> 0x0D */
|
||||
GO(0x10, adc) /* ADC 0x11 ~> 0x15 */
|
||||
GO(0x18, sbb) /* SBB 0x19 ~> 0x1D */
|
||||
GO(0x20, and) /* AND 0x21 ~> 0x25 */
|
||||
GO(0x28, sub) /* SUB 0x29 ~> 0x2D */
|
||||
GO(0x30, xor) /* XOR 0x31 ~> 0x35 */
|
||||
//GO(0x38, cmp) /* CMP 0x39 ~> 0x3D */
|
||||
#undef GO
|
||||
_66_0x06: /* PUSH ES */
|
||||
Push16(emu, emu->segs[_ES]);
|
||||
NEXT;
|
||||
_66_0x07: /* POP ES */
|
||||
emu->segs[_ES] = Pop16(emu); // no check, no use....
|
||||
emu->segs_serial[_ES] = 0;
|
||||
NEXT;
|
||||
|
||||
_66_0x0F: /* 66 0f prefix */
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip-2; // don't count 66 0F yet
|
||||
Run660F(emu); // implemented in Run660f.c
|
||||
ip = R_EIP;
|
||||
if(emu->quit) goto fini;
|
||||
STEP
|
||||
NEXT;
|
||||
|
||||
_66_0x1E: /* PUSH DS */
|
||||
Push16(emu, emu->segs[_DS]);
|
||||
NEXT;
|
||||
_66_0x1F: /* POP DS */
|
||||
emu->segs[_DS] = Pop16(emu); // no check, no use....
|
||||
emu->segs_serial[_DS] = 0;
|
||||
NEXT;
|
||||
|
||||
_66_0x26: /* ES: */
|
||||
// ignored
|
||||
opcode = F8;
|
||||
goto *opcodes66[opcode];
|
||||
_66_0x2E: /* CS: */
|
||||
// ignored
|
||||
opcode = F8;
|
||||
goto *opcodes66[opcode];
|
||||
_66_0x36: /* SS: */
|
||||
// ignored
|
||||
opcode = F8;
|
||||
goto *opcodes66[opcode];
|
||||
|
||||
_66_0x39:
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
cmp16(emu, EW->word[0], GW.word[0]);
|
||||
NEXT;
|
||||
_66_0x3B:
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
cmp16(emu, GW.word[0], EW->word[0]);
|
||||
NEXT;
|
||||
_66_0x3D:
|
||||
cmp16(emu, R_AX, F16);
|
||||
NEXT;
|
||||
_66_0x3E: /* DS: */
|
||||
// ignored
|
||||
opcode = F8;
|
||||
goto *opcodes66[opcode];
|
||||
|
||||
_66_0x40:
|
||||
_66_0x41:
|
||||
_66_0x42:
|
||||
_66_0x43:
|
||||
_66_0x44:
|
||||
_66_0x45:
|
||||
_66_0x46:
|
||||
_66_0x47: /* INC Reg */
|
||||
tmp8u = opcode&7;
|
||||
emu->regs[tmp8u].word[0] = inc16(emu, emu->regs[tmp8u].word[0]);
|
||||
NEXT;
|
||||
_66_0x48:
|
||||
_66_0x49:
|
||||
_66_0x4A:
|
||||
_66_0x4B:
|
||||
_66_0x4C:
|
||||
_66_0x4D:
|
||||
_66_0x4E:
|
||||
_66_0x4F: /* DEC Reg */
|
||||
tmp8u = opcode&7;
|
||||
emu->regs[tmp8u].word[0] = dec16(emu, emu->regs[tmp8u].word[0]);
|
||||
NEXT;
|
||||
_66_0x50:
|
||||
_66_0x51:
|
||||
_66_0x52:
|
||||
_66_0x53:
|
||||
_66_0x54:
|
||||
_66_0x55:
|
||||
_66_0x56:
|
||||
_66_0x57: /* PUSH Reg */
|
||||
tmp8u = opcode&7;
|
||||
Push16(emu, emu->regs[tmp8u].word[0]);
|
||||
NEXT;
|
||||
_66_0x58:
|
||||
_66_0x59:
|
||||
_66_0x5A:
|
||||
_66_0x5B:
|
||||
_66_0x5C:
|
||||
_66_0x5D:
|
||||
_66_0x5E:
|
||||
_66_0x5F: /* POP Reg */
|
||||
tmp8u = opcode&7;
|
||||
emu->regs[tmp8u].word[0] = Pop16(emu);
|
||||
NEXT;
|
||||
_66_0x60: /* PUSHA */
|
||||
tmp16u = R_SP;
|
||||
Push16(emu, R_AX);
|
||||
Push16(emu, R_CX);
|
||||
Push16(emu, R_DX);
|
||||
Push16(emu, R_BX);
|
||||
Push16(emu, tmp16u);
|
||||
Push16(emu, R_BP);
|
||||
Push16(emu, R_SI);
|
||||
Push16(emu, R_DI);
|
||||
NEXT;
|
||||
_66_0x61: /* POPA */
|
||||
R_DI = Pop16(emu);
|
||||
R_SI = Pop16(emu);
|
||||
R_BP = Pop16(emu);
|
||||
R_ESP+=2; // POP ESP
|
||||
R_BX = Pop16(emu);
|
||||
R_DX = Pop16(emu);
|
||||
R_CX = Pop16(emu);
|
||||
R_AX = Pop16(emu);
|
||||
NEXT;
|
||||
|
||||
_66_0x64:
|
||||
R_EIP = ip-2;
|
||||
RunFS66(emu, GetFSBaseEmu(emu));
|
||||
ip = R_EIP;
|
||||
STEP;
|
||||
NEXT;
|
||||
|
||||
_66_0x66:
|
||||
goto _0x66; // 0x66 0x66 => can remove one 0x66
|
||||
|
||||
_66_0x68: /* PUSH u16 */
|
||||
tmp16u = F16;
|
||||
Push16(emu, tmp16u);
|
||||
NEXT;
|
||||
_66_0x69: /* IMUL Gw,Ew,Iw */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
tmp16u = F16;
|
||||
GW.word[0] = imul16(emu, EW->word[0], tmp16u);
|
||||
NEXT;
|
||||
_66_0x6A: /* PUSH Ib (as signed word) */
|
||||
tmp16s = F8S;
|
||||
Push16(emu, (uint16_t)tmp16s);
|
||||
NEXT;
|
||||
_66_0x6B: /* IMUL Gw,Ew,Ib */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
tmp16s = F8S;
|
||||
GW.word[0] = imul16(emu, EW->word[0], (uint16_t)tmp16s);
|
||||
NEXT;
|
||||
|
||||
_66_0x81: /* GRP3 Ew,Iw */
|
||||
_66_0x83: /* GRP3 Ew,Ib */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
if(opcode==0x81)
|
||||
tmp16u = F16;
|
||||
else {
|
||||
tmp16s = F8S;
|
||||
tmp16u = (uint16_t)tmp16s;
|
||||
}
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: EW->word[0] = add16(emu, EW->word[0], tmp16u); break;
|
||||
case 1: EW->word[0] = or16(emu, EW->word[0], tmp16u); break;
|
||||
case 2: EW->word[0] = adc16(emu, EW->word[0], tmp16u); break;
|
||||
case 3: EW->word[0] = sbb16(emu, EW->word[0], tmp16u); break;
|
||||
case 4: EW->word[0] = and16(emu, EW->word[0], tmp16u); break;
|
||||
case 5: EW->word[0] = sub16(emu, EW->word[0], tmp16u); break;
|
||||
case 6: EW->word[0] = xor16(emu, EW->word[0], tmp16u); break;
|
||||
case 7: cmp16(emu, EW->word[0], tmp16u); break;
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_66_0x85: /* TEST Ew,Gw */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
test16(emu, EW->word[0], GW.word[0]);
|
||||
NEXT;
|
||||
|
||||
_66_0x87: /* XCHG Ew,Gw */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
tmp16u = GW.word[0];
|
||||
GW.word[0] = EW->word[0];
|
||||
EW->word[0] = tmp16u;
|
||||
NEXT;
|
||||
|
||||
_66_0x89: /* MOV Ew,Gw */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
EW->word[0] = GW.word[0];
|
||||
NEXT;
|
||||
|
||||
_66_0x8B: /* MOV Gw,Ew */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
GW.word[0] = EW->word[0];
|
||||
NEXT;
|
||||
_66_0x8C: /* MOV Ew,Seg */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
EW->word[0] = emu->segs[(nextop&0x38)>>3];
|
||||
NEXT;
|
||||
|
||||
_66_0x8E: /* MOV Seg,Ew */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
emu->segs[((nextop&0x38)>>3)] = EW->word[0];
|
||||
emu->segs_serial[((nextop&0x38)>>3)] = 0;
|
||||
NEXT;
|
||||
_66_0x8F: /* POP Ew */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
EW->word[0] = Pop16(emu);
|
||||
NEXT;
|
||||
_66_0x90: /* NOP */
|
||||
NEXT;
|
||||
|
||||
_66_0x91:
|
||||
_66_0x92:
|
||||
_66_0x93:
|
||||
_66_0x94:
|
||||
_66_0x95:
|
||||
_66_0x96:
|
||||
_66_0x97: /* XCHG reg,EAX */
|
||||
tmp16u = R_AX;
|
||||
R_AX = emu->regs[opcode&7].word[0];
|
||||
emu->regs[opcode&7].word[0] = tmp16u;
|
||||
NEXT;
|
||||
|
||||
_66_0x98: /* CBW */
|
||||
emu->regs[_AX].sword[0] = emu->regs[_AX].sbyte[0];
|
||||
NEXT;
|
||||
_66_0x99: /* CWD */
|
||||
R_DX=((R_AX & 0x8000)?0xFFFF:0x0000);
|
||||
NEXT;
|
||||
|
||||
_66_0x9C: /* PUSHFW */
|
||||
CHECK_FLAGS(emu);
|
||||
Push16(emu, (uint16_t)emu->eflags.x32);
|
||||
NEXT;
|
||||
_66_0x9D: /* POPFW */
|
||||
CHECK_FLAGS(emu);
|
||||
emu->eflags.x32 &=0xffff0000;
|
||||
emu->eflags.x32 |= (Pop16(emu) & 0x3F7FD7) | 0x2;
|
||||
NEXT;
|
||||
|
||||
_66_0xA1: /* MOV AX,Ow */
|
||||
R_AX = *(uint16_t*)F32;
|
||||
NEXT;
|
||||
_66_0xA3: /* MOV Ow,AX */
|
||||
*(uint16_t*)F32 = R_AX;
|
||||
NEXT;
|
||||
_66_0xA5: /* MOVSW */
|
||||
tmp8s = ACCESS_FLAG(F_DF)?-2:+2;
|
||||
*(uint16_t*)R_EDI = *(uint16_t*)R_ESI;
|
||||
R_EDI += tmp8s;
|
||||
R_ESI += tmp8s;
|
||||
NEXT;
|
||||
|
||||
_66_0xA7: /* CMPSW */
|
||||
tmp8s = ACCESS_FLAG(F_DF)?-2:+2;
|
||||
tmp16u = *(uint16_t*)R_EDI;
|
||||
tmp16u2 = *(uint16_t*)R_ESI;
|
||||
R_EDI += tmp8s;
|
||||
R_ESI += tmp8s;
|
||||
cmp16(emu, tmp16u2, tmp16u);
|
||||
NEXT;
|
||||
|
||||
_66_0xA9: /* TEST AX,Iw */
|
||||
test16(emu, R_AX, F16);
|
||||
NEXT;
|
||||
|
||||
_66_0xAB: /* STOSW */
|
||||
tmp8s = ACCESS_FLAG(F_DF)?-2:+2;
|
||||
*(uint16_t*)R_EDI = R_AX;
|
||||
R_EDI += tmp8s;
|
||||
NEXT;
|
||||
_66_0xAD: /* LODSW */
|
||||
tmp8s = ACCESS_FLAG(F_DF)?-2:+2;
|
||||
R_AX = *(uint16_t*)R_ESI;
|
||||
R_ESI += tmp8s;
|
||||
NEXT;
|
||||
_66_0xAF: /* SCASW */
|
||||
tmp8s = ACCESS_FLAG(F_DF)?-2:+2;
|
||||
cmp16(emu, R_AX, *(uint16_t*)R_EDI);
|
||||
R_EDI += tmp8s;
|
||||
NEXT;
|
||||
|
||||
_66_0xB8: /* MOV AX,Iw */
|
||||
_66_0xB9: /* MOV CX,Iw */
|
||||
_66_0xBA: /* MOV DX,Iw */
|
||||
_66_0xBB: /* MOV BX,Iw */
|
||||
_66_0xBC: /* ... */
|
||||
_66_0xBD:
|
||||
_66_0xBE:
|
||||
_66_0xBF:
|
||||
emu->regs[opcode&7].word[0] = F16;
|
||||
NEXT;
|
||||
|
||||
_66_0xC1: /* GRP2 Ew,Ib */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
tmp8u = F8 /*& 0x1f*/;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: EW->word[0] = rol16(emu, EW->word[0], tmp8u); break;
|
||||
case 1: EW->word[0] = ror16(emu, EW->word[0], tmp8u); break;
|
||||
case 2: EW->word[0] = rcl16(emu, EW->word[0], tmp8u); break;
|
||||
case 3: EW->word[0] = rcr16(emu, EW->word[0], tmp8u); break;
|
||||
case 4:
|
||||
case 6: EW->word[0] = shl16(emu, EW->word[0], tmp8u); break;
|
||||
case 5: EW->word[0] = shr16(emu, EW->word[0], tmp8u); break;
|
||||
case 7: EW->word[0] = sar16(emu, EW->word[0], tmp8u); break;
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_66_0xC7: /* MOV Ew,Iw */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
EW->word[0] = F16;
|
||||
NEXT;
|
||||
|
||||
_66_0xCB: /* FAR RET */
|
||||
ip = Pop(emu);
|
||||
emu->segs[_CS] = Pop(emu); // no check, no use....
|
||||
emu->segs_serial[_CS] = 0;
|
||||
// need to check status of CS register!
|
||||
STEP
|
||||
NEXT;
|
||||
_66_0xCC: /* INT3 */
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip-1;
|
||||
if(my_context->signals[SIGTRAP])
|
||||
raise(SIGTRAP);
|
||||
ip = R_EIP;
|
||||
if(emu->quit) goto fini;
|
||||
STEP
|
||||
NEXT;
|
||||
_66_0xD1: /* GRP2 Ew,1 */
|
||||
_66_0xD3: /* GRP2 Ew,CL */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
tmp8u=(opcode==0xD3)?R_CL:1;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: EW->word[0] = rol16(emu, EW->word[0], tmp8u); break;
|
||||
case 1: EW->word[0] = ror16(emu, EW->word[0], tmp8u); break;
|
||||
case 2: EW->word[0] = rcl16(emu, EW->word[0], tmp8u); break;
|
||||
case 3: EW->word[0] = rcr16(emu, EW->word[0], tmp8u); break;
|
||||
case 4:
|
||||
case 6: EW->word[0] = shl16(emu, EW->word[0], tmp8u); break;
|
||||
case 5: EW->word[0] = shr16(emu, EW->word[0], tmp8u); break;
|
||||
case 7: EW->word[0] = sar16(emu, EW->word[0], tmp8u); break;
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_66_0xD9:
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip;
|
||||
Run66D9(emu);
|
||||
ip = R_EIP;
|
||||
if(emu->quit) goto fini;
|
||||
STEP
|
||||
NEXT;
|
||||
|
||||
_66_0xDD:
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip;
|
||||
Run66DD(emu);
|
||||
ip = R_EIP;
|
||||
if(emu->quit) goto fini;
|
||||
STEP
|
||||
NEXT;
|
||||
|
||||
_66_0xF0: /* LOCK prefix */
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip - 2;
|
||||
RunLock66(emu);
|
||||
ip = R_EIP;
|
||||
if(emu->quit) goto fini;
|
||||
STEP
|
||||
NEXT;
|
||||
|
||||
_66_0xF2: /* REPNZ prefix */
|
||||
_66_0xF3: /* REPZ prefix */
|
||||
nextop = F8;
|
||||
tmp8s = ACCESS_FLAG(F_DF)?-2:+2;
|
||||
tmp32u = R_ECX;
|
||||
switch(nextop) {
|
||||
case 0xA4: /* REP MOVSB */
|
||||
while(tmp32u) {
|
||||
--tmp32u;
|
||||
*(uint8_t*)R_EDI = *(uint8_t*)R_ESI;
|
||||
R_EDI += tmp8s;
|
||||
R_ESI += tmp8s;
|
||||
}
|
||||
break;
|
||||
case 0xA5: /* REP MOVSW */
|
||||
while(tmp32u) {
|
||||
--tmp32u;
|
||||
*(uint16_t*)R_EDI = *(uint16_t*)R_ESI;
|
||||
R_EDI += tmp8s;
|
||||
R_ESI += tmp8s;
|
||||
}
|
||||
break;
|
||||
case 0xA7: /* REP(N)Z CMPSW */
|
||||
tmp16u = 0;
|
||||
tmp16u2 = 0;
|
||||
while(tmp32u) {
|
||||
--tmp32u;
|
||||
tmp16u = *(uint16_t*)R_EDI;
|
||||
tmp16u2 = *(uint16_t*)R_ESI;
|
||||
R_EDI += tmp8s;
|
||||
R_ESI += tmp8s;
|
||||
if((tmp16u==tmp16u2)==(opcode==0xF2))
|
||||
break;
|
||||
}
|
||||
if(R_ECX) cmp16(emu, tmp16u2, tmp16u);
|
||||
break;
|
||||
case 0xAB: /* REP STOSW */
|
||||
while(tmp32u) {
|
||||
--tmp32u;
|
||||
*(uint16_t*)R_EDI = R_AX;
|
||||
R_EDI += tmp8s;
|
||||
}
|
||||
break;
|
||||
case 0xAD: /* REP LODSW */
|
||||
while(tmp32u) {
|
||||
--tmp32u;
|
||||
R_AX = *(uint16_t*)R_ESI;
|
||||
R_ESI += tmp8s;
|
||||
}
|
||||
break;
|
||||
case 0xAF: /* REP(N)Z SCASW */
|
||||
tmp16u = 0;
|
||||
while(tmp32u) {
|
||||
--tmp32u;
|
||||
tmp16u = *(uint16_t*)R_EDI;
|
||||
R_EDI += tmp8s;
|
||||
if((R_AX==tmp16u)==(opcode==0xF2))
|
||||
break;
|
||||
}
|
||||
if(R_ECX) cmp16(emu, R_AX, tmp16u);
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
}
|
||||
R_ECX = tmp32u;
|
||||
NEXT;
|
||||
|
||||
_66_0xF5: /* CMC */
|
||||
CHECK_FLAGS(emu);
|
||||
CONDITIONAL_SET_FLAG(!ACCESS_FLAG(F_CF), F_CF);
|
||||
NEXT;
|
||||
|
||||
_66_0xF7: /* GRP3 Ew(,Iw) */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
case 1: /* TEST Ew,Iw */
|
||||
test16(emu, EW->word[0], F16);
|
||||
break;
|
||||
case 2: /* NOT Ew */
|
||||
EW->word[0] = not16(emu, EW->word[0]);
|
||||
break;
|
||||
case 3: /* NEG Ew */
|
||||
EW->word[0] = neg16(emu, EW->word[0]);
|
||||
break;
|
||||
case 4: /* MUL AX,Ew */
|
||||
mul16(emu, EW->word[0]);
|
||||
break;
|
||||
case 5: /* IMUL AX,Ew */
|
||||
imul16_eax(emu, EW->word[0]);
|
||||
break;
|
||||
case 6: /* DIV Ew */
|
||||
div16(emu, EW->word[0]);
|
||||
break;
|
||||
case 7: /* IDIV Ew */
|
||||
idiv16(emu, EW->word[0]);
|
||||
break;
|
||||
}
|
||||
NEXT;
|
||||
_66_0xF8: /* CLC */
|
||||
CHECK_FLAGS(emu);
|
||||
CLEAR_FLAG(F_CF);
|
||||
NEXT;
|
||||
_66_0xF9: /* STC */
|
||||
CHECK_FLAGS(emu);
|
||||
SET_FLAG(F_CF);
|
||||
NEXT;
|
||||
|
||||
_66_0xFF: /* GRP 5 Ew */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* INC Ed */
|
||||
EW->word[0] = inc16(emu, EW->word[0]);
|
||||
break;
|
||||
case 1: /* DEC Ed */
|
||||
EW->word[0] = dec16(emu, EW->word[0]);
|
||||
break;
|
||||
case 6:
|
||||
Push16(emu, EW->word[0]);
|
||||
break;
|
||||
default:
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip;
|
||||
printf_log(LOG_NONE, "Illegal Opcode 66 %02X %02X\n", opcode, nextop);
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
goto fini;
|
||||
}
|
||||
NEXT;
|
||||
+39
-13
@@ -54,17 +54,6 @@ uint32_t* GetParityTab()
|
||||
return x86emu_parity_tab;
|
||||
}
|
||||
|
||||
void PushExit(x86emu_t* emu)
|
||||
{
|
||||
uintptr_t endMarker = AddCheckBridge(my_context->system, NULL, NULL, 0, "(ExitEmulation)");
|
||||
Push(emu, endMarker);
|
||||
}
|
||||
|
||||
void* GetExit()
|
||||
{
|
||||
return (void*)AddCheckBridge(my_context->system, NULL, NULL, 0, "(ExitEmulation)");
|
||||
}
|
||||
|
||||
static void internalX86Setup(x86emu_t* emu, box86context_t *context, uintptr_t start, uintptr_t stack, int stacksize, int ownstack)
|
||||
{
|
||||
emu->context = context;
|
||||
@@ -198,6 +187,11 @@ void FreeX86Emu(x86emu_t **emu)
|
||||
return;
|
||||
printf_log(LOG_DEBUG, "%04d|Free a X86 Emu (%p)\n", GetTID(), *emu);
|
||||
|
||||
if((*emu)->test.emu) {
|
||||
internalFreeX86((*emu)->test.emu);
|
||||
box_free((*emu)->test.emu);
|
||||
(*emu)->test.emu = NULL;
|
||||
}
|
||||
internalFreeX86(*emu);
|
||||
|
||||
box_free(*emu);
|
||||
@@ -231,6 +225,10 @@ void CloneEmu(x86emu_t *newemu, const x86emu_t* emu)
|
||||
newemu->top = emu->top;
|
||||
newemu->fpu_stack = emu->fpu_stack;
|
||||
memcpy(newemu->xmm, emu->xmm, sizeof(emu->xmm));
|
||||
newemu->df = emu->df;
|
||||
newemu->op1 = emu->op1;
|
||||
newemu->op2 = emu->op2;
|
||||
newemu->res = emu->res;
|
||||
newemu->mxcsr = emu->mxcsr;
|
||||
newemu->quit = emu->quit;
|
||||
newemu->error = emu->error;
|
||||
@@ -240,6 +238,34 @@ void CloneEmu(x86emu_t *newemu, const x86emu_t* emu)
|
||||
newemu->regs[_SP].dword[0] = emu->regs[_SP].dword[0] + (intptr_t)(newst - oldst);
|
||||
}
|
||||
|
||||
void CopyEmu(x86emu_t *newemu, const x86emu_t* emu)
|
||||
{
|
||||
memcpy(newemu->regs, emu->regs, sizeof(emu->regs));
|
||||
memcpy(&newemu->ip, &emu->ip, sizeof(emu->ip));
|
||||
memcpy(&newemu->eflags, &emu->eflags, sizeof(emu->eflags));
|
||||
newemu->old_ip = emu->old_ip;
|
||||
memcpy(newemu->segs, emu->segs, sizeof(emu->segs));
|
||||
memcpy(newemu->segs_serial, emu->segs_serial, sizeof(emu->segs_serial));
|
||||
memcpy(newemu->segs_offs, emu->segs_offs, sizeof(emu->segs_offs));
|
||||
memcpy(newemu->x87, emu->x87, sizeof(emu->x87));
|
||||
memcpy(newemu->mmx, emu->mmx, sizeof(emu->mmx));
|
||||
memcpy(newemu->xmm, emu->xmm, sizeof(emu->xmm));
|
||||
memcpy(newemu->fpu_ld, emu->fpu_ld, sizeof(emu->fpu_ld));
|
||||
memcpy(newemu->fpu_ll, emu->fpu_ll, sizeof(emu->fpu_ll));
|
||||
memcpy(newemu->p_regs, emu->p_regs, sizeof(emu->p_regs));
|
||||
newemu->cw = emu->cw;
|
||||
newemu->sw = emu->sw;
|
||||
newemu->top = emu->top;
|
||||
newemu->fpu_stack = emu->fpu_stack;
|
||||
newemu->df = emu->df;
|
||||
newemu->op1 = emu->op1;
|
||||
newemu->op2 = emu->op2;
|
||||
newemu->res = emu->res;
|
||||
newemu->mxcsr = emu->mxcsr;
|
||||
newemu->quit = emu->quit;
|
||||
newemu->error = emu->error;
|
||||
}
|
||||
|
||||
box86context_t* GetEmuContext(x86emu_t* emu)
|
||||
{
|
||||
return emu->context;
|
||||
@@ -311,7 +337,7 @@ void ResetFlags(x86emu_t *emu)
|
||||
const char* DumpCPURegs(x86emu_t* emu, uintptr_t ip)
|
||||
{
|
||||
static char buff[800];
|
||||
char* regname[] = {"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"};
|
||||
static const char* regname[] = {"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"};
|
||||
char tmp[80];
|
||||
buff[0] = '\0';
|
||||
if(trace_emm) {
|
||||
@@ -475,8 +501,8 @@ uint64_t ReadTSC(x86emu_t* emu)
|
||||
uint64_t ret;
|
||||
__asm__ volatile("rdtsc" : "=A"(ret));
|
||||
return ret;
|
||||
#if 0
|
||||
#elif defined(__ARM_ARCH)
|
||||
#if 0
|
||||
#if (__ARM_ARCH >= 6)
|
||||
static int init = 1;
|
||||
if(init) {
|
||||
|
||||
@@ -23,6 +23,17 @@ typedef struct forkpty_s {
|
||||
void* f; // forkpty function
|
||||
} forkpty_t;
|
||||
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
|
||||
typedef struct x86test_s {
|
||||
x86emu_t* emu;
|
||||
uintptr_t memaddr;
|
||||
int memsize;
|
||||
int test;
|
||||
int clean;
|
||||
uint8_t mem[16];
|
||||
} x86test_t;
|
||||
|
||||
typedef struct x86emu_s {
|
||||
// cpu
|
||||
reg32_t regs[8];
|
||||
@@ -63,6 +74,7 @@ typedef struct x86emu_s {
|
||||
int exit;
|
||||
int quitonlongjmp; // quit if longjmp is called
|
||||
int longjmp; // if quit because of longjmp
|
||||
x86test_t test; // used for dynarec testing
|
||||
// parent context
|
||||
box86context_t *context;
|
||||
// cpu helpers
|
||||
|
||||
+970
-1037
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,459 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
#include "bridge.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t Test64(x86test_t *test, int seg, uintptr_t addr)
|
||||
#else
|
||||
uintptr_t Run64(x86emu_t *emu, int seg, uintptr_t addr)
|
||||
#endif
|
||||
{
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
reg32_t *oped;
|
||||
uint8_t tmp8u;
|
||||
uint32_t tmp32u;
|
||||
int32_t tmp32s;
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t* emu = test->emu;
|
||||
#endif
|
||||
uintptr_t tlsdata = (seg==_FS)?GetFSBaseEmu(emu):GetGSBaseEmu(emu);
|
||||
switch(opcode) {
|
||||
case 0x01: /* ADD GS:Ed, Gd */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
ED->dword[0] = add32(emu, ED->dword[0], GD.dword[0]);
|
||||
break;
|
||||
|
||||
case 0x03: /* ADD Gd, GS:Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
GD.dword[0] = add32(emu, GD.dword[0], ED->dword[0]);
|
||||
break;
|
||||
|
||||
case 0x06: /* PUSH ES */
|
||||
Push(emu, emu->segs[_ES]);
|
||||
break;
|
||||
case 0x07: /* POP ES */
|
||||
emu->segs[_ES] = Pop(emu);
|
||||
emu->segs_serial[_ES] = 0;
|
||||
break;
|
||||
|
||||
case 0x0f:
|
||||
#ifdef TEST_INTERPRETER
|
||||
return Test640F(test, tlsdata, addr);
|
||||
#else
|
||||
return Run640F(emu, tlsdata, addr);
|
||||
#endif
|
||||
|
||||
case 0x11: /* ADC GS:Ed, Gd */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
ED->dword[0] = adc32(emu, ED->dword[0], GD.dword[0]);
|
||||
break;
|
||||
|
||||
case 0x13: /* ADC Gd, GS:Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
GD.dword[0] = adc32(emu, GD.dword[0], ED->dword[0]);
|
||||
break;
|
||||
|
||||
case 0x21: /* AND Ed,Gd */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
ED->dword[0] = and32(emu, ED->dword[0], GD.dword[0]);
|
||||
break;
|
||||
|
||||
case 0x23: /* AND Gd,Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
GD.dword[0] = and32(emu, GD.dword[0], ED->dword[0]);
|
||||
break;
|
||||
|
||||
case 0x29: /* SUB GS:Ed, Gd */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
ED->dword[0] = sub32(emu, ED->dword[0], GD.dword[0]);
|
||||
break;
|
||||
|
||||
case 0x2B: /* SUB Gd, GS:Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
GD.dword[0] = sub32(emu, GD.dword[0], ED->dword[0]);
|
||||
break;
|
||||
|
||||
case 0x31: /* XOR Ed,Gd */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
ED->dword[0] = xor32(emu, ED->dword[0], GD.dword[0]);
|
||||
break;
|
||||
|
||||
case 0x33: /* XOR Gd,Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
GD.dword[0] = xor32(emu, GD.dword[0], ED->dword[0]);
|
||||
break;
|
||||
|
||||
case 0x39: /* CMP Ed,Gd */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
cmp32(emu, ED->dword[0], GD.dword[0]);
|
||||
break;
|
||||
|
||||
case 0x3B: /* CMP Gd,Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
cmp32(emu, GD.dword[0], ED->dword[0]);
|
||||
break;
|
||||
|
||||
case 0x40:
|
||||
case 0x41:
|
||||
case 0x42:
|
||||
case 0x43:
|
||||
case 0x44:
|
||||
case 0x45:
|
||||
case 0x46:
|
||||
case 0x47: /* INC Reg */
|
||||
tmp8u = opcode&7;
|
||||
emu->regs[tmp8u].dword[0] = inc32(emu, emu->regs[tmp8u].dword[0]);
|
||||
break;
|
||||
case 0x48:
|
||||
case 0x49:
|
||||
case 0x4A:
|
||||
case 0x4B:
|
||||
case 0x4C:
|
||||
case 0x4D:
|
||||
case 0x4E:
|
||||
case 0x4F: /* DEC Reg */
|
||||
tmp8u = opcode&7;
|
||||
emu->regs[tmp8u].dword[0] = dec32(emu, emu->regs[tmp8u].dword[0]);
|
||||
break;
|
||||
case 0x50: /* PUSH Reg */
|
||||
case 0x51:
|
||||
case 0x52:
|
||||
case 0x53:
|
||||
case 0x54: /* PUSH ESP */
|
||||
case 0x55:
|
||||
case 0x56:
|
||||
case 0x57:
|
||||
case 0x58: /* POP Reg */
|
||||
case 0x59:
|
||||
case 0x5A:
|
||||
case 0x5B:
|
||||
case 0x5C: /* POP ESP */
|
||||
case 0x5D:
|
||||
case 0x5E:
|
||||
case 0x5F:
|
||||
// Segment override if for memory loc, no stack segment
|
||||
return addr-1;
|
||||
|
||||
case 0x64: /* FS: */
|
||||
// so just ignore that GS: prefix then
|
||||
#ifdef TEST_INTERPRETER
|
||||
return Test64(test, _FS, addr-1); // put FS back
|
||||
#else
|
||||
return Run64(emu, _FS, addr-1); // put FS back
|
||||
#endif
|
||||
|
||||
case 0x66:
|
||||
#ifdef TEST_INTERPRETER
|
||||
return Test6466(test, tlsdata, addr);
|
||||
#else
|
||||
return Run6466(emu, tlsdata, addr);
|
||||
#endif
|
||||
case 0x67:
|
||||
#ifdef TEST_INTERPRETER
|
||||
return Test6467(test, tlsdata, addr);
|
||||
#else
|
||||
return Run6467(emu, tlsdata, addr);
|
||||
#endif
|
||||
|
||||
case 0x69: /* IMUL Gd,Ed,Id */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
tmp32u = F32;
|
||||
GD.dword[0] = imul32(emu, ED->dword[0], tmp32u);
|
||||
break;
|
||||
|
||||
case 0x70:
|
||||
case 0x71:
|
||||
case 0x72:
|
||||
case 0x73:
|
||||
case 0x74:
|
||||
case 0x75:
|
||||
case 0x76:
|
||||
case 0x77:
|
||||
case 0x78:
|
||||
case 0x79:
|
||||
case 0x7A:
|
||||
case 0x7B:
|
||||
case 0x7C:
|
||||
case 0x7D:
|
||||
case 0x7E:
|
||||
case 0x7F:
|
||||
// just ignore the prefix
|
||||
return addr-1;
|
||||
case 0x80: /* GRP Eb,Ib */
|
||||
case 0x82: // 0x82 and 0x80 are the same opcodes it seems?
|
||||
nextop = F8;
|
||||
GET_EB_OFFS(tlsdata);
|
||||
tmp8u = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: EB->byte[0] = add8(emu, EB->byte[0], tmp8u); break;
|
||||
case 1: EB->byte[0] = or8(emu, EB->byte[0], tmp8u); break;
|
||||
case 2: EB->byte[0] = adc8(emu, EB->byte[0], tmp8u); break;
|
||||
case 3: EB->byte[0] = sbb8(emu, EB->byte[0], tmp8u); break;
|
||||
case 4: EB->byte[0] = and8(emu, EB->byte[0], tmp8u); break;
|
||||
case 5: EB->byte[0] = sub8(emu, EB->byte[0], tmp8u); break;
|
||||
case 6: EB->byte[0] = xor8(emu, EB->byte[0], tmp8u); break;
|
||||
case 7: cmp8(emu, EB->byte[0], tmp8u); break;
|
||||
}
|
||||
break;
|
||||
case 0x81: /* GRP Ed,Id */
|
||||
case 0x83: /* GRP Ed,Ib */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
if(opcode==0x83) {
|
||||
tmp32s = F8S;
|
||||
tmp32u = (uint32_t)tmp32s;
|
||||
} else
|
||||
tmp32u = F32;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: ED->dword[0] = add32(emu, ED->dword[0], tmp32u); break;
|
||||
case 1: ED->dword[0] = or32(emu, ED->dword[0], tmp32u); break;
|
||||
case 2: ED->dword[0] = adc32(emu, ED->dword[0], tmp32u); break;
|
||||
case 3: ED->dword[0] = sbb32(emu, ED->dword[0], tmp32u); break;
|
||||
case 4: ED->dword[0] = and32(emu, ED->dword[0], tmp32u); break;
|
||||
case 5: ED->dword[0] = sub32(emu, ED->dword[0], tmp32u); break;
|
||||
case 6: ED->dword[0] = xor32(emu, ED->dword[0], tmp32u); break;
|
||||
case 7: cmp32(emu, ED->dword[0], tmp32u); break;
|
||||
}
|
||||
break;
|
||||
case 0x87:
|
||||
nextop = F8;
|
||||
#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
|
||||
GET_ED_OFFS(tlsdata);
|
||||
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;
|
||||
} else {
|
||||
// XCHG is supposed to automaticaly LOCK memory bus
|
||||
GD.dword[0] = arm_lock_xchg(ED, GD.dword[0]);
|
||||
}
|
||||
}
|
||||
#else
|
||||
GET_ED_OFFS(tlsdata);
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
pthread_mutex_lock(&emu->context->mutex_lock); // XCHG always LOCK (but when accessing memory only)
|
||||
tmp32u = GD.dword[0];
|
||||
GD.dword[0] = ED->dword[0];
|
||||
ED->dword[0] = tmp32u;
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0x89: /* MOV Ed,Gd */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
ED->dword[0] = GD.dword[0];
|
||||
break;
|
||||
case 0x8A: /* MOV Gb,GS:Eb */
|
||||
nextop = F8;
|
||||
GET_EB_OFFS(tlsdata);
|
||||
GB = EB->byte[0];
|
||||
break;
|
||||
case 0x8B: /* MOV Gd,Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
GD.dword[0] = ED->dword[0];
|
||||
break;
|
||||
case 0x8C: /* MOV Seg:Ed, Seg */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
ED->dword[0] = emu->segs[((nextop&0x38)>>3)];
|
||||
break;
|
||||
case 0x8E: /* MOV Seg,Seg:Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
emu->segs[((nextop&0x38)>>3)] = ED->word[0];
|
||||
emu->segs_serial[((nextop&0x38)>>3)] = 0;
|
||||
break;
|
||||
case 0x8F: /* POP Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
ED->dword[0] = Pop(emu);
|
||||
break;
|
||||
|
||||
case 0x9C: /* PUSHFD */
|
||||
// Segment override if for memory loc, no stack segment
|
||||
return addr-1; // so ignore prefix and continue
|
||||
|
||||
case 0xA0: /* MOV AL,Ob */
|
||||
tmp32s = F32S;
|
||||
R_AL = *(uint8_t*)((tlsdata) + tmp32s);
|
||||
break;
|
||||
case 0xA1: /* MOV EAX,Ov */
|
||||
tmp32s = F32S;
|
||||
R_EAX = *(uint32_t*)((tlsdata) + tmp32s);
|
||||
break;
|
||||
case 0xA2: /* MOV Ob,AL */
|
||||
tmp32s = F32S;
|
||||
*(uint8_t*)((tlsdata) + tmp32s) = R_AL;
|
||||
break;
|
||||
case 0xA3: /* MOV Od,EAX */
|
||||
tmp32s = F32S;
|
||||
*(uint32_t*)((tlsdata) + tmp32s) = R_EAX;
|
||||
break;
|
||||
|
||||
case 0xA8: /* TEST AL, Ib */
|
||||
test8(emu, R_AL, F8);
|
||||
break;
|
||||
|
||||
case 0xC0: /* GRP2 Eb,Ib */
|
||||
nextop = F8;
|
||||
GET_EB_OFFS(tlsdata);
|
||||
tmp8u = F8/* & 0x1f*/; // masking done in each functions
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: EB->byte[0] = rol8(emu, EB->byte[0], tmp8u); break;
|
||||
case 1: EB->byte[0] = ror8(emu, EB->byte[0], tmp8u); break;
|
||||
case 2: EB->byte[0] = rcl8(emu, EB->byte[0], tmp8u); break;
|
||||
case 3: EB->byte[0] = rcr8(emu, EB->byte[0], tmp8u); break;
|
||||
case 4:
|
||||
case 6: EB->byte[0] = shl8(emu, EB->byte[0], tmp8u); break;
|
||||
case 5: EB->byte[0] = shr8(emu, EB->byte[0], tmp8u); break;
|
||||
case 7: EB->byte[0] = sar8(emu, EB->byte[0], tmp8u); break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC6: /* MOV Eb,Ib */
|
||||
nextop = F8;
|
||||
GET_EB_OFFS(tlsdata);
|
||||
EB->byte[0] = F8;
|
||||
break;
|
||||
case 0xC7: /* MOV Ed,Id */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
ED->dword[0] = F32;
|
||||
break;
|
||||
|
||||
case 0xD0: /* GRP2 Eb,1 */
|
||||
case 0xD2: /* GRP2 Eb,CL */
|
||||
nextop = F8;
|
||||
GET_EB_OFFS(tlsdata);
|
||||
tmp8u = (opcode==0xD0)?1:R_CL;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: EB->byte[0] = rol8(emu, EB->byte[0], tmp8u); break;
|
||||
case 1: EB->byte[0] = ror8(emu, EB->byte[0], tmp8u); break;
|
||||
case 2: EB->byte[0] = rcl8(emu, EB->byte[0], tmp8u); break;
|
||||
case 3: EB->byte[0] = rcr8(emu, EB->byte[0], tmp8u); break;
|
||||
case 4:
|
||||
case 6: EB->byte[0] = shl8(emu, EB->byte[0], tmp8u); break;
|
||||
case 5: EB->byte[0] = shr8(emu, EB->byte[0], tmp8u); break;
|
||||
case 7: EB->byte[0] = sar8(emu, EB->byte[0], tmp8u); break;
|
||||
}
|
||||
break;
|
||||
case 0xD1: /* GRP2 Ed,1 */
|
||||
case 0xD3: /* GRP2 Ed,CL */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
tmp8u = (opcode==0xD1)?1:R_CL;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: ED->dword[0] = rol32(emu, ED->dword[0], tmp8u); break;
|
||||
case 1: ED->dword[0] = ror32(emu, ED->dword[0], tmp8u); break;
|
||||
case 2: ED->dword[0] = rcl32(emu, ED->dword[0], tmp8u); break;
|
||||
case 3: ED->dword[0] = rcr32(emu, ED->dword[0], tmp8u); break;
|
||||
case 4:
|
||||
case 6: ED->dword[0] = shl32(emu, ED->dword[0], tmp8u); break;
|
||||
case 5: ED->dword[0] = shr32(emu, ED->dword[0], tmp8u); break;
|
||||
case 7: ED->dword[0] = sar32(emu, ED->dword[0], tmp8u); break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE9:
|
||||
case 0xEB:
|
||||
return addr-1; // ignore FS: to execute regular opcode
|
||||
break;
|
||||
|
||||
case 0xFF: /* GRP 5 Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* INC Ed */
|
||||
ED->dword[0] = inc32(emu, ED->dword[0]);
|
||||
break;
|
||||
case 1: /* DEC Ed */
|
||||
ED->dword[0] = dec32(emu, ED->dword[0]);
|
||||
break;
|
||||
case 2: /* CALL NEAR Ed */
|
||||
R_EIP = (uintptr_t)getAlternate((void*)ED->dword[0]);
|
||||
Push(emu, addr);
|
||||
addr = R_EIP;
|
||||
break;
|
||||
case 3: /* CALL FAR Ed */
|
||||
if(nextop>0xc0) {
|
||||
printf_log(LOG_NONE, "Illegal Opcode %02X %02X\n", opcode, nextop);
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
return 0;
|
||||
} else {
|
||||
Push16(emu, R_CS);
|
||||
Push(emu, addr);
|
||||
addr = ED->dword[0];
|
||||
R_CS = (ED+1)->word[0];
|
||||
}
|
||||
break;
|
||||
case 4: /* JMP NEAR Ed */
|
||||
addr = (uintptr_t)getAlternate((void*)ED->dword[0]);
|
||||
break;
|
||||
case 5: /* JMP FAR Ed */
|
||||
if(nextop>0xc0) {
|
||||
printf_log(LOG_NONE, "Illegal Opcode 0x%02X 0x%02X\n", opcode, nextop);
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
return 0;
|
||||
} else {
|
||||
addr = ED->dword[0];
|
||||
R_CS = (ED+1)->word[0];
|
||||
}
|
||||
break;
|
||||
case 6: /* Push Ed */
|
||||
Push(emu, ED->dword[0]);
|
||||
break;
|
||||
default:
|
||||
printf_log(LOG_NONE, "Illegal Opcode 0x%02X 0x%02X\n", opcode, nextop);
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
#include "bridge.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t Test640F(x86test_t *test, uintptr_t tlsdata, uintptr_t addr)
|
||||
#else
|
||||
uintptr_t Run640F(x86emu_t *emu, uintptr_t tlsdata, uintptr_t addr)
|
||||
#endif
|
||||
{
|
||||
uint8_t nextop;
|
||||
reg32_t *oped;
|
||||
uint8_t tmp8u;
|
||||
uint32_t tmp32u;
|
||||
int32_t tmp32s;
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t* emu = test->emu;
|
||||
#endif
|
||||
uint8_t opcode = F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0xAF: /* IMUL Gd,Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
GD.dword[0] = imul32(emu, GD.dword[0], ED->dword[0]);
|
||||
break;
|
||||
|
||||
case 0xB6: /* MOVZX Gd,GS:Eb */
|
||||
nextop = F8;
|
||||
GET_EB_OFFS(tlsdata);
|
||||
GD.dword[0] = EB->byte[0];
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
#include "bridge.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t Test6466(x86test_t *test, uintptr_t tlsdata, uintptr_t addr)
|
||||
#else
|
||||
uintptr_t Run6466(x86emu_t *emu, uintptr_t tlsdata, uintptr_t addr)
|
||||
#endif
|
||||
{
|
||||
uint8_t nextop;
|
||||
reg32_t *oped;
|
||||
uint8_t tmp8u;
|
||||
uint32_t tmp32u;
|
||||
int32_t tmp32s;
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t* emu = test->emu;
|
||||
#endif
|
||||
uint8_t opcode = F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0x03: /* ADD Gw, FS:Ew */
|
||||
nextop = F8;
|
||||
GET_EW_OFFS(tlsdata);
|
||||
GW.word[0] = add16(emu, GW.word[0], EW->word[0]);
|
||||
break;
|
||||
|
||||
case 0x8B: /* MOV Gw,FS:Ew */
|
||||
nextop = F8;
|
||||
GET_EW_OFFS(tlsdata);
|
||||
GW.word[0] = EW->word[0];
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
#include "bridge.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t Test6467(x86test_t *test, uintptr_t tlsdata, uintptr_t addr)
|
||||
#else
|
||||
uintptr_t Run6467(x86emu_t *emu, uintptr_t tlsdata, uintptr_t addr)
|
||||
#endif
|
||||
{
|
||||
uint8_t nextop;
|
||||
reg32_t *oped;
|
||||
uint8_t tmp8u;
|
||||
uint32_t tmp32u;
|
||||
int32_t tmp32s;
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t* emu = test->emu;
|
||||
#endif
|
||||
uint8_t opcode = F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0x3B: /* CMP GD, FS:Ed16 */
|
||||
nextop = F8;
|
||||
GET_EW16_OFFS(tlsdata);
|
||||
cmp32(emu, GD.dword[0], ED->dword[0]);
|
||||
break;
|
||||
|
||||
case 0x89: /* MOV ED16,Gd */
|
||||
nextop = F8;
|
||||
GET_EW16_OFFS(tlsdata);
|
||||
ED->dword[0] = GD.dword[0];
|
||||
break;
|
||||
|
||||
case 0x8B: /* MOV Gd,Ed16 */
|
||||
nextop = F8;
|
||||
GET_EW16_OFFS(tlsdata);
|
||||
GD.dword[0] = ED->dword[0];
|
||||
break;
|
||||
|
||||
case 0x8F: /* POP FS:Ed */
|
||||
nextop = F8;
|
||||
GET_EW16_OFFS(tlsdata);
|
||||
ED->dword[0] = Pop(emu);
|
||||
break;
|
||||
|
||||
case 0xA1: /* MOV EAX,Ov16 */
|
||||
tmp32u = F16;
|
||||
R_EAX = *(uint32_t*)(tlsdata + tmp32u);
|
||||
break;
|
||||
case 0xA3: /* MOV Ov16,EAX */
|
||||
tmp32u = F16;
|
||||
#ifdef TEST_INTERPRETER
|
||||
test->memaddr = tlsdata + tmp32u;
|
||||
test->memsize = 4;
|
||||
*(uint32_t*)(test->mem) = R_EAX;
|
||||
#else
|
||||
*(uint32_t*)(tlsdata + tmp32u) = R_EAX;
|
||||
#endif
|
||||
break;
|
||||
case 0xFF: /* GRP 5 Ed */
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 6: /* Push Ed */
|
||||
GET_EW16_OFFS(tlsdata);
|
||||
Push(emu, ED->dword[0]);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
+520
-1634
File diff suppressed because it is too large.
Load diff
+119
-102
@@ -14,19 +14,14 @@
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
|
||||
#define F8 *(uint8_t*)(ip++)
|
||||
#define F8S *(int8_t*)(ip++)
|
||||
#define F16 *(uint16_t*)(ip+=2, ip-2)
|
||||
#define F16S *(int16_t*)(ip+=2, ip-2)
|
||||
#define F32 *(uint32_t*)(ip+=4, ip-4)
|
||||
#define F32S *(int32_t*)(ip+=4, ip-4)
|
||||
#define PK(a) *(uint8_t*)(ip+a)
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
void Run660F(x86emu_t *emu)
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t Test660F(x86test_t *test, uintptr_t addr)
|
||||
#else
|
||||
uintptr_t Run660F(x86emu_t *emu, uintptr_t addr)
|
||||
#endif
|
||||
{
|
||||
uintptr_t ip = R_EIP+2; //skip 66 0F
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
reg32_t *oped;
|
||||
@@ -43,6 +38,9 @@ void Run660F(x86emu_t *emu)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t* emu = test->emu;
|
||||
#endif
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
|
||||
@@ -144,8 +142,7 @@ void Run660F(x86emu_t *emu)
|
||||
EW->word[0] = 0; // dummy operation. Should be CR0 -> Ew
|
||||
break;
|
||||
default:
|
||||
ip = R_EIP;
|
||||
UnimpOpcode(emu);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0x10: /* MOVUPD Gx, Ex */
|
||||
@@ -160,7 +157,7 @@ void Run660F(x86emu_t *emu)
|
||||
break;
|
||||
case 0x12: /* MOVLPD Gx, Eq */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
GET_ED8;
|
||||
if((uintptr_t)ED & 7)
|
||||
memcpy(&GX.q[0], ED, 8);
|
||||
else
|
||||
@@ -168,7 +165,7 @@ void Run660F(x86emu_t *emu)
|
||||
break;
|
||||
case 0x13: /* MOVLPD Eq, Gx */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
GET_ED8;
|
||||
if((uintptr_t)ED & 7)
|
||||
memcpy(ED, &GX.q[0], 8);
|
||||
else
|
||||
@@ -187,18 +184,18 @@ void Run660F(x86emu_t *emu)
|
||||
break;
|
||||
case 0x16: /* MOVHPD Gx, Ed */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
GET_ED8;
|
||||
GX.q[1] = *(uint64_t*)ED;
|
||||
break;
|
||||
case 0x17: /* MOVHPD Ed, Gx */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
GET_ED8;
|
||||
*(uint64_t*)ED = GX.q[1];
|
||||
break;
|
||||
|
||||
case 0x1F: /* NOP (multi-byte) */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
GET_ED_;
|
||||
break;
|
||||
|
||||
case 0x28: /* MOVAPD Gx, Ex */
|
||||
@@ -219,16 +216,20 @@ void Run660F(x86emu_t *emu)
|
||||
GX.d[0] = EM->sd[0];
|
||||
GX.d[1] = EM->sd[1];
|
||||
break;
|
||||
|
||||
|
||||
case 0x2B: /* MOVNTPD Ex, Gx */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
EX->q[0] = GX.q[0]; // Address needs to ba aligned for MOVNTPD
|
||||
EX->q[1] = GX.q[1];
|
||||
break;
|
||||
case 0x2C: /* CVTTPD2PI Gm, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
if(isnan(EX->d[0]) || isinf(EX->d[0]) || EX->d[0]>0x7fffffff)
|
||||
if(!isfinite(EX->d[0]) || EX->d[0]>(double)0x7fffffff || EX->d[0]<-(double)0x80000000U)
|
||||
GM.ud[0] = 0x80000000;
|
||||
else
|
||||
GM.sd[0] = EX->d[0];
|
||||
if(isnan(EX->d[1]) || isinf(EX->d[1]) || EX->d[1]>0x7fffffff)
|
||||
if(!isfinite(EX->d[1]) || EX->d[1]>(double)0x7fffffff || EX->d[1]<-(double)0x80000000U)
|
||||
GM.ud[1] = 0x80000000;
|
||||
else
|
||||
GM.sd[1] = EX->d[1];
|
||||
@@ -237,7 +238,7 @@ void Run660F(x86emu_t *emu)
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<2; ++i)
|
||||
if(isnan(EX->d[i]) || isinf(EX->d[i]) || EX->d[i]>0x7fffffff)
|
||||
if(!isfinite(EX->d[i]) || EX->d[i]>(double)0x7fffffff || EX->d[i]<-(double)0x80000000U)
|
||||
GM.ud[i] = 0x80000000;
|
||||
else
|
||||
switch(emu->mxcsr.f.MXCSR_RC) {
|
||||
@@ -347,7 +348,34 @@ void Run660F(x86emu_t *emu)
|
||||
GX.sw[4+i] = EX->sw[i*2+0] - EX->sw[i*2+1];
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x06: /* PHSUBD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for (int i=0; i<2; ++i)
|
||||
GX.sd[i] = GX.sd[i*2+0] - GX.sd[i*2+1];
|
||||
if(&GX == EX) {
|
||||
GX.q[1] = GX.q[0];
|
||||
} else {
|
||||
for (int i=0; i<2; ++i)
|
||||
GX.sd[2+i] = EX->sd[i*2+0] - EX->sd[i*2+1];
|
||||
}
|
||||
break;
|
||||
case 0x07: /* PHSUBSW Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for (int i=0; i<4; ++i) {
|
||||
tmp32s = GX.sw[i*2+0]-GX.sw[i*2+1];
|
||||
GX.sw[i] = (tmp32s<-32768)?-32768:((tmp32s>32767)?32767:tmp32s);
|
||||
}
|
||||
if(&GX == EX) {
|
||||
GX.q[1] = GX.q[0];
|
||||
} else {
|
||||
for (int i=0; i<4; ++i) {
|
||||
tmp32s = EX->sw[i*2+0] - EX->sw[i*2+1];
|
||||
GX.sw[4+i] = (tmp32s<-32768)?-32768:((tmp32s>32767)?32767:tmp32s);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x08: /* PSIGNB Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
@@ -513,8 +541,7 @@ void Run660F(x86emu_t *emu)
|
||||
break;
|
||||
|
||||
default:
|
||||
ip = R_EIP;
|
||||
UnimpOpcode(emu);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -528,28 +555,28 @@ void Run660F(x86emu_t *emu)
|
||||
switch((tmp8u & 4) ? (emu->mxcsr.f.MXCSR_RC) : (tmp8u & 3))
|
||||
{
|
||||
case ROUND_Nearest:
|
||||
GX.f[0] = nearbyint(EX->f[0]);
|
||||
GX.f[1] = nearbyint(EX->f[1]);
|
||||
GX.f[2] = nearbyint(EX->f[2]);
|
||||
GX.f[3] = nearbyint(EX->f[3]);
|
||||
GX.f[0] = nearbyintf(EX->f[0]);
|
||||
GX.f[1] = nearbyintf(EX->f[1]);
|
||||
GX.f[2] = nearbyintf(EX->f[2]);
|
||||
GX.f[3] = nearbyintf(EX->f[3]);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
GX.f[0] = floor(EX->f[0]);
|
||||
GX.f[1] = floor(EX->f[1]);
|
||||
GX.f[2] = floor(EX->f[2]);
|
||||
GX.f[3] = floor(EX->f[3]);
|
||||
GX.f[0] = floorf(EX->f[0]);
|
||||
GX.f[1] = floorf(EX->f[1]);
|
||||
GX.f[2] = floorf(EX->f[2]);
|
||||
GX.f[3] = floorf(EX->f[3]);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
GX.f[0] = ceil(EX->f[0]);
|
||||
GX.f[1] = ceil(EX->f[1]);
|
||||
GX.f[2] = ceil(EX->f[2]);
|
||||
GX.f[3] = ceil(EX->f[3]);
|
||||
GX.f[0] = ceilf(EX->f[0]);
|
||||
GX.f[1] = ceilf(EX->f[1]);
|
||||
GX.f[2] = ceilf(EX->f[2]);
|
||||
GX.f[3] = ceilf(EX->f[3]);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
GX.f[0] = trunc(EX->f[0]);
|
||||
GX.f[1] = trunc(EX->f[1]);
|
||||
GX.f[2] = trunc(EX->f[2]);
|
||||
GX.f[3] = trunc(EX->f[3]);
|
||||
GX.f[0] = truncf(EX->f[0]);
|
||||
GX.f[1] = truncf(EX->f[1]);
|
||||
GX.f[2] = truncf(EX->f[2]);
|
||||
GX.f[3] = truncf(EX->f[3]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -584,16 +611,16 @@ void Run660F(x86emu_t *emu)
|
||||
switch((tmp8u & 4) ? (emu->mxcsr.f.MXCSR_RC) : (tmp8u & 3))
|
||||
{
|
||||
case ROUND_Nearest:
|
||||
GX.f[0] = nearbyint(EX->f[0]);
|
||||
GX.f[0] = nearbyintf(EX->f[0]);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
GX.f[0] = floor(EX->f[0]);
|
||||
GX.f[0] = floorf(EX->f[0]);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
GX.f[0] = ceil(EX->f[0]);
|
||||
GX.f[0] = ceilf(EX->f[0]);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
GX.f[0] = trunc(EX->f[0]);
|
||||
GX.f[0] = truncf(EX->f[0]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -634,35 +661,12 @@ void Run660F(x86emu_t *emu)
|
||||
if(tmp8u>31)
|
||||
{GX.q[0] = GX.q[1] = 0;}
|
||||
else
|
||||
#if 0
|
||||
if(tmp8u>15) {
|
||||
tmp8u=(tmp8u-16)*8;
|
||||
if (tmp8u < 64) {
|
||||
GX.q[0] = (GX.q[0] >> tmp8u) | (GX.q[1] << (64 - tmp8u));
|
||||
GX.q[1] = (GX.q[1] >> tmp8u);
|
||||
} else {
|
||||
GX.q[0] = GX.q[1] >> (tmp8u - 64);
|
||||
GX.q[1] = 0;
|
||||
}
|
||||
} else {
|
||||
tmp8u*=8;
|
||||
if (tmp8u < 64) {
|
||||
GX.q[0] = (EX->q[0] >> tmp8u) | (EX->q[1] << (64 - tmp8u));
|
||||
GX.q[1] = (EX->q[1] >> tmp8u) | (GX.q[0] << (64-tmp8u));
|
||||
} else {
|
||||
tmp8u -= 64;
|
||||
GX.q[0] = (EX->q[1] >> tmp8u) | (GX.q[0] << (64 - tmp8u));
|
||||
GX.q[1] = (GX.q[0] >> tmp8u) | (GX.q[1] >> (64 - tmp8u));
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
for (int i=0; i<16; ++i, ++tmp8u)
|
||||
eax1.ub[i] = (tmp8u>15)?((tmp8u>31)?0:GX.ub[tmp8u-16]):EX->ub[tmp8u];
|
||||
GX.q[0] = eax1.q[0];
|
||||
GX.q[1] = eax1.q[1];
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0x16: // PEXTRD ED, GX, u8
|
||||
@@ -696,8 +700,7 @@ void Run660F(x86emu_t *emu)
|
||||
break;
|
||||
|
||||
default:
|
||||
ip = R_EIP;
|
||||
UnimpOpcode(emu);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -782,23 +785,24 @@ void Run660F(x86emu_t *emu)
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<4; ++i)
|
||||
if(isnanf(EX->f[i]) || isinff(EX->f[i]) || EX->f[i]>0x7fffffff)
|
||||
// note, converting 0x7fffffff to float gives 0x80000000 basicaly, because of the loss or precision in the mantice. So uing >= here...
|
||||
if(isnanf(EX->f[i]) || isinff(EX->f[i]) || EX->f[i]>=(float)0x80000000U || EX->f[i]<-(float)0x80000000U)
|
||||
GX.sd[i] = 0x80000000;
|
||||
else
|
||||
switch(emu->mxcsr.f.MXCSR_RC) {
|
||||
case ROUND_Nearest:
|
||||
GX.sd[i] = nearbyintf(EX->f[i]);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
GX.sd[i] = floorf(EX->f[i]);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
GX.sd[i] = ceilf(EX->f[i]);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
GX.sd[i] = EX->f[i];
|
||||
break;
|
||||
}
|
||||
else
|
||||
switch(emu->mxcsr.f.MXCSR_RC) {
|
||||
case ROUND_Nearest:
|
||||
GX.sd[i] = nearbyintf(EX->f[i]);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
GX.sd[i] = floorf(EX->f[i]);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
GX.sd[i] = ceilf(EX->f[i]);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
GX.sd[i] = EX->f[i];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x5C: /* SUBPD Gx, Ex */
|
||||
nextop = F8;
|
||||
@@ -1016,8 +1020,7 @@ void Run660F(x86emu_t *emu)
|
||||
for (int i=0; i<8; ++i) EX->uw[i] <<= tmp8u;
|
||||
break;
|
||||
default:
|
||||
ip = R_EIP;
|
||||
UnimpOpcode(emu);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0x72: /* GRP */
|
||||
@@ -1043,8 +1046,7 @@ void Run660F(x86emu_t *emu)
|
||||
for (int i=0; i<4; ++i) EX->ud[i] <<= tmp8u;
|
||||
break;
|
||||
default:
|
||||
ip = R_EIP;
|
||||
UnimpOpcode(emu);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0x73: /* GRP */
|
||||
@@ -1096,8 +1098,7 @@ void Run660F(x86emu_t *emu)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ip = R_EIP;
|
||||
UnimpOpcode(emu);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0x74: /* PCMPEQB Gx,Ex */
|
||||
@@ -1190,7 +1191,12 @@ void Run660F(x86emu_t *emu)
|
||||
GET_EW;
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
{
|
||||
#ifdef TEST_INTERPRETER
|
||||
test->memaddr=((test->memaddr)+tmp32s*2);
|
||||
*(uint16_t*)test->mem = *(uint16_t*)test->memaddr;
|
||||
#else
|
||||
EW=(reg32_t*)(((uintptr_t)(EW))+(tmp32s*2));
|
||||
#endif
|
||||
}
|
||||
if(EW->word[0] & (1<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
@@ -1217,7 +1223,12 @@ void Run660F(x86emu_t *emu)
|
||||
GET_EW;
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
{
|
||||
#ifdef TEST_INTERPRETER
|
||||
test->memaddr=((test->memaddr)+tmp32s*2);
|
||||
*(uint16_t*)test->mem = *(uint16_t*)test->memaddr;
|
||||
#else
|
||||
EW=(reg32_t*)(((uintptr_t)(EW))+(tmp32s*2));
|
||||
#endif
|
||||
}
|
||||
if(EW->word[0] & (1<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
@@ -1263,7 +1274,12 @@ void Run660F(x86emu_t *emu)
|
||||
GET_EW;
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
{
|
||||
#ifdef TEST_INTERPRETER
|
||||
test->memaddr=((test->memaddr)+tmp32s*2);
|
||||
*(uint16_t*)test->mem = *(uint16_t*)test->memaddr;
|
||||
#else
|
||||
EW=(reg32_t*)(((uintptr_t)(EW))+(tmp32s*2));
|
||||
#endif
|
||||
}
|
||||
if(EW->word[0] & (1<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
@@ -1332,8 +1348,7 @@ void Run660F(x86emu_t *emu)
|
||||
break;
|
||||
|
||||
default:
|
||||
ip = R_EIP;
|
||||
UnimpOpcode(emu);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0xBB: /* BTC Ew,Gw */
|
||||
@@ -1345,7 +1360,12 @@ void Run660F(x86emu_t *emu)
|
||||
GET_EW;
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
{
|
||||
#ifdef TEST_INTERPRETER
|
||||
test->memaddr=((test->memaddr)+tmp32s*2);
|
||||
*(uint16_t*)test->mem = *(uint16_t*)test->memaddr;
|
||||
#else
|
||||
EW=(reg32_t*)(((uintptr_t)(EW))+(tmp32s*2));
|
||||
#endif
|
||||
}
|
||||
if(EW->word[0] & (1<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
@@ -1512,8 +1532,7 @@ void Run660F(x86emu_t *emu)
|
||||
if(EX->ub[i]&0x80)
|
||||
GD.dword[0] |= (1<<i);
|
||||
} else {
|
||||
ip = R_EIP;
|
||||
UnimpOpcode(emu);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0xD8: /* PSUBUSB Gx,Ex */
|
||||
@@ -1617,11 +1636,11 @@ void Run660F(x86emu_t *emu)
|
||||
case 0xE6: /* CVTTPD2DQ Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
if(isnan(EX->d[0]) || isinf(EX->d[0]) || EX->d[0]>0x7fffffff)
|
||||
if(isnan(EX->d[0]) || isinf(EX->d[0]) || EX->d[0]>(double)0x7fffffff || EX->d[0]<-(double)0x80000000U)
|
||||
GX.sd[0] = 0x80000000;
|
||||
else
|
||||
GX.sd[0] = EX->d[0];
|
||||
if(isnan(EX->d[1]) || isinf(EX->d[1]) || EX->d[1]>0x7fffffff)
|
||||
if(isnan(EX->d[1]) || isinf(EX->d[1]) || EX->d[1]>(double)0x7fffffff || EX->d[1]<-(double)0x80000000U)
|
||||
GX.sd[1] = 0x80000000;
|
||||
else
|
||||
GX.sd[1] = EX->d[1];
|
||||
@@ -1799,10 +1818,8 @@ void Run660F(x86emu_t *emu)
|
||||
break;
|
||||
|
||||
default:
|
||||
ip = R_EIP;
|
||||
UnimpOpcode(emu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
R_EIP = ip;
|
||||
return;
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t Test66D9(x86test_t *test, uintptr_t addr)
|
||||
#else
|
||||
uintptr_t Run66D9(x86emu_t *emu, uintptr_t addr)
|
||||
#endif
|
||||
{
|
||||
uint8_t nextop;
|
||||
reg32_t *oped;
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t* emu = test->emu;
|
||||
#endif
|
||||
|
||||
uint8_t opcode = F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
case 0xD0:
|
||||
case 0xE0:
|
||||
case 0xE5:
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xFC:
|
||||
case 0xE1:
|
||||
case 0xE4:
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 4: /* FLDENV m */
|
||||
// warning, incomplete
|
||||
GET_EW;
|
||||
#ifndef TEST_INTERPRETER
|
||||
fpu_loadenv(emu, (char*)ED, 1);
|
||||
#endif
|
||||
break;
|
||||
case 6: /* FNSTENV m */
|
||||
// warning, incomplete
|
||||
GET_EW;
|
||||
#ifndef TEST_INTERPRETER
|
||||
fpu_savenv(emu, (char*)ED, 1);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t Test66DD(x86test_t *test, uintptr_t addr)
|
||||
#else
|
||||
uintptr_t Run66DD(x86emu_t *emu, uintptr_t addr)
|
||||
#endif
|
||||
{
|
||||
uint8_t nextop;
|
||||
reg32_t *oped;
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t* emu = test->emu;
|
||||
#endif
|
||||
|
||||
uint8_t opcode = F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
case 0xD0:
|
||||
case 0xE0:
|
||||
case 0xE5:
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xFC:
|
||||
case 0xE1:
|
||||
case 0xE4:
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
return 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 4: /* FRSTOR m94byte */
|
||||
GET_EW;
|
||||
#ifndef TEST_INTERPRETER
|
||||
fpu_loadenv(emu, (char*)ED, 1);
|
||||
// get the STx
|
||||
{
|
||||
char* p =(char*)ED;
|
||||
p += 14;
|
||||
for (int i=0; i<8; ++i) {
|
||||
LD2D(p, &ST(i).d);
|
||||
p+=10;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 6: /* FNSAVE m94byte */
|
||||
GET_EW;
|
||||
// ENV first...
|
||||
#ifndef TEST_INTERPRETER
|
||||
fpu_savenv(emu, (char*)ED, 1);
|
||||
// save the STx
|
||||
{
|
||||
char* p =(char*)ED;
|
||||
p += 14;
|
||||
for (int i=0; i<8; ++i) {
|
||||
D2LD(&ST(i).d, p);
|
||||
p+=10;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
reset_fpu(emu);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box86context.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "bridge.h"
|
||||
#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t Test67(x86test_t *test, int rep, uintptr_t addr)
|
||||
#else
|
||||
uintptr_t Run67(x86emu_t *emu, int rep, uintptr_t addr)
|
||||
#endif
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
reg32_t *oped;
|
||||
uint8_t tmp8u, tmp8u2;
|
||||
int8_t tmp8s;
|
||||
uint16_t tmp16u, tmp16u2;
|
||||
int16_t tmp16s;
|
||||
uint32_t tmp32u, tmp32u2, tmp32u3;
|
||||
int32_t tmp32s, tmp32s2;
|
||||
uint64_t tmp64u;
|
||||
int64_t tmp64s;
|
||||
double d;
|
||||
float f;
|
||||
int64_t ll;
|
||||
sse_regs_t *opex, eax1;
|
||||
mmx87_regs_t *opem, eam1;
|
||||
uintptr_t tlsdata;
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t *emu = test->emu;
|
||||
#endif
|
||||
opcode = F8;
|
||||
|
||||
while(opcode==0x67)
|
||||
opcode = F8;
|
||||
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x64:
|
||||
tlsdata = GetFSBaseEmu(emu);
|
||||
#ifdef TEST_INTERPRETER
|
||||
return Test6467(test, tlsdata, addr);
|
||||
#else
|
||||
return Run6467(emu, tlsdata, addr);
|
||||
#endif
|
||||
|
||||
case 0x66: /* MoooRE opcodes */
|
||||
#ifdef TEST_INTERPRETER
|
||||
return Test6766(test, rep, addr);
|
||||
#else
|
||||
return Run6766(emu, rep, addr);
|
||||
#endif
|
||||
|
||||
case 0x6C: /* INSB */
|
||||
tmp32u = rep?R_CX:1;
|
||||
while(tmp32u--) {
|
||||
#ifdef TEST_INTERPRETER
|
||||
*(int8_t*)(R_DI+GetESBaseEmu(emu)) = 0; // faking port read, using actual segment ES, just in case
|
||||
#endif
|
||||
if(ACCESS_FLAG(F_DF))
|
||||
R_DI-=1;
|
||||
else
|
||||
R_DI+=1;
|
||||
}
|
||||
if(rep) R_CX = 0;
|
||||
break;
|
||||
|
||||
case 0xAC: /* LODSB */
|
||||
tmp32u = rep?R_CX:1;
|
||||
while(tmp32u--) {
|
||||
R_AL = *(int8_t*)(R_SI+GetDSBaseEmu(emu));
|
||||
if(ACCESS_FLAG(F_DF))
|
||||
R_SI-=1;
|
||||
else
|
||||
R_SI+=1;
|
||||
}
|
||||
if(rep) R_CX = 0;
|
||||
break;
|
||||
|
||||
case 0xE0: /* LOOPNZ */
|
||||
CHECK_FLAGS(emu);
|
||||
tmp8s = F8S;
|
||||
--R_CX; // don't update flags
|
||||
if(R_CX && !ACCESS_FLAG(F_ZF))
|
||||
addr += tmp8s;
|
||||
break;
|
||||
case 0xE1: /* LOOPZ */
|
||||
CHECK_FLAGS(emu);
|
||||
tmp8s = F8S;
|
||||
--R_CX; // don't update flags
|
||||
if(R_CX && ACCESS_FLAG(F_ZF))
|
||||
addr += tmp8s;
|
||||
break;
|
||||
case 0xE2: /* LOOP */
|
||||
tmp8s = F8S;
|
||||
--R_CX; // don't update flags
|
||||
if(R_CX)
|
||||
addr += tmp8s;
|
||||
break;
|
||||
case 0xE3: /* JCXZ */
|
||||
tmp8s = F8S;
|
||||
if(!R_CX)
|
||||
addr += tmp8s;
|
||||
break;
|
||||
|
||||
case 0xE8: /* CALL Id */
|
||||
tmp32s = F32S; // call is relative
|
||||
Push(emu, addr);
|
||||
addr += tmp32s;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
#include "bridge.h"
|
||||
#ifdef DYNAREC
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t Test6766(x86test_t *test, int rep, uintptr_t addr)
|
||||
#else
|
||||
uintptr_t Run6766(x86emu_t *emu, int rep, uintptr_t addr)
|
||||
#endif
|
||||
{
|
||||
uint8_t nextop;
|
||||
reg32_t *oped;
|
||||
uint8_t tmp8u;
|
||||
uint32_t tmp32u;
|
||||
int32_t tmp32s;
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t* emu = test->emu;
|
||||
#endif
|
||||
uint8_t opcode = F8;
|
||||
|
||||
while((opcode==0x2E) || (opcode==0x66)) // ignoring CS: or multiple 0x66
|
||||
opcode = F8;
|
||||
|
||||
while((opcode==0xF2) || (opcode==0xF3)) {
|
||||
rep = opcode-0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x8D: /* LEA Gw,Ew */
|
||||
nextop = F8;
|
||||
GET_EW16_;
|
||||
GW.word[0] = (uint16_t)(uintptr_t)ED;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -890,7 +890,7 @@ void PrintTrace(x86emu_t* emu, uintptr_t ip, int dynarec)
|
||||
const uint8_t pk1 = PK(1);
|
||||
if(((pk1>>3)&7)==2 || ((pk1>>3)&7)==4) { // jmp/call near
|
||||
uintptr_t nextaddr = (uintptr_t)getAlternate((void*)evalED(emu, ip+1));
|
||||
printf_log(LOG_NONE, " => %p", nextaddr);
|
||||
printf_log(LOG_NONE, " => %p", (void*)nextaddr);
|
||||
printFunctionAddr(nextaddr, " / ");
|
||||
}
|
||||
}
|
||||
|
||||
+70
-13
@@ -4,6 +4,7 @@
|
||||
#include <stdint.h>
|
||||
#include "regs.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "box86context.h"
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
|
||||
static inline uint8_t Fetch8(x86emu_t *emu) {return *(uint8_t*)(R_EIP++);}
|
||||
@@ -41,15 +42,25 @@ static inline uint32_t Pop(x86emu_t *emu)
|
||||
return *st;
|
||||
}
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
#define Push(E, V) do{E->regs[_SP].dword[0] -=4; test->memsize = 4; *(uint64_t*)test->mem = (V); test->memaddr = E->regs[_SP].dword[0];}while(0)
|
||||
#define Push16(E, V) do{E->regs[_SP].dword[0] -=2; test->memsize = 2; *(uint16_t*)test->mem = (V); test->memaddr = E->regs[_SP].dword[0];}while(0)
|
||||
#else
|
||||
static inline void Push(x86emu_t *emu, uint32_t v)
|
||||
{
|
||||
R_ESP -= 4;
|
||||
*((uint32_t*)R_ESP) = v;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void PushExit(x86emu_t* emu)
|
||||
{
|
||||
R_ESP -= 4;
|
||||
*((uint32_t*)R_ESP) = my_context->exit_bridge;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// the op code definition can be found here: http://ref.x86asm.net/geek32.html
|
||||
|
||||
static inline reg32_t* GetECommon(x86emu_t* emu, uint32_t m)
|
||||
{
|
||||
if (m<=7) {
|
||||
@@ -188,23 +199,69 @@ static inline sse_regs_t* GetGx(x86emu_t *emu, uint32_t v)
|
||||
uint8_t m = (v&0x38)>>3;
|
||||
return &emu->xmm[m&7];
|
||||
}
|
||||
|
||||
#endif
|
||||
void UpdateFlags(x86emu_t *emu);
|
||||
|
||||
#define CHECK_FLAGS(emu) if(emu->df) UpdateFlags(emu)
|
||||
#define RESET_FLAGS(emu) emu->df = d_none
|
||||
|
||||
void Run67(x86emu_t *emu);
|
||||
void Run0F(x86emu_t *emu);
|
||||
void Run660F(x86emu_t *emu);
|
||||
void Run66D9(x86emu_t *emu); // x87
|
||||
void Run6766(x86emu_t *emu);
|
||||
void RunGS(x86emu_t *emu);
|
||||
void RunGS0F(x86emu_t *emu, uintptr_t tlsdata);
|
||||
void RunFS(x86emu_t *emu);
|
||||
void RunFS66(x86emu_t *emu, uintptr_t tlsdata);
|
||||
void RunLock(x86emu_t *emu);
|
||||
void RunLock66(x86emu_t *emu);
|
||||
uintptr_t Run0F(x86emu_t *emu, uintptr_t addr, int *step);
|
||||
uintptr_t Run64(x86emu_t *emu, int seg, uintptr_t addr);
|
||||
uintptr_t Run640F(x86emu_t *emu, uintptr_t tlsdata, uintptr_t addr);
|
||||
uintptr_t Run6466(x86emu_t *emu, uintptr_t tlsdata, uintptr_t addr);
|
||||
uintptr_t Run6467(x86emu_t *emu, uintptr_t tlsdata, uintptr_t addr);
|
||||
uintptr_t Run66(x86emu_t *emu, int rep, uintptr_t addr);
|
||||
uintptr_t Run660F(x86emu_t *emu, uintptr_t addr);
|
||||
uintptr_t Run6664(x86emu_t *emu, int seg, uintptr_t addr);
|
||||
uintptr_t Run66D9(x86emu_t *emu, uintptr_t addr);
|
||||
uintptr_t Run66DD(x86emu_t *emu, uintptr_t addr);
|
||||
uintptr_t Run66F0(x86emu_t *emu, uintptr_t addr);
|
||||
uintptr_t Run67(x86emu_t *emu, int rep, uintptr_t addr);
|
||||
uintptr_t Run670F(x86emu_t *emu, int rep, uintptr_t addr);
|
||||
uintptr_t Run6766(x86emu_t *emu, int rep, uintptr_t addr);
|
||||
uintptr_t Run67660F(x86emu_t *emu, uintptr_t addr);
|
||||
uintptr_t RunD8(x86emu_t *emu, uintptr_t addr);
|
||||
uintptr_t RunD9(x86emu_t *emu, uintptr_t addr);
|
||||
uintptr_t RunDA(x86emu_t *emu, uintptr_t addr);
|
||||
uintptr_t RunDB(x86emu_t *emu, uintptr_t addr);
|
||||
uintptr_t RunDC(x86emu_t *emu, uintptr_t addr);
|
||||
uintptr_t RunDD(x86emu_t *emu, uintptr_t addr);
|
||||
uintptr_t RunDE(x86emu_t *emu, uintptr_t addr);
|
||||
uintptr_t RunDF(x86emu_t *emu, uintptr_t addr);
|
||||
uintptr_t RunF0(x86emu_t *emu, uintptr_t addr);
|
||||
uintptr_t RunF066(x86emu_t *emu, uintptr_t addr);
|
||||
uintptr_t RunF20F(x86emu_t *emu, uintptr_t addr, int *step);
|
||||
uintptr_t RunF30F(x86emu_t *emu, uintptr_t addr);
|
||||
|
||||
#ifdef DYNAREC
|
||||
uintptr_t Test0F(x86test_t *test, uintptr_t addr, int *step);
|
||||
uintptr_t Test64(x86test_t *test, int seg, uintptr_t addr);
|
||||
uintptr_t Test640F(x86test_t *test, uintptr_t tlsdata, uintptr_t addr);
|
||||
uintptr_t Test6466(x86test_t *test, uintptr_t tlsdata, uintptr_t addr);
|
||||
uintptr_t Test6467(x86test_t *test, uintptr_t tlsdata, uintptr_t addr);
|
||||
uintptr_t Test66(x86test_t *test, int rep, uintptr_t addr);
|
||||
uintptr_t Test660F(x86test_t *test, uintptr_t addr);
|
||||
uintptr_t Test6664(x86test_t *test, int seg, uintptr_t addr);
|
||||
uintptr_t Test66D9(x86test_t *test, uintptr_t addr);
|
||||
uintptr_t Test66DD(x86test_t *test, uintptr_t addr);
|
||||
uintptr_t Test66F0(x86test_t *test, uintptr_t addr);
|
||||
uintptr_t Test67(x86test_t *test, int rep, uintptr_t addr);
|
||||
uintptr_t Test670F(x86test_t *test, int rep, uintptr_t addr);
|
||||
uintptr_t Test6766(x86test_t *test, int rep, uintptr_t addr);
|
||||
uintptr_t Test67660F(x86test_t *test, uintptr_t addr);
|
||||
uintptr_t TestD8(x86test_t *test, uintptr_t addr);
|
||||
uintptr_t TestD9(x86test_t *test, uintptr_t addr);
|
||||
uintptr_t TestDA(x86test_t *test, uintptr_t addr);
|
||||
uintptr_t TestDB(x86test_t *test, uintptr_t addr);
|
||||
uintptr_t TestDC(x86test_t *test, uintptr_t addr);
|
||||
uintptr_t TestDD(x86test_t *test, uintptr_t addr);
|
||||
uintptr_t TestDE(x86test_t *test, uintptr_t addr);
|
||||
uintptr_t TestDF(x86test_t *test, uintptr_t addr);
|
||||
uintptr_t TestF0(x86test_t *test, uintptr_t addr);
|
||||
uintptr_t TestF066(x86test_t *test, uintptr_t addr);
|
||||
uintptr_t TestF20F(x86test_t *test, uintptr_t addr, int *step);
|
||||
uintptr_t TestF30F(x86test_t *test, uintptr_t addr);
|
||||
#endif
|
||||
|
||||
void x86Syscall(x86emu_t *emu);
|
||||
void x86Int3(x86emu_t* emu);
|
||||
|
||||
@@ -1,7 +1,40 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t TestD8(x86test_t *test, uintptr_t addr)
|
||||
#else
|
||||
uintptr_t RunD8(x86emu_t *emu, uintptr_t addr)
|
||||
#endif
|
||||
{
|
||||
uint8_t nextop;
|
||||
float f;
|
||||
reg32_t *oped;
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t*emu = test->emu;
|
||||
#endif
|
||||
|
||||
nextop = F8;
|
||||
switch(nextop) {
|
||||
switch (nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
@@ -159,7 +192,9 @@
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
@@ -1,3 +1,38 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t TestD9(x86test_t *test, uintptr_t addr)
|
||||
#else
|
||||
uintptr_t RunD9(x86emu_t *emu, uintptr_t addr)
|
||||
#endif
|
||||
{
|
||||
uint8_t nextop;
|
||||
int32_t tmp32s;
|
||||
int64_t ll;
|
||||
float f;
|
||||
reg32_t *oped;
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t*emu = test->emu;
|
||||
#endif
|
||||
|
||||
nextop = F8;
|
||||
switch (nextop) {
|
||||
case 0xC0:
|
||||
@@ -206,7 +241,7 @@
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
case 0xEF:
|
||||
goto _default;
|
||||
return 0;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FLD ST0, Ed float */
|
||||
@@ -241,7 +276,9 @@
|
||||
case 4: /* FLDENV m */
|
||||
// warning, incomplete
|
||||
GET_ED;
|
||||
#ifndef TEST_INTERPRETER
|
||||
fpu_loadenv(emu, (char*)ED, 0);
|
||||
#endif
|
||||
break;
|
||||
case 5: /* FLDCW Ew */
|
||||
GET_EW;
|
||||
@@ -251,7 +288,9 @@
|
||||
case 6: /* FNSTENV m */
|
||||
// warning, incomplete
|
||||
GET_ED;
|
||||
#ifndef TEST_INTERPRETER
|
||||
fpu_savenv(emu, (char*)ED, 0);
|
||||
#endif
|
||||
// intruction pointer: 48bits
|
||||
// data (operand) pointer: 48bits
|
||||
// last opcode: 11bits save: 16bits restaured (1st and 2nd opcode only)
|
||||
@@ -261,6 +300,8 @@
|
||||
EW->word[0] = emu->cw.x16;
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -1,3 +1,37 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t TestDA(x86test_t *test, uintptr_t addr)
|
||||
#else
|
||||
uintptr_t RunDA(x86emu_t *emu, uintptr_t addr)
|
||||
#endif
|
||||
{
|
||||
uint8_t nextop;
|
||||
int32_t tmp32s;
|
||||
int64_t ll;
|
||||
float f;
|
||||
reg32_t *oped;
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t*emu = test->emu;
|
||||
#endif
|
||||
|
||||
nextop = F8;
|
||||
switch(nextop) {
|
||||
|
||||
@@ -66,8 +100,7 @@
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFD:
|
||||
UnimpOpcode(emu);
|
||||
break;
|
||||
return 0;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FIADD ST0, Ed int */
|
||||
@@ -105,3 +138,5 @@
|
||||
break;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -1,3 +1,37 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t TestDB(x86test_t *test, uintptr_t addr)
|
||||
#else
|
||||
uintptr_t RunDB(x86emu_t *emu, uintptr_t addr)
|
||||
#endif
|
||||
{
|
||||
uint8_t nextop;
|
||||
int32_t tmp32s;
|
||||
int64_t ll;
|
||||
float f;
|
||||
reg32_t *oped;
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t*emu = test->emu;
|
||||
#endif
|
||||
|
||||
nextop = F8;
|
||||
switch(nextop) {
|
||||
case 0xC0: /* FCMOVNB ST(0), ST(i) */
|
||||
@@ -93,7 +127,7 @@
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
goto _default;
|
||||
return 0;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FILD ST0, Ed */
|
||||
@@ -103,15 +137,16 @@
|
||||
break;
|
||||
case 1: /* FISTTP Ed, ST0 */
|
||||
GET_ED;
|
||||
tmp32s = ST0.d; // TODO: Handling of FPU Exception
|
||||
if(tmp32s==0x7fffffff && isgreater(ST0.d, (double)(int32_t)0x7fffffff))
|
||||
if(isgreater(ST0.d, (double)0x7fffffff) || isless(ST0.d, -(double)0x80000000U) || !isfinite(ST0.d))
|
||||
tmp32s = 0x80000000;
|
||||
else
|
||||
tmp32s = ST0.d; // TODO: Handling of FPU Exception
|
||||
fpu_do_pop(emu);
|
||||
ED->sdword[0] = tmp32s;
|
||||
break;
|
||||
case 2: /* FIST Ed, ST0 */
|
||||
GET_ED;
|
||||
if(isgreater(ST0.d, (double)(int32_t)0x7fffffff) || isless(ST0.d, -(double)(int32_t)0x7fffffff) || !isfinite(ST0.d))
|
||||
if(isgreater(ST0.d, (double)0x7fffffff) || isless(ST0.d, -(double)0x80000000U) || !isfinite(ST0.d))
|
||||
ED->sdword[0] = 0x80000000;
|
||||
else {
|
||||
volatile int32_t tmp = fpu_round(emu, ST0.d); // tmp to avoid BUS ERROR
|
||||
@@ -120,7 +155,7 @@
|
||||
break;
|
||||
case 3: /* FISTP Ed, ST0 */
|
||||
GET_ED;
|
||||
if(isgreater(ST0.d, (double)(int32_t)0x7fffffff) || isless(ST0.d, -(double)(int32_t)0x7fffffff) || !isfinite(ST0.d))
|
||||
if(isgreater(ST0.d, (double)0x7fffffff) || isless(ST0.d, -(double)0x80000000U) || !isfinite(ST0.d))
|
||||
ED->sdword[0] = 0x80000000;
|
||||
else {
|
||||
volatile int32_t tmp = fpu_round(emu, ST0.d); // tmp to avoid BUS ERROR
|
||||
@@ -129,14 +164,14 @@
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 5: /* FLD ST0, Et */
|
||||
GET_ED;
|
||||
GET_EDT;
|
||||
fpu_do_push(emu);
|
||||
memcpy(&STld(0).ld, ED, 10);
|
||||
LD2D(&STld(0).ld, &ST(0).d);
|
||||
STld(0).uref = ST0.q;
|
||||
break;
|
||||
case 7: /* FSTP tbyte */
|
||||
GET_ED;
|
||||
GET_EDT;
|
||||
if(ST0.q!=STld(0).uref)
|
||||
D2LD(&ST0.d, ED);
|
||||
else
|
||||
@@ -144,6 +179,8 @@
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -1,3 +1,37 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t TestDC(x86test_t *test, uintptr_t addr)
|
||||
#else
|
||||
uintptr_t RunDC(x86emu_t *emu, uintptr_t addr)
|
||||
#endif
|
||||
{
|
||||
uint8_t nextop;
|
||||
int32_t tmp32s;
|
||||
int64_t ll;
|
||||
double d;
|
||||
reg32_t *oped;
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t*emu = test->emu;
|
||||
#endif
|
||||
|
||||
nextop = F8;
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
@@ -82,7 +116,7 @@
|
||||
ST(nextop&7).d /= ST0.d;
|
||||
break;
|
||||
default:
|
||||
GET_ED;
|
||||
GET_ED8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FADD ST0, double */
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
@@ -150,7 +184,8 @@
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
return addr;
|
||||
}
|
||||
@@ -1,3 +1,37 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t TestDD(x86test_t *test, uintptr_t addr)
|
||||
#else
|
||||
uintptr_t RunDD(x86emu_t *emu, uintptr_t addr)
|
||||
#endif
|
||||
{
|
||||
uint8_t nextop;
|
||||
int32_t tmp32s;
|
||||
int64_t ll;
|
||||
double d;
|
||||
reg32_t *oped;
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t*emu = test->emu;
|
||||
#endif
|
||||
|
||||
nextop = F8;
|
||||
switch(nextop) {
|
||||
|
||||
@@ -79,12 +113,12 @@
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
goto _default;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FLD double */
|
||||
GET_ED;
|
||||
GET_ED8;
|
||||
fpu_do_push(emu);
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.d = *(double*)ED;
|
||||
@@ -93,17 +127,32 @@
|
||||
}
|
||||
break;
|
||||
case 1: /* FISTTP ED qword */
|
||||
GET_ED;
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
*(int64_t*)ED = ST0.d;
|
||||
else {
|
||||
int64_t i64 = ST0.d;
|
||||
GET_ED8;
|
||||
if(!(((uintptr_t)ED)&7)) {
|
||||
if(STll(0).sref==ST(0).sq)
|
||||
*(int64_t*)ED = STll(0).sq;
|
||||
else {
|
||||
if(isgreater(ST0.d, (double)0x7fffffffffffffffLL) || isless(ST0.d, -(double)0x8000000000000000LL) || !isfinite(ST0.d))
|
||||
*(uint64_t*)ED = 0x8000000000000000LL;
|
||||
else
|
||||
*(int64_t*)ED = ST0.d;
|
||||
}
|
||||
} else {
|
||||
int64_t i64;
|
||||
if(STll(0).sref==ST(0).sq)
|
||||
i64 = STll(0).sq;
|
||||
else {
|
||||
if(isgreater(ST0.d, (double)0x7fffffffffffffffLL) || isless(ST0.d, -(double)0x8000000000000000LL) || !isfinite(ST0.d))
|
||||
i64 = 0x8000000000000000LL;
|
||||
else
|
||||
i64 = ST0.d;
|
||||
}
|
||||
memcpy(ED, &i64, sizeof(int64_t));
|
||||
}
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 2: /* FST double */
|
||||
GET_ED;
|
||||
GET_ED8;
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
*(double*)ED = ST0.d;
|
||||
else {
|
||||
@@ -111,7 +160,7 @@
|
||||
}
|
||||
break;
|
||||
case 3: /* FSTP double */
|
||||
GET_ED;
|
||||
GET_ED8;
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
*(double*)ED = ST0.d;
|
||||
else {
|
||||
@@ -120,8 +169,10 @@
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 4: /* FRSTOR m108byte */
|
||||
GET_ED;
|
||||
GET_ED_;
|
||||
#ifndef TEST_INTERPRETER
|
||||
fpu_loadenv(emu, (char*)ED, 0);
|
||||
#endif
|
||||
// get the STx
|
||||
{
|
||||
char* p =(char*)ED;
|
||||
@@ -133,9 +184,10 @@
|
||||
}
|
||||
break;
|
||||
case 6: /* FNSAVE m108byte */
|
||||
GET_ED;
|
||||
GET_ED_;
|
||||
// ENV first...
|
||||
// warning, incomplete
|
||||
#ifndef TEST_INTERPRETER
|
||||
fpu_savenv(emu, (char*)ED, 0);
|
||||
// save the STx
|
||||
{
|
||||
@@ -146,6 +198,7 @@
|
||||
p+=10;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
reset_fpu(emu);
|
||||
break;
|
||||
case 7: /* FNSTSW m2byte */
|
||||
@@ -154,6 +207,8 @@
|
||||
*(uint16_t*)ED = emu->sw.x16;
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -1,3 +1,37 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t TestDE(x86test_t *test, uintptr_t addr)
|
||||
#else
|
||||
uintptr_t RunDE(x86emu_t *emu, uintptr_t addr)
|
||||
#endif
|
||||
{
|
||||
uint8_t nextop;
|
||||
int32_t tmp32s;
|
||||
int64_t ll;
|
||||
double d;
|
||||
reg32_t *oped;
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t*emu = test->emu;
|
||||
#endif
|
||||
|
||||
nextop = F8;
|
||||
switch (nextop) {
|
||||
case 0xC0: /* FADDP STx, ST0 */
|
||||
@@ -95,7 +129,7 @@
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
goto _default;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
@@ -124,6 +158,8 @@
|
||||
ST0.d = (double)EW->sword[0] / ST0.d;
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -1,3 +1,37 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t TestDF(x86test_t *test, uintptr_t addr)
|
||||
#else
|
||||
uintptr_t RunDF(x86emu_t *emu, uintptr_t addr)
|
||||
#endif
|
||||
{
|
||||
uint8_t nextop;
|
||||
int16_t tmp16s;
|
||||
int64_t tmp64s;
|
||||
double d;
|
||||
reg32_t *oped;
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t*emu = test->emu;
|
||||
#endif
|
||||
|
||||
nextop = F8;
|
||||
switch (nextop) {
|
||||
case 0xC0: /* FFREEP STx */
|
||||
@@ -25,8 +59,11 @@
|
||||
break;
|
||||
|
||||
case 0xE0: /* FNSTSW AX */
|
||||
emu->sw.f.F87_TOP = emu->top&7;
|
||||
R_AX = emu->sw.x16;
|
||||
{
|
||||
x87flags_t sw = emu->sw;
|
||||
sw.f.F87_TOP = emu->top&7;
|
||||
R_AX = sw.x16;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE8: /* FUCOMIP ST0, STx */
|
||||
@@ -84,7 +121,7 @@
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
goto _default;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
@@ -96,32 +133,35 @@
|
||||
break;
|
||||
case 1: /* FISTTP Ew, ST0 */
|
||||
GET_EW;
|
||||
tmp16s = ST0.d;
|
||||
if(isgreater(ST0.d, (double)(int32_t)0x7fff) || isless(ST0.d, -(double)(int32_t)0x8000) || !isfinite(ST0.d))
|
||||
tmp16s = 0x8000;
|
||||
else
|
||||
tmp16s = ST0.d;
|
||||
EW->sword[0] = tmp16s;
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 2: /* FIST Ew, ST0 */
|
||||
GET_EW;
|
||||
if(isgreater(ST0.d, (double)(int32_t)0x7fff) || isless(ST0.d, -(double)(int32_t)0x7fff) || !isfinite(ST0.d))
|
||||
if(isgreater(ST0.d, (double)(int32_t)0x7fff) || isless(ST0.d, -(double)(int32_t)0x8000) || !isfinite(ST0.d))
|
||||
EW->sword[0] = 0x8000;
|
||||
else
|
||||
EW->sword[0] = fpu_round(emu, ST0.d);
|
||||
break;
|
||||
case 3: /* FISTP Ew, ST0 */
|
||||
GET_EW;
|
||||
if(isgreater(ST0.d, (double)(int32_t)0x7fff) || isless(ST0.d, -(double)(int32_t)0x7fff) || !isfinite(ST0.d))
|
||||
if(isgreater(ST0.d, (double)(int32_t)0x7fff) || isless(ST0.d, -(double)(int32_t)0x8000) || !isfinite(ST0.d))
|
||||
EW->sword[0] = 0x8000;
|
||||
else
|
||||
EW->sword[0] = fpu_round(emu, ST0.d);
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 4: /* FBLD ST0, tbytes */
|
||||
GET_ED;
|
||||
GET_EDT;
|
||||
fpu_do_push(emu);
|
||||
fpu_fbld(emu, (uint8_t*)ED);
|
||||
break;
|
||||
case 5: /* FILD ST0, Gq */
|
||||
GET_ED;
|
||||
GET_ED8;
|
||||
tmp64s = *(int64_t*)ED;
|
||||
fpu_do_push(emu);
|
||||
ST0.d = tmp64s;
|
||||
@@ -129,19 +169,19 @@
|
||||
STll(0).sref = ST0.sq;
|
||||
break;
|
||||
case 6: /* FBSTP tbytes, ST0 */
|
||||
GET_ED;
|
||||
GET_EDT;
|
||||
fpu_fbst(emu, (uint8_t*)ED);
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 7: /* FISTP i64 */
|
||||
GET_ED;
|
||||
GET_ED8;
|
||||
if((uintptr_t)ED & 0x7) {
|
||||
// un-aligned!
|
||||
if(STll(0).sref==ST(0).sq)
|
||||
memcpy(ED, &STll(0).sq, sizeof(int64_t));
|
||||
else {
|
||||
int64_t i64;
|
||||
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, -(double)(int64_t)0x7fffffffffffffffLL) || !isfinite(ST0.d))
|
||||
if(isgreater(ST0.d, (double)0x7fffffffffffffffLL) || isless(ST0.d, -(double)0x8000000000000000LL) || !isfinite(ST0.d))
|
||||
i64 = 0x8000000000000000LL;
|
||||
else
|
||||
i64 = fpu_round(emu, ST0.d);
|
||||
@@ -151,7 +191,7 @@
|
||||
if(STll(0).sref==ST(0).sq)
|
||||
*(int64_t*)ED = STll(0).sq;
|
||||
else {
|
||||
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, -(double)(int64_t)0x7fffffffffffffffLL) || !isfinite(ST0.d))
|
||||
if(isgreater(ST0.d, (double)0x7fffffffffffffffLL) || isless(ST0.d, -(double)0x8000000000000000LL) || !isfinite(ST0.d))
|
||||
*(int64_t*)ED = 0x8000000000000000LL;
|
||||
else
|
||||
*(int64_t*)ED = fpu_round(emu, ST0.d);
|
||||
@@ -160,6 +200,8 @@
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,625 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box86context.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "bridge.h"
|
||||
#include "signals.h"
|
||||
#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t TestF0(x86test_t *test, uintptr_t addr)
|
||||
#else
|
||||
uintptr_t RunF0(x86emu_t *emu, uintptr_t addr)
|
||||
#endif
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
reg32_t *oped;
|
||||
uint8_t tmp8u, tmp8u2;
|
||||
int8_t tmp8s;
|
||||
uint16_t tmp16u, tmp16u2;
|
||||
int16_t tmp16s;
|
||||
uint32_t tmp32u, tmp32u2, tmp32u3;
|
||||
int32_t tmp32s, tmp32s2;
|
||||
uint64_t tmp64u;
|
||||
int64_t tmp64s;
|
||||
double d;
|
||||
float f;
|
||||
int64_t ll;
|
||||
sse_regs_t *opex, eax1;
|
||||
mmx87_regs_t *opem, eam1;
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t *emu = test->emu;
|
||||
#endif
|
||||
opcode = F8;
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
|
||||
#define GO(B, OP) \
|
||||
case B+0: \
|
||||
nextop = F8; \
|
||||
GET_EB; \
|
||||
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; \
|
||||
GET_ED; \
|
||||
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; \
|
||||
GET_EB; \
|
||||
GB = OP##8(emu, GB, EB->byte[0]); \
|
||||
break; \
|
||||
case B+3: \
|
||||
nextop = F8; \
|
||||
GET_ED; \
|
||||
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); \
|
||||
break;
|
||||
#else
|
||||
#define GO(B, OP) \
|
||||
case B+0: \
|
||||
nextop = F8; \
|
||||
GET_EB; \
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);\
|
||||
EB->byte[0] = OP##8(emu, EB->byte[0], GB); \
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);\
|
||||
break; \
|
||||
case B+1: \
|
||||
nextop = F8; \
|
||||
GET_ED; \
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);\
|
||||
ED->dword[0] = OP##32(emu, ED->dword[0], GD.dword[0]); \
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);\
|
||||
break; \
|
||||
case B+2: \
|
||||
nextop = F8; \
|
||||
GET_EB; \
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);\
|
||||
GB = OP##8(emu, GB, EB->byte[0]); \
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);\
|
||||
break; \
|
||||
case B+3: \
|
||||
nextop = F8; \
|
||||
GET_ED; \
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);\
|
||||
GD.dword[0] = OP##32(emu, GD.dword[0], ED->dword[0]); \
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);\
|
||||
break; \
|
||||
case B+4: \
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);\
|
||||
R_AL = OP##8(emu, R_AL, F8); \
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);\
|
||||
break; \
|
||||
case B+5: \
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);\
|
||||
R_EAX = OP##32(emu, R_EAX, F32); \
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);\
|
||||
break;
|
||||
#endif
|
||||
GO(0x00, add) /* ADD 0x00 -> 0x05 */
|
||||
GO(0x08, or) /* OR 0x08 -> 0x0D */
|
||||
GO(0x10, adc) /* ADC 0x10 -> 0x15 */
|
||||
GO(0x18, sbb) /* SBB 0x18 -> 0x1D */
|
||||
GO(0x20, and) /* AND 0x20 -> 0x25 */
|
||||
GO(0x28, sub) /* SUB 0x28 -> 0x2D */
|
||||
GO(0x30, xor) /* XOR 0x30 -> 0x35 */
|
||||
#undef GO
|
||||
|
||||
case 0x0f:
|
||||
opcode = F8;
|
||||
switch (opcode) {
|
||||
case 0xB0: /* CMPXCHG Eb,Gb */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GET_EB;
|
||||
#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
|
||||
do {
|
||||
tmp8u = arm_lock_read_b(EB);
|
||||
cmp8(emu, R_AL, tmp8u);
|
||||
if(ACCESS_FLAG(F_ZF)) {
|
||||
tmp32s = arm_lock_write_b(EB, GB);
|
||||
} else {
|
||||
R_AL = tmp8u;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
cmp8(emu, R_AL, EB->byte[0]);
|
||||
if(ACCESS_FLAG(F_ZF)) {
|
||||
EB->byte[0] = GB;
|
||||
} else {
|
||||
R_AL = EB->byte[0];
|
||||
}
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
case 0xB1: /* CMPXCHG Ed,Gd */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
|
||||
if(((uintptr_t)ED)&3) {
|
||||
do {
|
||||
tmp32u = ED->dword[0] & ~0xff;
|
||||
tmp32u |= arm_lock_read_b(ED);
|
||||
cmp32(emu, R_EAX, tmp32u);
|
||||
if(ACCESS_FLAG(F_ZF)) {
|
||||
tmp32s = arm_lock_write_b(ED, GD.dword[0] & 0xff);
|
||||
if(!tmp32s)
|
||||
ED->dword[0] = GD.dword[0];
|
||||
} else {
|
||||
R_EAX = tmp32u;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
} else {
|
||||
do {
|
||||
tmp32u = arm_lock_read_d(ED);
|
||||
cmp32(emu, R_EAX, tmp32u);
|
||||
if(ACCESS_FLAG(F_ZF)) {
|
||||
tmp32s = arm_lock_write_d(ED, GD.dword[0]);
|
||||
} else {
|
||||
R_EAX = tmp32u;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
}
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
cmp32(emu, R_EAX, ED->dword[0]);
|
||||
if(ACCESS_FLAG(F_ZF)) {
|
||||
ED->dword[0] = GD.dword[0];
|
||||
} else {
|
||||
R_EAX = ED->dword[0];
|
||||
}
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
case 0xB3: /* BTR Ed,Gd */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp8u = GD.byte[0];
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
{
|
||||
#ifdef TEST_INTERPRETER
|
||||
test->memaddr=((test->memaddr)+(tmp8u>>5));
|
||||
*(uint32_t*)test->mem = *(uint32_t*)test->memaddr;
|
||||
#else
|
||||
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
|
||||
#endif
|
||||
}
|
||||
tmp8u&=31;
|
||||
#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
|
||||
do {
|
||||
tmp32u = arm_lock_read_d(ED);
|
||||
if(tmp32u & (1<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
tmp32u ^= (1<<tmp8u);
|
||||
tmp32s = arm_lock_write_d(ED, tmp32u);
|
||||
} else {
|
||||
CLEAR_FLAG(F_CF);
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
if(ED->dword[0] & (1<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
ED->dword[0] ^= (1<<tmp8u);
|
||||
} else
|
||||
CLEAR_FLAG(F_CF);
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
case 0xBA:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 4: /* BT Ed,Ib */
|
||||
CHECK_FLAGS(emu);
|
||||
GET_ED;
|
||||
tmp8u = F8;
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
{
|
||||
#ifdef TEST_INTERPRETER
|
||||
test->memaddr=((test->memaddr)+(tmp8u>>5));
|
||||
*(uint32_t*)test->mem = *(uint32_t*)test->memaddr;
|
||||
#else
|
||||
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
|
||||
#endif
|
||||
}
|
||||
tmp8u&=31;
|
||||
#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
|
||||
if(arm_lock_read_d(ED) & (1<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else
|
||||
CLEAR_FLAG(F_CF);
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
if(ED->dword[0] & (1<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else
|
||||
CLEAR_FLAG(F_CF);
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
case 5: /* BTS Ed, Ib */
|
||||
CHECK_FLAGS(emu);
|
||||
GET_ED;
|
||||
tmp8u = F8;
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
{
|
||||
#ifdef TEST_INTERPRETER
|
||||
test->memaddr=((test->memaddr)+(tmp8u>>5));
|
||||
*(uint32_t*)test->mem = *(uint32_t*)test->memaddr;
|
||||
#else
|
||||
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
|
||||
#endif
|
||||
}
|
||||
tmp8u&=31;
|
||||
#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
|
||||
do {
|
||||
tmp32u = arm_lock_read_d(ED);
|
||||
if(tmp32u & (1<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
tmp32s = 0;
|
||||
} else {
|
||||
CLEAR_FLAG(F_CF);
|
||||
tmp32u ^= (1<<tmp8u);
|
||||
tmp32s = arm_lock_write_d(ED, tmp32u);
|
||||
}
|
||||
} while(tmp32s);
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
if(ED->dword[0] & (1<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
} else {
|
||||
CLEAR_FLAG(F_CF);
|
||||
ED->dword[0] ^= (1<<tmp8u);
|
||||
}
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
case 6: /* BTR Ed, Ib */
|
||||
CHECK_FLAGS(emu);
|
||||
GET_ED;
|
||||
tmp8u = F8;
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
{
|
||||
#ifdef TEST_INTERPRETER
|
||||
test->memaddr=((test->memaddr)+(tmp8u>>5));
|
||||
*(uint32_t*)test->mem = *(uint32_t*)test->memaddr;
|
||||
#else
|
||||
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
|
||||
#endif
|
||||
}
|
||||
tmp8u&=31;
|
||||
#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
|
||||
do {
|
||||
tmp32u = arm_lock_read_d(ED);
|
||||
if(tmp32u & (1<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
tmp32u ^= (1<<tmp8u);
|
||||
tmp32s = arm_lock_write_d(ED, tmp32u);
|
||||
} else {
|
||||
CLEAR_FLAG(F_CF);
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
if(ED->dword[0] & (1<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
ED->dword[0] ^= (1<<tmp8u);
|
||||
} else
|
||||
CLEAR_FLAG(F_CF);
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
return addr-3; //unfetchall 0F BA nextop but not F0, continue normal without LOCK
|
||||
}
|
||||
break;
|
||||
case 0xBB: /* BTC Ed,Gd */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp8u = GD.byte[0];
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
{
|
||||
#ifdef TEST_INTERPRETER
|
||||
test->memaddr=((test->memaddr)+(tmp8u>>5));
|
||||
*(uint32_t*)test->mem = *(uint32_t*)test->memaddr;
|
||||
#else
|
||||
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
|
||||
#endif
|
||||
}
|
||||
tmp8u&=31;
|
||||
#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
|
||||
do {
|
||||
tmp32u = arm_lock_read_d(ED);
|
||||
if(tmp32u & (1<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
} else {
|
||||
CLEAR_FLAG(F_CF);
|
||||
}
|
||||
tmp32u ^= (1<<tmp8u);
|
||||
} while(arm_lock_write_d(ED, tmp32u));
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
if(ED->dword[0] & (1<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else
|
||||
CLEAR_FLAG(F_CF);
|
||||
ED->dword[0] ^= (1<<tmp8u);
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
case 0xC0: /* XADD Gb,Eb */
|
||||
nextop = F8;
|
||||
GET_EB;
|
||||
#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
|
||||
do {
|
||||
tmp8u = arm_lock_read_b(EB);
|
||||
tmp8u2 = add8(emu, tmp8u, GB);
|
||||
} while (arm_lock_write_b(EB, tmp8u2));
|
||||
GB = tmp8u;
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
tmp8u = add8(emu, EB->byte[0], GB);
|
||||
GB = EB->byte[0];
|
||||
EB->byte[0] = tmp8u;
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
case 0xC1: /* XADD Gd,Ed */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
|
||||
if(((uintptr_t)ED)&3) {
|
||||
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;
|
||||
} else {
|
||||
do {
|
||||
tmp32u = arm_lock_read_d(ED);
|
||||
tmp32u2 = add32(emu, tmp32u, GD.dword[0]);
|
||||
} while(arm_lock_write_d(ED, tmp32u2));
|
||||
}
|
||||
GD.dword[0] = tmp32u;
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
tmp32u = add32(emu, ED->dword[0], GD.dword[0]);
|
||||
GD.dword[0] = ED->dword[0];
|
||||
ED->dword[0] = tmp32u;
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
case 0xC7: /* CMPXCHG8B Gq */
|
||||
nextop = F8;
|
||||
GET_ED8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 1:
|
||||
CHECK_FLAGS(emu);
|
||||
#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
|
||||
if(((uintptr_t)ED)&7) {
|
||||
// unaligned!!!
|
||||
uint64_t ref = R_EDX;
|
||||
ref = ref<<32 | R_EAX;
|
||||
void* p = (void*)(((uintptr_t)ED + 3)&~3);
|
||||
int d = (((uintptr_t)p - (uintptr_t)ED))*8;
|
||||
do {
|
||||
uint64_t m = *(uint64_t*)ED;
|
||||
m&=~((0xffffffffLL)<<d);
|
||||
tmp32u = arm_lock_read_d(p);
|
||||
m|=((uint64_t)tmp32u)<<d;
|
||||
if(ref == m) {
|
||||
SET_FLAG(F_ZF);
|
||||
m = ((uint64_t)R_ECX)<<32 | R_EBX;
|
||||
tmp32u2 = m>>d;
|
||||
tmp32s = arm_lock_write_d(p, tmp32u2);
|
||||
if(!tmp32s)
|
||||
*(uint64_t*)ED = m;
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
R_EAX = m&0xffffffff;
|
||||
R_EDX = m>>32;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
} else
|
||||
do {
|
||||
arm_lock_read_dd(&tmp32u, &tmp32u2, ED);
|
||||
if(R_EAX == tmp32u && R_EDX == tmp32u2) {
|
||||
SET_FLAG(F_ZF);
|
||||
tmp32s = arm_lock_write_dd(R_EBX, R_ECX, ED);
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
R_EAX = tmp32u;
|
||||
R_EDX = tmp32u2;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
tmp32u = ED->dword[0];
|
||||
tmp32u2= ED->dword[1];
|
||||
if(R_EAX == tmp32u && R_EDX == tmp32u2) {
|
||||
SET_FLAG(F_ZF);
|
||||
ED->dword[0] = R_EBX;
|
||||
ED->dword[1] = R_ECX;
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
R_EAX = tmp32u;
|
||||
R_EDX = tmp32u2;
|
||||
}
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
printf_log(LOG_NONE, "Illegal Opcode 0xF0 0xC7 0x%02X 0x%02X\n", nextop, PK(0));
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// trigger invalid lock?
|
||||
return addr-2; // unfetch 0F and nextop but not F0
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x66:
|
||||
#ifdef TEST_INTERPRETER
|
||||
return TestF066(test, addr);
|
||||
#else
|
||||
return RunF066(emu, addr);
|
||||
#endif
|
||||
|
||||
case 0x81: /* GRP Ed,Id */
|
||||
case 0x83: /* GRP Ed,Ib */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
if(opcode==0x83) {
|
||||
tmp32s = F8S;
|
||||
tmp32u = (uint32_t)tmp32s;
|
||||
} else
|
||||
tmp32u = F32;
|
||||
#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
|
||||
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;
|
||||
}
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: ED->dword[0] = add32(emu, ED->dword[0], tmp32u); break;
|
||||
case 1: ED->dword[0] = or32(emu, ED->dword[0], tmp32u); break;
|
||||
case 2: ED->dword[0] = adc32(emu, ED->dword[0], tmp32u); break;
|
||||
case 3: ED->dword[0] = sbb32(emu, ED->dword[0], tmp32u); break;
|
||||
case 4: ED->dword[0] = and32(emu, ED->dword[0], tmp32u); break;
|
||||
case 5: ED->dword[0] = sub32(emu, ED->dword[0], tmp32u); break;
|
||||
case 6: ED->dword[0] = xor32(emu, ED->dword[0], tmp32u); break;
|
||||
case 7: cmp32(emu, ED->dword[0], tmp32u); break;
|
||||
}
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
case 0x86: /* XCHG Eb,Gb */
|
||||
case 0x87: /* XCHG Ed,Gd */
|
||||
return addr-1; // let the normal XCHG execute, it have integrated LOCK
|
||||
case 0x90: // This is xchg reg, reg, so let's ignore the LOCK prefix...
|
||||
case 0x91:
|
||||
case 0x92:
|
||||
case 0x93:
|
||||
case 0x94:
|
||||
case 0x95:
|
||||
case 0x96:
|
||||
case 0x97:
|
||||
return addr-1;
|
||||
|
||||
case 0xFF: /* GRP 5 Ed */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* INC Ed */
|
||||
#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
|
||||
if((uintptr_t)ED&3) {
|
||||
//meh.
|
||||
do {
|
||||
tmp32u = ED->dword[0];
|
||||
tmp32u &=~0xff;
|
||||
tmp32u |= arm_lock_read_b(ED);
|
||||
tmp32u = inc32(emu, tmp32u);
|
||||
} while(arm_lock_write_b(ED, tmp32u&0xff));
|
||||
ED->dword[0] = tmp32u;
|
||||
} else
|
||||
do {
|
||||
tmp32u = arm_lock_read_d(ED);
|
||||
} while(arm_lock_write_d(ED, inc32(emu, tmp32u)));
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
ED->dword[0] = inc32(emu, ED->dword[0]);
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
case 1: /* DEC Ed */
|
||||
#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
|
||||
if((uintptr_t)ED&3) {
|
||||
//meh.
|
||||
do {
|
||||
tmp32u = ED->dword[0];
|
||||
tmp32u &=~0xff;
|
||||
tmp32u |= arm_lock_read_b(ED);
|
||||
tmp32u = dec32(emu, tmp32u);
|
||||
} while(arm_lock_write_b(ED, tmp32u&0xff));
|
||||
ED->dword[0] = tmp32u;
|
||||
} else
|
||||
do {
|
||||
tmp32u = arm_lock_read_d(ED);
|
||||
} while(arm_lock_write_d(ED, dec32(emu, tmp32u)));
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
ED->dword[0] = dec32(emu, ED->dword[0]);
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
printf_log(LOG_NONE, "Illegal Opcode 0xF0 0xFF 0x%02X 0x%02X\n", nextop, PK(0));
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box86context.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "bridge.h"
|
||||
#include "signals.h"
|
||||
#if defined(DYNAREC) && !defined(TEST_INTERPRETER)
|
||||
#include "../dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t TestF066(x86test_t *test, uintptr_t addr)
|
||||
#else
|
||||
uintptr_t RunF066(x86emu_t *emu, uintptr_t addr)
|
||||
#endif
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
reg32_t *oped;
|
||||
uint8_t tmp8u, tmp8u2;
|
||||
int8_t tmp8s;
|
||||
uint16_t tmp16u, tmp16u2;
|
||||
int16_t tmp16s;
|
||||
uint32_t tmp32u, tmp32u2, tmp32u3;
|
||||
int32_t tmp32s, tmp32s2;
|
||||
uint64_t tmp64u;
|
||||
int64_t tmp64s;
|
||||
double d;
|
||||
float f;
|
||||
int64_t ll;
|
||||
sse_regs_t *opex, eax1;
|
||||
mmx87_regs_t *opem, eam1;
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t *emu = test->emu;
|
||||
#endif
|
||||
opcode = F8;
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x0f:
|
||||
opcode = F8;
|
||||
switch (opcode) {
|
||||
case 0xB1: /* CMPXCHG Ew,Gw */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
#ifdef DYNAREC
|
||||
do {
|
||||
tmp16u = arm_lock_read_h(ED);
|
||||
cmp16(emu, R_AX, tmp16u);
|
||||
if(ACCESS_FLAG(F_ZF)) {
|
||||
tmp32s = arm_lock_write_h(ED, GW.word[0]);
|
||||
} else {
|
||||
R_AX = tmp16u;
|
||||
tmp32s = 0;
|
||||
}
|
||||
} while(tmp32s);
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
GET_EW;
|
||||
cmp16(emu, R_AX, EW->word[0]);
|
||||
if(ACCESS_FLAG(F_ZF)) {
|
||||
EW->word[0] = GW.word[0];
|
||||
} else {
|
||||
R_AX = EW->word[0];
|
||||
}
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0x81: /* GRP Ed,Iw */
|
||||
case 0x83: /* GRP Ed,Ib */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
if(opcode==0x83) {
|
||||
tmp16s = F8S;
|
||||
tmp16u = (uint32_t)tmp16s;
|
||||
} else
|
||||
tmp16u = F16;
|
||||
#ifdef DYNAREC
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: do { tmp16u2 = arm_lock_read_h(EW);} while(arm_lock_write_h(EW, add16(emu, tmp16u2, tmp16u))); break;
|
||||
case 1: do { tmp16u2 = arm_lock_read_h(EW);} while(arm_lock_write_h(EW, or16(emu, tmp16u2, tmp16u))); break;
|
||||
case 2: do { tmp16u2 = arm_lock_read_h(EW);} while(arm_lock_write_h(EW, adc16(emu, tmp16u2, tmp16u))); break;
|
||||
case 3: do { tmp16u2 = arm_lock_read_h(EW);} while(arm_lock_write_h(EW, sbb16(emu, tmp16u2, tmp16u))); break;
|
||||
case 4: do { tmp16u2 = arm_lock_read_h(EW);} while(arm_lock_write_h(EW, and16(emu, tmp16u2, tmp16u))); break;
|
||||
case 5: do { tmp16u2 = arm_lock_read_h(EW);} while(arm_lock_write_h(EW, sub16(emu, tmp16u2, tmp16u))); break;
|
||||
case 6: do { tmp16u2 = arm_lock_read_h(EW);} while(arm_lock_write_h(EW, xor16(emu, tmp16u2, tmp16u))); break;
|
||||
case 7: cmp16(emu, ED->dword[0], tmp16u); break;
|
||||
}
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: EW->word[0] = add16(emu, EW->word[0], tmp16u); break;
|
||||
case 1: EW->word[0] = or16(emu, EW->word[0], tmp16u); break;
|
||||
case 2: EW->word[0] = adc16(emu, EW->word[0], tmp16u); break;
|
||||
case 3: EW->word[0] = sbb16(emu, EW->word[0], tmp16u); break;
|
||||
case 4: EW->word[0] = and16(emu, EW->word[0], tmp16u); break;
|
||||
case 5: EW->word[0] = sub16(emu, EW->word[0], tmp16u); break;
|
||||
case 6: EW->word[0] = xor16(emu, EW->word[0], tmp16u); break;
|
||||
case 7: cmp16(emu, EW->word[0], tmp16u); break;
|
||||
}
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* INC Ed */
|
||||
#ifdef DYNAREC
|
||||
if((uintptr_t)ED&1) {
|
||||
//meh.
|
||||
do {
|
||||
tmp16u = ED->dword[0];
|
||||
tmp16u &=~0xff;
|
||||
tmp16u |= arm_lock_read_b(ED);
|
||||
tmp16u = inc16(emu, tmp16u);
|
||||
} while(arm_lock_write_b(ED, tmp16u&0xff));
|
||||
ED->dword[0] = tmp16u;
|
||||
} else
|
||||
do {
|
||||
tmp16u = arm_lock_read_h(ED);
|
||||
} while(arm_lock_write_h(ED, inc16(emu, tmp16u)));
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
ED->dword[0] = inc32(emu, ED->dword[0]);
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
case 1: /* DEC Ed */
|
||||
#ifdef DYNAREC
|
||||
if((uintptr_t)ED&1) {
|
||||
//meh.
|
||||
do {
|
||||
tmp16u = ED->dword[0];
|
||||
tmp16u &=~0xff;
|
||||
tmp16u |= arm_lock_read_b(ED);
|
||||
tmp16u = dec16(emu, tmp16u);
|
||||
} while(arm_lock_write_b(ED, tmp16u&0xff));
|
||||
ED->dword[0] = tmp16u;
|
||||
} else
|
||||
do {
|
||||
tmp16u = arm_lock_read_h(ED);
|
||||
} while(arm_lock_write_h(ED, dec16(emu, tmp16u)));
|
||||
#else
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
ED->dword[0] = dec32(emu, ED->dword[0]);
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -1,4 +1,51 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box86context.h"
|
||||
#include "bridge.h"
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t TestF20F(x86test_t *test, uintptr_t addr, int *step)
|
||||
#else
|
||||
uintptr_t RunF20F(x86emu_t *emu, uintptr_t addr, int *step)
|
||||
#endif
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
int8_t tmp8s;
|
||||
uint8_t tmp8u;
|
||||
int32_t tmp32s;
|
||||
int64_t tmp64s0, tmp64s1;
|
||||
reg32_t *oped, *opgd;
|
||||
sse_regs_t *opex, *opgx, eax1;
|
||||
mmx87_regs_t *opgm;
|
||||
#ifndef NOALIGN
|
||||
int is_nan;
|
||||
#endif
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t*emu = test->emu;
|
||||
#endif
|
||||
|
||||
opcode = F8;
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x10: /* MOVSD Gx, Ex */
|
||||
@@ -30,7 +77,7 @@
|
||||
case 0x2C: /* CVTTSD2SI Gd, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
if(isnan(EX->d[0]) || isinf(EX->d[0]) || EX->d[0]>0x7fffffff)
|
||||
if(!isfinite(EX->d[0]) || EX->d[0]>(double)0x7fffffff || EX->d[0]<-(double)0x80000000U)
|
||||
GD.dword[0] = 0x80000000;
|
||||
else
|
||||
GD.sdword[0] = EX->d[0];
|
||||
@@ -38,7 +85,7 @@
|
||||
case 0x2D: /* CVTSD2SI Gd, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
if(isnan(EX->d[0]) || isinf(EX->d[0]) || EX->d[0]>0x7fffffff)
|
||||
if(!isfinite(EX->d[0]) || EX->d[0]>(double)0x7fffffff || EX->d[0]<-(double)0x80000000U)
|
||||
GD.dword[0] = 0x80000000;
|
||||
else
|
||||
switch(emu->mxcsr.f.MXCSR_RC) {
|
||||
@@ -255,7 +302,7 @@
|
||||
|
||||
GOCOND(0x80
|
||||
, tmp32s = F32S; CHECK_FLAGS(emu);
|
||||
, ip += tmp32s;
|
||||
, addr += tmp32s; STEP3;
|
||||
) /* 0x80 -> 0x8F Jxx */
|
||||
|
||||
case 0xC2: /* CMPSD Gx, Ex, Ib */
|
||||
@@ -295,7 +342,7 @@
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<2; ++i)
|
||||
if(isnan(EX->d[i]) || isinf(EX->d[i]) || EX->d[i]>0x7fffffff)
|
||||
if(!isfinite(EX->d[i]) || EX->d[i]>(double)0x7fffffff || EX->d[i]<-(double)0x80000000U)
|
||||
GX.ud[i] = 0x80000000;
|
||||
else
|
||||
switch(emu->mxcsr.f.MXCSR_RC) {
|
||||
@@ -322,6 +369,7 @@
|
||||
break;
|
||||
|
||||
default:
|
||||
goto _default;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
@@ -1,4 +1,49 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box86context.h"
|
||||
#include "bridge.h"
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
#ifdef TEST_INTERPRETER
|
||||
uintptr_t TestF30F(x86test_t *test, uintptr_t addr)
|
||||
#else
|
||||
uintptr_t RunF30F(x86emu_t *emu, uintptr_t addr)
|
||||
#endif
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
int8_t tmp8s;
|
||||
uint8_t tmp8u;
|
||||
uint32_t tmp32u;
|
||||
int64_t tmp64s;
|
||||
uint64_t tmp64u;
|
||||
reg32_t *oped, *opgd;
|
||||
sse_regs_t *opex, *opgx, eax1;
|
||||
mmx87_regs_t *opem;
|
||||
#ifdef TEST_INTERPRETER
|
||||
x86emu_t*emu = test->emu;
|
||||
#endif
|
||||
|
||||
opcode = F8;
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x10: /* MOVSS Gx Ex */
|
||||
@@ -47,7 +92,7 @@
|
||||
case 0x2C: /* CVTTSS2SI Gd, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
if(isnanf(EX->f[0]) || isinff(EX->f[0]) || EX->f[0]>0x7fffffff)
|
||||
if(isnanf(EX->f[0]) || isinff(EX->f[0]) || EX->f[0]>=(float)0x80000000U || EX->f[0]<-(float)0x80000000U)
|
||||
GD.dword[0] = 0x80000000;
|
||||
else
|
||||
GD.sdword[0] = EX->f[0];
|
||||
@@ -55,7 +100,7 @@
|
||||
case 0x2D: /* CVTSS2SI Gd, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
if(isnanf(EX->f[0]) || isinff(EX->f[0]) || EX->f[0]>0x7fffffff)
|
||||
if(isnanf(EX->f[0]) || isinff(EX->f[0]) || EX->f[0]>=(float)0x80000000U || EX->f[0]<-(float)0x80000000U)
|
||||
GD.dword[0] = 0x80000000;
|
||||
else
|
||||
switch(emu->mxcsr.f.MXCSR_RC) {
|
||||
@@ -109,7 +154,7 @@
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<4; ++i)
|
||||
if(isnanf(EX->f[i]) || isinff(EX->f[i]) || EX->f[i]>0x7fffffff)
|
||||
if(isnanf(EX->f[i]) || isinff(EX->f[i]) || EX->f[i]>=(float)0x80000000U || EX->f[i]<-(float)0x80000000U)
|
||||
GX.ud[i] = 0x80000000;
|
||||
else
|
||||
GX.sd[i] = EX->f[i];
|
||||
@@ -123,7 +168,7 @@
|
||||
case 0x5D: /* MINSS Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
if(isnan(GX.f[0]) || isnan(EX->f[0]) || islessequal(EX->f[0], GX.f[0]))
|
||||
if(isnanf(GX.f[0]) || isnanf(EX->f[0]) || islessequal(EX->f[0], GX.f[0]))
|
||||
GX.f[0] = EX->f[0];
|
||||
break;
|
||||
case 0x5E: /* DIVSS Gx, Ex */
|
||||
@@ -134,7 +179,7 @@
|
||||
case 0x5F: /* MAXSS Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
if (isnan(GX.f[0]) || isnan(EX->f[0]) || isgreaterequal(EX->f[0], GX.f[0]))
|
||||
if (isnanf(GX.f[0]) || isnanf(EX->f[0]) || isgreaterequal(EX->f[0], GX.f[0]))
|
||||
GX.f[0] = EX->f[0];
|
||||
break;
|
||||
|
||||
@@ -240,5 +285,7 @@
|
||||
break;
|
||||
|
||||
default:
|
||||
goto _default;
|
||||
return 0;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
+67
-34
@@ -51,6 +51,7 @@ int32_t my___sendmmsg(x86emu_t* emu, int32_t fd, void* msgvec, uint32_t vlen, ui
|
||||
#endif
|
||||
#endif
|
||||
typedef struct x86_sigaction_s x86_sigaction_t;
|
||||
typedef struct x86_sigaction_restorer_s x86_sigaction_restorer_t;
|
||||
|
||||
|
||||
int32_t my_getrandom(x86emu_t* emu, void* buf, uint32_t buflen, uint32_t flags);
|
||||
@@ -67,6 +68,7 @@ int32_t my_epoll_ctl(x86emu_t* emu, int32_t epfd, int32_t op, int32_t fd, void*
|
||||
int32_t my_epoll_wait(x86emu_t* emu, int32_t epfd, void* events, int32_t maxevents, int32_t timeout);
|
||||
#endif
|
||||
int my_sigaction(x86emu_t* emu, int signum, const x86_sigaction_t *act, x86_sigaction_t *oldact);
|
||||
int my_syscall_sigaction(x86emu_t* emu, int signum, const x86_sigaction_restorer_t *act, x86_sigaction_restorer_t *oldact, int sigsetsize);
|
||||
int32_t my_execve(x86emu_t* emu, const char* path, char* const argv[], char* const envp[]);
|
||||
void* my_mmap(x86emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, int offset);
|
||||
void* my_mmap64(x86emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, int64_t offset);
|
||||
@@ -75,6 +77,39 @@ int my_mprotect(x86emu_t* emu, void *addr, unsigned long len, int prot);
|
||||
void* ElfSetBrk(void* newbrk);
|
||||
int my_vfork(x86emu_t* emu);
|
||||
|
||||
#ifndef __NR_socketcall
|
||||
int my_socketcall(x86emu_t* emu, int n, unsigned long *args) {
|
||||
int ret = 0;
|
||||
switch(n) {
|
||||
case SYS_SOCKET: ret = socket(args[0], args[1], args[2]); break;
|
||||
case SYS_BIND: ret = bind(args[0], (void*)args[1], args[2]); break;
|
||||
case SYS_CONNECT: ret = connect(args[0], (void*)args[1], args[2]); break;
|
||||
case SYS_LISTEN: ret = listen(args[0], args[1]); break;
|
||||
case SYS_ACCEPT: ret = accept(args[0], (void*)args[1], (void*)args[2]); break;
|
||||
case SYS_GETSOCKNAME: ret = getsockname(args[0], (void*)args[1], (void*)args[2]); break;
|
||||
case SYS_GETPEERNAME: ret = getpeername(args[0], (void*)args[1], (void*)args[2]); break;
|
||||
case SYS_SOCKETPAIR: ret = socketpair(args[0], args[1], args[2], (int*)args[3]); break;
|
||||
case SYS_SEND: ret = send(args[0], (void*)args[1], args[2], args[3]); break;
|
||||
case SYS_RECV: ret = recv(args[0], (void*)args[1], args[2], args[3]); break;
|
||||
case SYS_SENDTO: ret = sendto(args[0], (void*)args[1], args[2], args[3], (void*)args[4], args[5]); break;
|
||||
case SYS_RECVFROM: ret = recvfrom(args[0], (void*)args[1], args[2], args[3], (void*)args[4], (void*)args[5]); break;
|
||||
case SYS_SHUTDOWN: ret = shutdown(args[0], args[1]); break;
|
||||
case SYS_SETSOCKOPT: ret = setsockopt(args[0], args[1], args[2], (void*)args[3], args[4]); break;
|
||||
case SYS_GETSOCKOPT: ret = getsockopt(args[0], args[1], args[2], (void*)args[3], (void*)args[4]); break;
|
||||
case SYS_SENDMSG: ret = sendmsg(args[0], (void*)args[1], args[2]); break;
|
||||
case SYS_RECVMSG: ret = recvmsg(args[0], (void*)args[1], args[2]); break;
|
||||
case SYS_ACCEPT4: ret = my_accept4(emu, args[0], (void*)args[1], (void*)args[2], args[3]); break;
|
||||
#ifdef SYS_RECVMMSG
|
||||
case SYS_RECVMMSG: ret = my_recvmmsg(emu, args[0], (void*)args[1], args[2], args[3], (void*)args[4]); break;
|
||||
case SYS_SENDMMSG: ret = my___sendmmsg(emu, args[0], (void*)args[1], args[2], args[3]); break;
|
||||
#endif
|
||||
default:
|
||||
printf_log(LOG_DEBUG, "BOX86 Error on Syscall 102: Unknown Soket command %d\n", n);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
// cannot include <fcntl.h>, it conflict with some asm includes...
|
||||
#ifndef O_NONBLOCK
|
||||
#define O_NONBLOCK 04000
|
||||
@@ -106,6 +141,9 @@ scwrap_t syscallwrap[] = {
|
||||
{ 19, __NR_lseek, 3 },
|
||||
{ 20, __NR_getpid, 0 },
|
||||
{ 24, __NR_getuid, 0 },
|
||||
#ifdef __NR_alarm
|
||||
{ 27, __NR_alarm, 1 },
|
||||
#endif
|
||||
{ 33, __NR_access, 2 },
|
||||
{ 37, __NR_kill, 2 },
|
||||
{ 38, __NR_rename, 2 },
|
||||
@@ -123,12 +161,14 @@ scwrap_t syscallwrap[] = {
|
||||
{ 63, __NR_dup2, 2 },
|
||||
{ 64, __NR_getppid, 0 },
|
||||
{ 66, __NR_setsid, 0 },
|
||||
//{ 67, __NR_sigaction, 3 },
|
||||
{ 75, __NR_setrlimit, 2 },
|
||||
#ifdef __NR_getrlimit
|
||||
{ 76, __NR_getrlimit, 2 },
|
||||
#endif
|
||||
{ 77, __NR_getrusage, 2 },
|
||||
{ 78, __NR_gettimeofday, 2 },
|
||||
{ 80, __NR_getgroups, 2 },
|
||||
{ 83, __NR_symlink, 2 },
|
||||
#ifdef __NR_select
|
||||
{ 82, __NR_select, 5 },
|
||||
@@ -172,6 +212,7 @@ scwrap_t syscallwrap[] = {
|
||||
//{ 122, __NR_uname, 1 },
|
||||
//{ 123, __NR_modify_ldt },
|
||||
//{ 125, __NR_mprotect, 3 },
|
||||
{ 126, __NR_sigprocmask, 3 },
|
||||
{ 136, __NR_personality, 1 },
|
||||
{ 140, __NR__llseek, 5 },
|
||||
{ 141, __NR_getdents, 3 },
|
||||
@@ -447,6 +488,13 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
break;
|
||||
#endif
|
||||
#ifndef __NR_alarm
|
||||
case 27:
|
||||
R_EAX = alarm(R_EBX);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
break;
|
||||
#endif
|
||||
case 45: // sys_brk
|
||||
R_EAX = (uintptr_t)ElfSetBrk((void*)R_EBX);
|
||||
@@ -463,6 +511,11 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
break;
|
||||
case 67: // sys_sigaction
|
||||
R_EAX = (uint32_t)my_syscall_sigaction(emu, R_EBX, (x86_sigaction_restorer_t*)R_ECX, (x86_sigaction_restorer_t*)R_EDX, R_ESI);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
break;
|
||||
#ifndef __NR_getrlimit
|
||||
case 76: // sys_getrlimit... this is the old version, using the new one. Maybe some tranform is needed?
|
||||
R_EAX = getrlimit(R_EBX, (void*)R_ECX);
|
||||
@@ -491,39 +544,10 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
break;
|
||||
#ifndef __NR_socketcall
|
||||
case 102: {
|
||||
unsigned long *args = (unsigned long *)R_ECX;
|
||||
// need to do all call "by hand"
|
||||
switch(R_EBX) {
|
||||
case SYS_SOCKET: R_EAX = socket(args[0], args[1], args[2]); break;
|
||||
case SYS_BIND: R_EAX = bind(args[0], (void*)args[1], args[2]); break;
|
||||
case SYS_CONNECT: R_EAX = connect(args[0], (void*)args[1], args[2]); break;
|
||||
case SYS_LISTEN: R_EAX = listen(args[0], args[1]); break;
|
||||
case SYS_ACCEPT: R_EAX = accept(args[0], (void*)args[1], (void*)args[2]); break;
|
||||
case SYS_GETSOCKNAME: R_EAX = getsockname(args[0], (void*)args[1], (void*)args[2]); break;
|
||||
case SYS_GETPEERNAME: R_EAX = getpeername(args[0], (void*)args[1], (void*)args[2]); break;
|
||||
case SYS_SOCKETPAIR: R_EAX = socketpair(args[0], args[1], args[2], (int*)args[3]); break;
|
||||
case SYS_SEND: R_EAX = send(args[0], (void*)args[1], args[2], args[3]); break;
|
||||
case SYS_RECV: R_EAX = recv(args[0], (void*)args[1], args[2], args[3]); break;
|
||||
case SYS_SENDTO: R_EAX = sendto(args[0], (void*)args[1], args[2], args[3], (void*)args[4], args[5]); break;
|
||||
case SYS_RECVFROM: R_EAX = recvfrom(args[0], (void*)args[1], args[2], args[3], (void*)args[4], (void*)args[5]); break;
|
||||
case SYS_SHUTDOWN: R_EAX = shutdown(args[0], args[1]); break;
|
||||
case SYS_SETSOCKOPT: R_EAX = setsockopt(args[0], args[1], args[2], (void*)args[3], args[4]); break;
|
||||
case SYS_GETSOCKOPT: R_EAX = getsockopt(args[0], args[1], args[2], (void*)args[3], (void*)args[4]); break;
|
||||
case SYS_SENDMSG: R_EAX = sendmsg(args[0], (void*)args[1], args[2]); break;
|
||||
case SYS_RECVMSG: R_EAX = recvmsg(args[0], (void*)args[1], args[2]); break;
|
||||
case SYS_ACCEPT4: R_EAX = my_accept4(emu, args[0], (void*)args[1], (void*)args[2], args[3]); break;
|
||||
#ifdef SYS_RECVMMSG
|
||||
case SYS_RECVMMSG: R_EAX = my_recvmmsg(emu, args[0], (void*)args[1], args[2], args[3], (void*)args[4]); break;
|
||||
case SYS_SENDMMSG: R_EAX = my___sendmmsg(emu, args[0], (void*)args[1], args[2], args[3]); break;
|
||||
#endif
|
||||
default:
|
||||
printf_log(LOG_DEBUG, "BOX86 Error on Syscall 102: Unknown Soket command %d\n", R_EBX);
|
||||
R_EAX = -EINVAL;
|
||||
}
|
||||
case 102:
|
||||
R_EAX = my_socketcall(emu, R_EBX, (unsigned long *)R_ECX);
|
||||
if(R_EAX==0xffffffff && errno>0)
|
||||
R_EAX = (uint32_t)-errno;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifndef __NR_olduname
|
||||
@@ -748,9 +772,8 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
printf_log(LOG_INFO, "Error: Unsupported Syscall 0x%02Xh (%d)\n", s, s);
|
||||
emu->quit = 1;
|
||||
emu->error |= ERR_UNIMPL;
|
||||
printf_log(LOG_INFO, "Warning: Unsupported Syscall 0x%02Xh (%d)\n", s, s);
|
||||
R_EAX = (uint32_t)-ENOSYS;
|
||||
return;
|
||||
}
|
||||
printf_log(LOG_DEBUG, " => 0x%x\n", R_EAX);
|
||||
@@ -800,10 +823,20 @@ uint32_t EXPORT my_syscall(x86emu_t *emu)
|
||||
return (uint32_t)close(i32(4));
|
||||
case 11: // execve
|
||||
return (uint32_t)my_execve(emu, p(4), p(8), p(12));
|
||||
#ifndef __NR_alarm
|
||||
case 27:
|
||||
return alarm(R_EBX);
|
||||
#endif
|
||||
case 45: // brk
|
||||
return (uintptr_t)ElfSetBrk(p(4));
|
||||
case 67: // sys_sigaction
|
||||
return my_syscall_sigaction(emu, u32(4), (x86_sigaction_restorer_t*)p(8), (x86_sigaction_restorer_t*)p(12), u32(16));
|
||||
case 91: // munmap
|
||||
return (uint32_t)my_munmap(emu, p(4), u32(8));
|
||||
#ifndef __NR_socketcall
|
||||
case 102:
|
||||
return my_socketcall(emu, i32(4), (unsigned long *)p(8));
|
||||
#endif
|
||||
#ifndef __NR_ipc
|
||||
case 117: // ipc
|
||||
return (uint32_t)my_ipc(u32(4), i32(8), i32(12), i32(16), p(20), i32(24));
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box86context.h"
|
||||
#include "bridge.h"
|
||||
#include "signals.h"
|
||||
|
||||
void print_banner(x86emu_t* ref)
|
||||
{
|
||||
printf_log(LOG_NONE, "Warning, difference between Interpreter and Dynarec in %p (%02x %02x %02x %02x %02x %02x %02x %02x)\n"\
|
||||
"=======================================\n",
|
||||
(void*)ref->old_ip,
|
||||
((uint8_t*)ref->old_ip)[0], ((uint8_t*)ref->old_ip)[1], ((uint8_t*)ref->old_ip)[2], ((uint8_t*)ref->old_ip)[3],
|
||||
((uint8_t*)ref->old_ip)[4], ((uint8_t*)ref->old_ip)[5], ((uint8_t*)ref->old_ip)[6], ((uint8_t*)ref->old_ip)[7]
|
||||
);
|
||||
printf_log(LOG_NONE, "DIFF: Dynarec | Interpreter\n----------------------\n");
|
||||
}
|
||||
#define BANNER if(!banner) {banner=1; print_banner(ref);}
|
||||
void x86test_check(x86emu_t* ref, uintptr_t ip)
|
||||
{
|
||||
int banner = 0;
|
||||
x86test_t* test = &ref->test;
|
||||
x86emu_t* emu = test->emu;
|
||||
if(memcmp(ref->regs, emu->regs, sizeof(emu->regs))) {
|
||||
static const char* regname[] = {"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI"};
|
||||
BANNER;
|
||||
for(int i=0; i<8; ++i) {
|
||||
if(ref->regs[i].dword[0]!=emu->regs[i].dword[0]) {
|
||||
printf_log(LOG_NONE, "%s: %08x | %08x\n", regname[i], ref->regs[i].dword[0], emu->regs[i].dword[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ip!=emu->ip.dword[0]) {
|
||||
BANNER;
|
||||
printf_log(LOG_NONE, "RIP: %08x | %08x\n", ip, emu->ip.dword[0]);
|
||||
}
|
||||
// flags are volatile, so don't test them
|
||||
//memcpy(&ref->eflags, &emu->eflags, sizeof(emu->eflags));
|
||||
if(memcmp(ref->segs, emu->segs, sizeof(emu->segs))) {
|
||||
static const char* segname[] = {"CS", "DS", "ES", "SS", "FS", "GS"};
|
||||
BANNER;
|
||||
for(int i=0; i<6; ++i) {
|
||||
if(ref->segs[i]!=emu->segs[i]) {
|
||||
printf_log(LOG_NONE, "%s: %04x | %04x\n", segname[i], ref->segs[i], emu->segs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ref->top != emu->top) {
|
||||
BANNER;
|
||||
printf_log(LOG_NONE, "X87 TOP: %d | %d\n", ref->top, emu->top);
|
||||
}
|
||||
if(ref->fpu_stack != emu->fpu_stack) {
|
||||
BANNER;
|
||||
printf_log(LOG_NONE, "X87 STACK: %d | %d\n", ref->fpu_stack, emu->fpu_stack);
|
||||
}
|
||||
if(ref->fpu_stack && memcmp(ref->x87, emu->x87, sizeof(emu->x87))) {
|
||||
// need to check each regs, unused one might have different left over value
|
||||
for(int i=0; i<ref->fpu_stack; ++i) {
|
||||
if(ref->x87[(ref->top+i)&7].d != emu->x87[(emu->top+i)&7].d) {
|
||||
BANNER;
|
||||
printf_log(LOG_NONE, "ST%d: %g | %g\n", i, ref->x87[(ref->top+i)&7].d, emu->x87[(emu->top+i)&7].d);
|
||||
}
|
||||
}
|
||||
}
|
||||
//memcpy(ref->fpu_ld, emu->fpu_ld, sizeof(emu->fpu_ld));
|
||||
//memcpy(ref->fpu_ll, emu->fpu_ll, sizeof(emu->fpu_ll));
|
||||
/*if(ref->p_regs != emu->p_regs) {
|
||||
BANNER;
|
||||
printf_log(LOG_NONE, "X87 PREG: %x | %x\n", ref->p_regs, emu->p_regs);
|
||||
}*/
|
||||
if(ref->cw.x16 != emu->cw.x16) {
|
||||
BANNER;
|
||||
printf_log(LOG_NONE, "X87 CW: %x | %x\n", ref->cw.x16, emu->cw.x16);
|
||||
}
|
||||
if(ref->sw.x16 != emu->sw.x16) {
|
||||
BANNER;
|
||||
printf_log(LOG_NONE, "X87 SW: %x | %x\n", ref->sw.x16, emu->sw.x16);
|
||||
}
|
||||
if(memcmp(ref->mmx, emu->mmx, sizeof(emu->mmx))) {
|
||||
BANNER;
|
||||
for(int i=0; i<8; ++i) {
|
||||
if(ref->mmx[i].q!=emu->mmx[i].q) {
|
||||
printf_log(LOG_NONE, "EMM[%d]: %016llx | %016llx\n", i, ref->mmx[i].q, emu->mmx[i].q);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ref->mxcsr.x32 != emu->mxcsr.x32) {
|
||||
BANNER;
|
||||
printf_log(LOG_NONE, "MXCSR: %x | %x\n", ref->mxcsr.x32, emu->mxcsr.x32);
|
||||
}
|
||||
if(memcmp(ref->xmm, emu->xmm, sizeof(emu->xmm))) {
|
||||
BANNER;
|
||||
for(int i=0; i<8; ++i) {
|
||||
if(ref->xmm[i].q[0]!=emu->xmm[i].q[0] || ref->xmm[i].q[1]!=emu->xmm[i].q[1] ) {
|
||||
printf_log(LOG_NONE, "XMM[%02d]: %016llx-%016llx | %016llx-%016llx\n", i, ref->xmm[i].q[1], ref->xmm[i].q[0], emu->xmm[i].q[1], emu->xmm[i].q[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(test->memsize) {
|
||||
if(memcmp(test->mem, (void*)test->memaddr, test->memsize)) {
|
||||
BANNER;
|
||||
printf_log(LOG_NONE, "MEM: @%p :", (void*)test->memaddr);
|
||||
for(int i=0; i<test->memsize; ++i)
|
||||
printf_log(LOG_NONE, " %02x", test->mem[i]);
|
||||
printf_log(LOG_NONE, " |");
|
||||
for(int i=0; i<test->memsize; ++i)
|
||||
printf_log(LOG_NONE, " %02x", ((uint8_t*)test->memaddr)[i]);
|
||||
printf_log(LOG_NONE, "\n");
|
||||
}
|
||||
}
|
||||
if(banner) // there was an error, re-sync!
|
||||
CopyEmu(emu, ref);
|
||||
}
|
||||
#undef BANNER
|
||||
|
||||
void x86test_init(x86emu_t* ref, uintptr_t ip)
|
||||
{
|
||||
x86test_t* test = &ref->test;
|
||||
if(!test->test) {
|
||||
test->clean = 0;
|
||||
return;
|
||||
}
|
||||
// check if test as a valid emu struct
|
||||
if(!test->emu) {
|
||||
test->emu = NewX86Emu(my_context, ip, (uintptr_t)ref->init_stack, ref->size_stack, 0);
|
||||
CopyEmu(test->emu, ref);
|
||||
} else {
|
||||
// check if IP is same, else, sync
|
||||
uintptr_t prev_ip = test->emu->ip.dword[0];
|
||||
if(test->clean)
|
||||
x86test_check(ref, ip);
|
||||
if(ip != prev_ip || !test->test || !test->clean) {
|
||||
CopyEmu(test->emu, ref);
|
||||
}
|
||||
}
|
||||
// Do a Dry single Step
|
||||
test->memsize = 0;
|
||||
test->clean = 1;
|
||||
ref->old_ip = ip;
|
||||
RunTest(test);
|
||||
// this will be anakyzed next step
|
||||
}
|
||||
@@ -304,6 +304,8 @@ void fpu_fxsave(x86emu_t* emu, void* ed)
|
||||
emu->sw.f.F87_TOP = top;
|
||||
p->ControlWord = emu->cw.x16;
|
||||
p->StatusWord = emu->sw.x16;
|
||||
p->MxCsr = emu->mxcsr.x32;
|
||||
p->MxCsr_Mask = 0;
|
||||
uint8_t tags = 0;
|
||||
for (int i=0; i<8; ++i)
|
||||
tags |= (emu->p_regs[i].tag==0b11)?0:(1<<(i*2));
|
||||
@@ -313,8 +315,6 @@ void fpu_fxsave(x86emu_t* emu, void* ed)
|
||||
p->ErrorSelector = 0;
|
||||
p->DataOffset = 0;
|
||||
p->DataSelector = 0;
|
||||
p->MxCsr = 0;
|
||||
p->MxCsr_Mask = 0;
|
||||
// copy MMX regs...
|
||||
for(int i=0; i<8; ++i)
|
||||
memcpy(&p->FloatRegisters[i].q[0], (i<stack)?&ST(i):&emu->mmx[i], sizeof(mmx87_regs_t));
|
||||
@@ -327,6 +327,7 @@ void fpu_fxrstor(x86emu_t* emu, void* ed)
|
||||
xsave_t *p = (xsave_t*)ed;
|
||||
emu->cw.x16 = p->ControlWord;
|
||||
emu->sw.x16 = p->StatusWord;
|
||||
emu->mxcsr.x32 = p->MxCsr;
|
||||
emu->top = emu->sw.f.F87_TOP;
|
||||
uint8_t tags = p->TagWord;
|
||||
for(int i=0; i<8; ++i)
|
||||
|
||||
@@ -14,10 +14,6 @@ typedef struct x86emu_s x86emu_t;
|
||||
#define LN2 0.69314718055994531
|
||||
#define LG2 0.3010299956639812
|
||||
|
||||
void Run66D9(x86emu_t *emu);
|
||||
void Run66DD(x86emu_t *emu);
|
||||
void RunDF(x86emu_t *emu);
|
||||
|
||||
#define ST0 emu->x87[emu->top]
|
||||
#define ST1 emu->x87[(emu->top+1)&7]
|
||||
#define ST(a) emu->x87[(emu->top+(a))&7]
|
||||
|
||||
@@ -1,193 +0,0 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "x86run.h"
|
||||
|
||||
#define F8 *(uint8_t*)(ip++)
|
||||
#define F8S *(int8_t*)(ip++)
|
||||
#define F16 *(uint16_t*)(ip+=2, ip-2)
|
||||
#define F16S *(int16_t*)(ip+=2, ip-2)
|
||||
#define F32 *(uint32_t*)(ip+=4, ip-4)
|
||||
#define F32S *(int32_t*)(ip+=4, ip-4)
|
||||
#define PK(a) *(uint8_t*)(ip+a)
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
void Run66D9(x86emu_t *emu)
|
||||
{
|
||||
uintptr_t ip = R_EIP;
|
||||
uint8_t nextop = F8;
|
||||
reg32_t *oped;
|
||||
switch (nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
case 0xD0:
|
||||
case 0xE0:
|
||||
case 0xE5:
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xFC:
|
||||
case 0xE1:
|
||||
case 0xE4:
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
ip = R_EIP-2;
|
||||
UnimpOpcode(emu);
|
||||
break;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 4: /* FLDENV m */
|
||||
// warning, incomplete
|
||||
GET_EW;
|
||||
fpu_loadenv(emu, (char*)ED, 1);
|
||||
break;
|
||||
case 6: /* FNSTENV m */
|
||||
// warning, incomplete
|
||||
GET_EW;
|
||||
fpu_savenv(emu, (char*)ED, 1);
|
||||
break;
|
||||
default:
|
||||
ip = R_EIP-2;
|
||||
UnimpOpcode(emu);
|
||||
}
|
||||
}
|
||||
R_EIP = ip;
|
||||
}
|
||||
|
||||
void Run66DD(x86emu_t *emu)
|
||||
{
|
||||
uintptr_t ip = R_EIP;
|
||||
uint8_t nextop = F8;
|
||||
reg32_t *oped;
|
||||
switch(nextop) {
|
||||
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
case 0xD0:
|
||||
case 0xE0:
|
||||
case 0xE5:
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xFC:
|
||||
case 0xE1:
|
||||
case 0xE4:
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
ip = R_EIP-2;
|
||||
UnimpOpcode(emu);
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 4: /* FRSTOR m94byte */
|
||||
GET_EW;
|
||||
fpu_loadenv(emu, (char*)ED, 1);
|
||||
// get the STx
|
||||
{
|
||||
char* p =(char*)ED;
|
||||
p += 14;
|
||||
for (int i=0; i<8; ++i) {
|
||||
LD2D(p, &ST(i).d);
|
||||
p+=10;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 6: /* FNSAVE m94byte */
|
||||
GET_EW;
|
||||
// ENV first...
|
||||
fpu_savenv(emu, (char*)ED, 1);
|
||||
// save the STx
|
||||
{
|
||||
char* p =(char*)ED;
|
||||
p += 14;
|
||||
for (int i=0; i<8; ++i) {
|
||||
D2LD(&ST(i).d, p);
|
||||
p+=10;
|
||||
}
|
||||
}
|
||||
reset_fpu(emu);
|
||||
break;
|
||||
default:
|
||||
ip = R_EIP-2; // unfetch
|
||||
UnimpOpcode(emu);
|
||||
}
|
||||
}
|
||||
R_EIP = ip;
|
||||
}
|
||||
+30
-21
@@ -17,6 +17,7 @@ typedef struct bridge_s bridge_t;
|
||||
typedef struct dlprivate_s dlprivate_t;
|
||||
typedef struct kh_symbolmap_s kh_symbolmap_t;
|
||||
typedef struct kh_defaultversion_s kh_defaultversion_t;
|
||||
typedef struct kh_mapsymbols_s kh_mapsymbols_t;
|
||||
typedef struct library_s library_t;
|
||||
typedef struct linkmap_s linkmap_t;
|
||||
typedef struct kh_fts_s kh_fts_t;
|
||||
@@ -30,7 +31,6 @@ typedef struct atfork_fnc_s {
|
||||
} atfork_fnc_t;
|
||||
#ifdef DYNAREC
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
typedef struct mmaplist_s mmaplist_t;
|
||||
typedef struct kh_dynablocks_s kh_dynablocks_t;
|
||||
#endif
|
||||
@@ -38,9 +38,10 @@ typedef struct kh_dynablocks_s kh_dynablocks_t;
|
||||
#define DYNAMAP_SIZE (1<<(32-DYNAMAP_SHIFT))
|
||||
#define JMPTABL_SHIFT 16
|
||||
#define JMPTABL_SIZE (1<<(32-JMPTABL_SHIFT))
|
||||
#define JMPTABLE_MASK ((1<<JMPTABL_SHIFT)-1)
|
||||
|
||||
typedef void* (*procaddess_t)(const char* name);
|
||||
typedef void* (*vkprocaddess_t)(void* instance, const char* name);
|
||||
typedef void* (*procaddress_t)(const char* name);
|
||||
typedef void* (*vkprocaddress_t)(void* instance, const char* name);
|
||||
|
||||
#define MAX_SIGNAL 64
|
||||
|
||||
@@ -56,9 +57,15 @@ void free_tlsdatasize(void* p);
|
||||
typedef struct needed_libs_s {
|
||||
int cap;
|
||||
int size;
|
||||
library_t **libs;
|
||||
char** names;
|
||||
library_t** libs;
|
||||
} needed_libs_t;
|
||||
void free_neededlib(needed_libs_t* needed); // defined in library.c
|
||||
|
||||
void free_neededlib(needed_libs_t* needed);
|
||||
needed_libs_t* new_neededlib(int n);
|
||||
needed_libs_t* copy_neededlib(needed_libs_t* needed);
|
||||
void add1_neededlib(needed_libs_t* needed);
|
||||
void add1lib_neededlib(needed_libs_t* needed, library_t* lib, const char* name);
|
||||
|
||||
typedef struct base_segment_s {
|
||||
uintptr_t base;
|
||||
@@ -100,7 +107,8 @@ typedef struct box86context_s {
|
||||
int elfcap;
|
||||
int elfsize; // number of elf loaded
|
||||
|
||||
needed_libs_t neededlibs; // needed libs for main elf
|
||||
needed_libs_t *neededlibs; // needed libs for main elf
|
||||
needed_libs_t *preload;
|
||||
|
||||
uintptr_t ep; // entry point
|
||||
|
||||
@@ -109,22 +117,19 @@ typedef struct box86context_s {
|
||||
|
||||
lib_t *maplib; // lib and symbols handling
|
||||
lib_t *local_maplib; // libs and symbols openned has local (only collection of libs, no symbols)
|
||||
dic_t *versym; // dictionnary of versionned symbols
|
||||
dic_t *versym; // dictionnary of versioned symbols
|
||||
kh_mapsymbols_t *globdata; // GLOBAL_DAT relocation for COPY mapping in main elf
|
||||
|
||||
kh_threadstack_t *stacksizes; // stack sizes attributes for thread (temporary)
|
||||
bridge_t *system; // other bridges
|
||||
uintptr_t exit_bridge; // exit bridge value
|
||||
uintptr_t vsyscall; // vsyscall bridge value
|
||||
dlprivate_t *dlprivate; // dlopen library map
|
||||
kh_symbolmap_t *glwrappers; // the map of wrapper for glProcs (for GLX or SDL1/2)
|
||||
kh_symbolmap_t *glmymap; // link to the mysymbolmap of libGL
|
||||
procaddess_t glxprocaddress;
|
||||
kh_symbolmap_t *alwrappers; // the map of wrapper for alGetProcAddress
|
||||
kh_symbolmap_t *almymap; // link to the mysymbolmap if libOpenAL
|
||||
kh_symbolmap_t *vkwrappers; // the map of wrapper for VulkanProcs (TODO: check SDL2)
|
||||
kh_symbolmap_t *vkmymap; // link to the mysymbolmap of libGL
|
||||
kh_defaultversion_t *globaldefver; // the global default version for symbols (the XXX@@vvvv of symbols)
|
||||
kh_defaultversion_t *weakdefver; // the weak default version for symbols (the XXX@@vvvv of symbols)
|
||||
vkprocaddess_t vkprocaddress;
|
||||
vkprocaddress_t vkprocaddress;
|
||||
|
||||
#ifndef DYNAREC
|
||||
pthread_mutex_t mutex_once;
|
||||
@@ -142,7 +147,9 @@ typedef struct box86context_s {
|
||||
uint32_t mutex_thread;
|
||||
uint32_t mutex_bridge;
|
||||
uint32_t mutex_dyndump;
|
||||
uintptr_t max_db_size; // the biggest (in x86_64 instructions bytes) built dynablock
|
||||
int trace_dynarec;
|
||||
pthread_mutex_t mutex_lock; // this is for the Test interpreter
|
||||
#endif
|
||||
|
||||
library_t *libclib; // shortcut to libc library (if loaded, so probably yes)
|
||||
@@ -157,10 +164,10 @@ typedef struct box86context_s {
|
||||
void* sdl2allocrw; // AllocRW/FreeRW functions from SDL2
|
||||
void* sdl2freerw;
|
||||
|
||||
int deferedInit;
|
||||
elfheader_t **deferedInitList;
|
||||
int deferedInitSz;
|
||||
int deferedInitCap;
|
||||
int deferredInit;
|
||||
elfheader_t **deferredInitList;
|
||||
int deferredInitSz;
|
||||
int deferredInitCap;
|
||||
|
||||
pthread_key_t tlskey; // then tls key to have actual tlsdata
|
||||
void* tlsdata; // the initial global tlsdata
|
||||
@@ -169,9 +176,9 @@ typedef struct box86context_s {
|
||||
|
||||
uintptr_t *auxval_start;
|
||||
|
||||
cleanup_t *cleanups; // atexit functions
|
||||
int clean_sz;
|
||||
int clean_cap;
|
||||
cleanup_t *cleanups; // atexit functions
|
||||
int clean_sz;
|
||||
int clean_cap;
|
||||
#ifndef NOALIGN
|
||||
kh_fts_t *ftsmap;
|
||||
#endif
|
||||
@@ -208,7 +215,7 @@ typedef struct box86context_s {
|
||||
#else
|
||||
int GetTID();
|
||||
#define mutex_lock(A) {int tid = GetTID(); while(arm_lock_storeifnull(A, (void*)tid)) sched_yield();}
|
||||
#define mutex_trylock(A) arm_lock_storeifnull(A, (void*)GetTID())
|
||||
#define mutex_trylock(A) (uintptr_t)arm_lock_storeifnull(A, (void*)GetTID())
|
||||
#define mutex_unlock(A) arm_lock_storeifref(A, NULL, (void*)GetTID())
|
||||
#endif
|
||||
|
||||
@@ -224,6 +231,8 @@ void print_cycle_log(int loglevel);
|
||||
|
||||
// return the index of the added header
|
||||
int AddElfHeader(box86context_t* ctx, elfheader_t* head);
|
||||
// remove an elf from list (but list is never reduced, so there can be holes)
|
||||
void RemoveElfHeader(box86context_t* ctx, elfheader_t* head);
|
||||
|
||||
// return the tlsbase (negative) for the new TLS partition created (no partition index is stored in the context)
|
||||
int AddTLSPartition(box86context_t* context, int tlssize);
|
||||
|
||||
@@ -14,7 +14,7 @@ uintptr_t AddBridge(bridge_t* bridge, wrapper_t w, void* fnc, int N, const char*
|
||||
uintptr_t CheckBridged(bridge_t* bridge, void* fnc);
|
||||
int IsBridge(void* func);
|
||||
uintptr_t AddCheckBridge(bridge_t* bridge, wrapper_t w, void* fnc, int N, const char* name);
|
||||
uintptr_t AddAutomaticBridge(x86emu_t* emu, bridge_t* bridge, wrapper_t w, void* fnc, int N);
|
||||
uintptr_t AddAutomaticBridge(x86emu_t* emu, bridge_t* bridge, wrapper_t w, void* fnc, int N, const char* name);
|
||||
void* GetNativeFnc(uintptr_t fnc);
|
||||
void* GetNativeFncOrFnc(uintptr_t fnc);
|
||||
|
||||
|
||||
@@ -5,11 +5,15 @@
|
||||
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
|
||||
uint32_t RunFunction(box86context_t *context, uintptr_t fnc, int nargs, ...);
|
||||
uint32_t RunFunction(uintptr_t fnc, int nargs, ...);
|
||||
// using a fmt description
|
||||
uint32_t RunFunctionFmt(uintptr_t fnc, const char* fmt, ...);
|
||||
// use thread local emu to run the function (context is unused now)
|
||||
uint64_t RunFunction64(box86context_t *context, uintptr_t fnc, int nargs, ...);
|
||||
uint64_t RunFunction64(uintptr_t fnc, int nargs, ...);
|
||||
// using a fmt description and returning a 64bit value
|
||||
uint64_t RunFunctionFmt64(uintptr_t fnc, const char* fmt, ...);
|
||||
// use emu state to run function
|
||||
uint32_t RunFunctionWithEmu(x86emu_t *emu, int QuitOnLongJump, uintptr_t fnc, int nargs, ...);
|
||||
|
||||
uint32_t RunSafeFunction(box86context_t *context, uintptr_t fnc, int nargs, ...);
|
||||
uint32_t RunSafeFunction(uintptr_t fnc, int nargs, ...);
|
||||
#endif //__CALLBACK_H__
|
||||
Loaded 100 of 758 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user