Compare commits

..
289 changed files with 4521 additions and 21789 deletions

No files matched your search

-95
View File
@@ -1,95 +0,0 @@
### Manual build Box64 with Github Action
name: Custom build Box64
on:
workflow_dispatch:
inputs:
platform:
description: 'Target platform name'
required: true
default: 'GENERIC_ARM'
type: choice
options:
- X64
- GENERIC_ARM
- PHYTIUM
- RK3288
- RK3326
- RK3399
- RPI4ARM64
- SD845
- TEGRAX1
build_type:
description: 'Build type'
required: true
default: 'RelWithDebInfo'
type: choice
options:
- RelWithDebInfo
- Release
- Debug
- MinSizeRel
dynarec:
description: 'Enable dynarec'
required: false
default: 'true'
type: boolean
trace:
description: 'Enable trace'
required: false
default: 'false'
type: boolean
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: "Checkout Box64 Repository"
uses: actions/checkout@v2
- name: "Environment preparation"
run: |
sudo apt-get update
if [[ ${{ github.event.inputs.platform }} != 'X64' && ${{ github.event.inputs.platform }} != 'GENERIC_ARM' ]]; then
echo "BOX64_PLATFORM_MARCRO=-D${{ github.event.inputs.platform }}=1" >> $GITHUB_ENV
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
sudo apt-get -y install git gcc-aarch64-linux-gnu cmake make python3
else
if [[ ${{ github.event.inputs.platform }} == 'X64' ]]; then
echo "BOX64_PLATFORM_MARCRO=-DLD80BITS=1 -DNOALIGN=1" >> $GITHUB_ENV
echo "BOX64_COMPILER=gcc" >> $GITHUB_ENV
sudo apt-get -y install git cmake make python3
else
echo BOX64_PLATFORM_MARCRO="-DARM_DYNAREC=ON" >> $GITHUB_ENV
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
sudo apt-get -y install git gcc-aarch64-linux-gnu cmake make python3
fi
fi
- name: "Display Build info"
run: |
echo "CMake Platform Macro: ${{ env.BOX64_PLATFORM_MARCRO }}"
echo "CMake C Compiler: ${{ env.BOX64_COMPILER }}"
echo "Build type: ${{ github.event.inputs.build_type }}"
echo "Dynarec Enabled: ${{ github.event.inputs.dynarec }}"
echo "Trace Enabled: ${{ github.event.inputs.trace }}"
- name: "Build Box64"
run: |
mkdir build
cd build
cmake .. -DCMAKE_C_COMPILER=${{ env.BOX64_COMPILER }} ${{ env.BOX64_PLATFORM_MARCRO }}\
-DCMAKE_BUILD_TYPE=${{ github.event.inputs.build_type }}\
-DARM_DYNAREC:BOOL=${{ github.event.inputs.dynarec }}\
-DHAVE_TRACE:BOOL=${{ github.event.inputs.trace }}\
-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON
make -j$(nproc) VERBOSE=1
- name: "Upload Artifact"
uses: actions/upload-artifact@v2
with:
name: box64-${{ github.event.inputs.platform }}-${{ github.event.inputs.build_type }}
path: build/box64
-96
View File
@@ -1,96 +0,0 @@
### Auto build Box64 and release its binary with Github Action
name: Build and Release Box64
on:
workflow_dispatch:
release:
push:
paths:
- "**/*.c"
- "**/*.h"
- "**/*.S"
- "**/*.py"
- "CMakeLists.txt"
- "**/*.yml"
pull_request:
types: [assigned, opened, synchronize, reopened]
paths:
- "**/*.c"
- "**/*.h"
- "**/*.S"
- "**/*.py"
- "CMakeLists.txt"
- "**/*.yml"
jobs:
build:
strategy:
fail-fast: false
matrix:
platform: [X64, OTHER_ARM, RISCV, RPI4ARM64, RK3326, RK3399, RK3288, TEGRAX1, PHYTIUM, SD845]
type: [Release, Trace]
runs-on: ubuntu-latest
steps:
- name: "Checkout Box64 Repository"
uses: actions/checkout@v2
- name: "Environment preparation"
run: |
sudo apt-get update
if [[ ${{ matrix.platform }} != 'X64' && ${{ matrix.platform }} != 'OTHER_ARM' && ${{ matrix.platform }} != 'RISCV' ]]; then
echo "BOX64_PLATFORM_MARCRO=-D${{ matrix.platform }}=1" >> $GITHUB_ENV
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
sudo apt-get -y install git gcc-aarch64-linux-gnu cmake make python3
else
if [[ ${{ matrix.platform }} == 'X64' ]]; then
echo "BOX64_PLATFORM_MARCRO=-DLD80BITS=1 -DNOALIGN=1" >> $GITHUB_ENV
echo "BOX64_COMPILER=gcc" >> $GITHUB_ENV
sudo apt-get -y install git cmake make python3
elif [[ ${{ matrix.platform }} == 'RISCV' ]]; then
echo BOX64_PLATFORM_MARCRO="-DRV64=ON" >> $GITHUB_ENV
echo "BOX64_COMPILER=riscv64-linux-gnu-gcc" >> $GITHUB_ENV
sudo apt-get -y install git gcc-riscv64-linux-gnu cmake make python3
else
echo BOX64_PLATFORM_MARCRO="-DARM_DYNAREC=ON" >> $GITHUB_ENV
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
sudo apt-get -y install git gcc-aarch64-linux-gnu cmake make python3
fi
fi
if [[ ${{ matrix.type }} == 'Release' ]]; then
echo BOX64_BUILD_TYPE=Release >> $GITHUB_ENV
echo BOX64_HAVE_TRACE=0 >> $GITHUB_ENV
else
echo BOX64_BUILD_TYPE=RelWithDebInfo >> $GITHUB_ENV
echo BOX64_HAVE_TRACE=1 >> $GITHUB_ENV
fi
- name: "Display Build info"
run: |
echo "CMake Platform Macro: ${{ env.BOX64_PLATFORM_MARCRO }}"
echo "CMake C Compiler: ${{ env.BOX64_COMPILER }}"
echo "Build type: ${{ env.BOX64_BUILD_TYPE }}"
echo "Trace Enabled: ${{ env.BOX64_HAVE_TRACE }}"
- name: "Build Box64"
run: |
mkdir build
cd build
cmake .. -DCMAKE_C_COMPILER=${{ env.BOX64_COMPILER }}\
${{ env.BOX64_PLATFORM_MARCRO }}\
-DCMAKE_BUILD_TYPE=${{ env.BOX64_BUILD_TYPE }}\
-DHAVE_TRACE=${{ env.BOX64_HAVE_TRACE }}\
-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON
make -j$(nproc) VERBOSE=1
- name: "Test Box64"
if: ${{ matrix.platform == 'X64' }}
run: |
cd build
ctest -j$(nproc)
- name: "Upload Artifact"
uses: actions/upload-artifact@v2
with:
name: box64-${{ matrix.platform }}-${{ matrix.type }}
path: build/box64
+97 -186
View File
@@ -8,51 +8,27 @@ SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
option(RPI4ARM64 "Set to ON if targeting an RaspberryPI4 device with multiarch arm64 and armhf" ${RPI4ARM64})
option(RK3326 "Set to ON if targeting an Rockchip RK3326 based device" ${RK3326})
option(RK3399 "Set to ON if targeting an Rockchip RK3399 based device" ${RK3399})
option(ODROIDN2 "Set to ON if targeting an Odroid-N2 device" ${ODROIDN2})
option(TEGRAX1 "Set to ON if targeting an Tegra X1 based device" ${TEGRAX1})
option(PHYTIUM "Set to ON if targeting an Phytium (D2000 or FT2000/4) based device" ${PHYTIUM})
option(SD845 "Set to ON if targeting a Snapragon 845 based device" ${SD845})
option(M1 "Set to ON if targeting a AppleM1 running on Asahi computer" ${M1})
option(LARCH64 "Set to ON if targeting an Loongarch64 based device" ${LARCH64})
option(RV64 "Set to ON if targeting an RISCV RV64G based device" ${RV64})
option(PPC64LE "Set to ON if targeting an PowerPC 64 LE based device" ${PPC64LE})
option(LX2160A "Set to ON if targeting an LX2160A based device" ${LX2160A})
option(USE_CCACHE "Set to ON to use ccache if present in the system" ${USE_CCACHE})
option(HAVE_TRACE "Set to ON to have Trace ability (needs ZydisInfo library)" ${HAVE_TRACE})
option(NOLOADADDR "Set to ON to avoid fixing the load address of Box64" OFF)
option(NOGIT "Set to ON if not building from a git clone repo (like when building from a zip download from github)" ${NOGIT})
if(LARCH64)
set(LD80BITS OFF CACHE BOOL "")
set(NOALIGN OFF CACHE BOOL "")
set(ARM_DYNAREC OFF CACHE BOOL "")
endif()
if(RV64)
set(LD80BITS OFF CACHE BOOL "")
set(NOALIGN OFF CACHE BOOL "")
set(ARM_DYNAREC OFF CACHE BOOL "")
set(PAGE16K OFF CACHE BOOL "")
endif()
if(PPC64LE)
set(LD80BITS OFF CACHE BOOL "")
set(NOALIGN OFF CACHE BOOL "")
set(ARM_DYNAREC OFF CACHE BOOL "")
set(PAGE16K OFF CACHE BOOL "")
endif()
if(RK3399 OR ODROIDN2 OR RPI4ARM64 OR RK3326 OR TEGRAX1 OR PHYTIUM OR SD845 OR LX2160A OR M1)
if(RK3399 OR RPI4ARM64 OR RK3326 OR TEGRAX1 OR PHYTIUM OR SD845)
set(LD80BITS OFF CACHE BOOL "")
set(NOALIGN OFF CACHE BOOL "")
set(ARM_DYNAREC ON CACHE BOOL "")
endif()
if(RK3399 OR ODROIDN2 OR RPI4ARM64 OR RK3326 OR TEGRAX1 OR PHYTIUM OR SD845 OR LX2160A)
set(PAGE16K OFF CACHE BOOL "")
endif()
if(M1 OR LARCH64)
set(PAGE16K ON CACHE BOOL "")
endif()
option(LD80BITS "Set to ON if host device have 80bits long double (i.e. i386)" ${LD80BITS})
option(NOALIGN "Set to ON if host device doesn't need re-align (i.e. i386)" ${NOALIGN})
option(ARM_DYNAREC "Set to ON to use ARM Dynamic Recompilation" ${ARM_DYNAREC})
option(PAGE16K "Set to ON if host device have PageSize of 16K (instead of 4K)" ${PAGE16K})
if(${CMAKE_VERSION} VERSION_LESS "3.12.2")
find_package(PythonInterp 3)
@@ -94,10 +70,6 @@ elseif(RK3399)
add_definitions(-DRK3399)
add_definitions(-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a72+crypto)
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a72+crypto")
elseif(ODROIDN2)
add_definitions(-DODROIDN2)
add_definitions(-march=armv8-a+crc+simd+crypto -mcpu=cortex-a73.cortex-a53+crypto)
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a73.cortex-a53+crypto")
elseif(TEGRAX1)
add_definitions(-DTEGRAX1)
add_definitions(-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a57+crypto)
@@ -110,32 +82,14 @@ elseif(SD845)
add_definitions(-DSD845)
add_definitions(-pipe -march=armv8.2-a+simd+crypto -mtune=cortex-a75.cortex-a55)
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.2-a+simd+crypto -mtune=cortex-a75.cortex-a55")
elseif(M1)
add_definitions(-DM1)
add_definitions(-pipe -march=armv8.5-a+simd+crypto)
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.5-a+simd+crypto")
elseif(LARCH64)
add_definitions(-DLA464)
add_definitions(-DLARCH64)
add_definitions(-pipe -march=loongarch64)
set(CMAKE_ASM_FLAGS "-pipe -march=loongarch64")
elseif(RV64)
add_definitions(-DRV64)
add_definitions(-pipe -march=rv64g)
set(CMAKE_ASM_FLAGS "-pipe -march=rv64g")
elseif(PPC64LE)
add_definitions(-DPPC64LE)
elseif(LX2160A)
add_definitions(-DLX2160A)
add_definitions(-pipe -march=armv8-a+crypto+crc -mcpu=cortex-a72+crypto)
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crypto+crc -mcpu=cortex-a72+crypto")
elseif(ARM_DYNAREC)
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto")
endif()
if(PAGE16K)
add_definitions(-DPAGE16K)
endif()
if(NOGIT)
add_definitions(-DNOGIT)
endif()
@@ -165,10 +119,6 @@ if(ARM_DYNAREC)
add_definitions(-DDYNAREC)
add_definitions(-DARM64)
enable_language(ASM)
include_directories("${BOX64_ROOT}/src/dynarec/arm64")
set(DYNAREC ON)
else()
set(DYNAREC OFF)
endif()
set(BOX64_ROOT ${CMAKE_SOURCE_DIR})
@@ -202,9 +152,8 @@ set(ELFLOADER_SRC
"${BOX64_ROOT}/src/box64context.c"
"${BOX64_ROOT}/src/build_info.c"
"${BOX64_ROOT}/src/custommem.c"
"${BOX64_ROOT}/src/steam.c"
"${BOX64_ROOT}/src/mailbox.c"
"${BOX64_ROOT}/src/dynarec/dynarec.c"
"${BOX64_ROOT}/src/elfs/elfdwarf_private.c"
"${BOX64_ROOT}/src/elfs/elfloader.c"
"${BOX64_ROOT}/src/elfs/elfparser.c"
"${BOX64_ROOT}/src/elfs/elfload_dump.c"
@@ -246,7 +195,6 @@ set(ELFLOADER_SRC
"${BOX64_ROOT}/src/librarian/globalsymbols.c"
"${BOX64_ROOT}/src/librarian/symbols.c"
"${BOX64_ROOT}/src/libtools/auxval.c"
"${BOX64_ROOT}/src/libtools/obstack.c"
"${BOX64_ROOT}/src/libtools/myalign.c"
"${BOX64_ROOT}/src/libtools/sdl1rwops.c"
"${BOX64_ROOT}/src/libtools/sdl2rwops.c"
@@ -277,28 +225,19 @@ set(WRAPPEDS
"${BOX64_ROOT}/src/wrapped/wrappeddbus.c"
"${BOX64_ROOT}/src/wrapped/wrappeddbusglib1.c"
"${BOX64_ROOT}/src/wrapped/wrappedexpat.c"
"${BOX64_ROOT}/src/wrapped/wrappedfaudio.c"
"${BOX64_ROOT}/src/wrapped/wrappedflac.c"
"${BOX64_ROOT}/src/wrapped/wrappedfontconfig.c"
"${BOX64_ROOT}/src/wrapped/wrappedfreetype.c"
"${BOX64_ROOT}/src/wrapped/wrappedgbm.c"
"${BOX64_ROOT}/src/wrapped/wrappedgconf2.c"
"${BOX64_ROOT}/src/wrapped/wrappedgdkpixbuf2.c"
"${BOX64_ROOT}/src/wrapped/wrappedgdkx112.c"
"${BOX64_ROOT}/src/wrapped/wrappedgio2.c"
"${BOX64_ROOT}/src/wrapped/wrappedglib2.c"
"${BOX64_ROOT}/src/wrapped/wrappedgmodule2.c"
"${BOX64_ROOT}/src/wrapped/wrappedgmp.c"
"${BOX64_ROOT}/src/wrapped/wrappedgnutls.c"
"${BOX64_ROOT}/src/wrapped/wrappedgobject2.c"
"${BOX64_ROOT}/src/wrapped/wrappedgssapi.c"
"${BOX64_ROOT}/src/wrapped/wrappedgssapikrb5.c"
"${BOX64_ROOT}/src/wrapped/wrappedgstapp.c"
"${BOX64_ROOT}/src/wrapped/wrappedgstaudio.c"
"${BOX64_ROOT}/src/wrapped/wrappedgstbase.c"
"${BOX64_ROOT}/src/wrapped/wrappedgstreamer.c"
"${BOX64_ROOT}/src/wrapped/wrappedgsttag.c"
"${BOX64_ROOT}/src/wrapped/wrappedgstvideo.c"
"${BOX64_ROOT}/src/wrapped/wrappedgthread2.c"
"${BOX64_ROOT}/src/wrapped/wrappedgtkx112.c"
"${BOX64_ROOT}/src/wrapped/wrappedkrb5.c"
@@ -308,7 +247,6 @@ set(WRAPPEDS
"${BOX64_ROOT}/src/wrapped/wrappedlibcrypt.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibcups.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibdl.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibdrm.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibform.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibformw.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibfuse.c"
@@ -322,7 +260,6 @@ set(WRAPPEDS
"${BOX64_ROOT}/src/wrapped/wrappedlibncursesw6.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibogg.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibpanel.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibpci.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibpcre.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibpthread.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibresolv.c"
@@ -332,15 +269,12 @@ set(WRAPPEDS
"${BOX64_ROOT}/src/wrapped/wrappedlibssl.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibtinfo.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibtinfo6.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibusb1.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibuuid.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibvorbis.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibx11.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibx11xcb.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibxau.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibxcb.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbdri2.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbdri3.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbglx.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbkeysyms.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbimage.c"
@@ -407,10 +341,6 @@ set(WRAPPEDS
"${BOX64_ROOT}/src/wrapped/wrappedxkbcommon.c"
"${BOX64_ROOT}/src/wrapped/wrappedxkbcommonx11.c"
"${BOX64_ROOT}/src/wrapped/wrappedxml2.c"
"${BOX64_ROOT}/src/wrapped/wrappedxslt.c"
"${BOX64_ROOT}/src/wrapped/wrappedldapr.c"
"${BOX64_ROOT}/src/wrapped/wrappedlber.c"
"${BOX64_ROOT}/src/wrapped/wrappedvulkan.c"
)
#set(WRAPPEDS_HEAD "${BOX64_ROOT}/src/wrapped/wrappedd3dadapter9_gen.h")
@@ -444,87 +374,77 @@ add_custom_command(
add_custom_target(WRAPPERS DEPENDS "${BOX64_ROOT}/src/wrapped/generated/functions_list.txt")
#add_custom_target(PRINTER DEPENDS "${BOX64_ROOT}/src/dynarec/last_run.txt")
if(DYNAREC)
set(DYNAREC_SRC
"${BOX64_ROOT}/src/dynarec/dynablock.c"
"${BOX64_ROOT}/src/dynarec/dynarec_native.c"
)
endif()
if(ARM_DYNAREC)
set(DYNAREC_SRC
${DYNAREC_SRC}
"${BOX64_ROOT}/src/dynarec/dynablock.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_functions.c"
"${BOX64_ROOT}/src/dynarec/arm64/arm64_printer.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_functions.c"
"${BOX64_ROOT}/src/dynarec/arm64_printer.c"
"${BOX64_ROOT}/src/dynarec/arm64/arm64_prolog.S"
"${BOX64_ROOT}/src/dynarec/arm64/arm64_epilog.S"
"${BOX64_ROOT}/src/dynarec/arm64/arm64_next.S"
"${BOX64_ROOT}/src/dynarec/arm64/arm64_lock.S"
"${BOX64_ROOT}/src/dynarec/arm64_prolog.S"
"${BOX64_ROOT}/src/dynarec/arm64_epilog.S"
"${BOX64_ROOT}/src/dynarec/arm64_next.S"
"${BOX64_ROOT}/src/dynarec/arm64_lock.S"
)
set(DYNAREC_PASS
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_helper.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_emit_tests.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_emit_math.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_emit_logic.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_emit_shift.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_00.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_0f.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_64.c"
#"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_65.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_66.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_67.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_d8.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_d9.c"
#"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_da.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_db.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_dc.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_dd.c"
#"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_de.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_df.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_f0.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_660f.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_6664.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_f20f.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_f30f.c"
)
endif()
if(DYNAREC)
set(DYNAREC_PASS
"${BOX64_ROOT}/src/wrapped/generated/wrapper.h"
${DYNAREC_PASS}
"${BOX64_ROOT}/src/dynarec/dynarec_native_pass.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_helper.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_emit_tests.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_emit_math.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_emit_logic.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_emit_shift.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_pass.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_00.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_0f.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_64.c"
#"${BOX64_ROOT}/src/dynarec/dynarec_arm64_65.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_66.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_67.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_d8.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_d9.c"
#"${BOX64_ROOT}/src/dynarec/dynarec_arm64_da.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_db.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_dc.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_dd.c"
#"${BOX64_ROOT}/src/dynarec/dynarec_arm64_de.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_df.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_f0.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_660f.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_6664.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_f20f.c"
"${BOX64_ROOT}/src/dynarec/dynarec_arm64_f30f.c"
)
add_library(dynarec_native OBJECT ${DYNAREC_SRC})
set(DYNAREC_PASS "${BOX64_ROOT}/src/wrapped/generated/wrapper.h" ${DYNAREC_PASS})
add_library(native_pass0 OBJECT ${DYNAREC_PASS})
set_target_properties(native_pass0 PROPERTIES COMPILE_FLAGS "-DSTEP=0")
add_library(native_pass1 OBJECT ${DYNAREC_PASS})
set_target_properties(native_pass1 PROPERTIES COMPILE_FLAGS "-DSTEP=1")
add_library(native_pass2 OBJECT ${DYNAREC_PASS})
set_target_properties(native_pass2 PROPERTIES COMPILE_FLAGS "-DSTEP=2")
add_library(native_pass3 OBJECT ${DYNAREC_PASS})
set_target_properties(native_pass3 PROPERTIES COMPILE_FLAGS "-DSTEP=3")
add_dependencies(native_pass0 WRAPPERS)
add_dependencies(native_pass1 WRAPPERS)
add_dependencies(native_pass2 WRAPPERS)
add_dependencies(native_pass3 WRAPPERS)
add_library(dynarec_arm OBJECT ${DYNAREC_SRC})
add_library(arm64_pass0 OBJECT ${DYNAREC_PASS})
set_target_properties(arm64_pass0 PROPERTIES COMPILE_FLAGS "-DSTEP=0")
add_library(arm64_pass1 OBJECT ${DYNAREC_PASS})
set_target_properties(arm64_pass1 PROPERTIES COMPILE_FLAGS "-DSTEP=1")
add_library(arm64_pass2 OBJECT ${DYNAREC_PASS})
set_target_properties(arm64_pass2 PROPERTIES COMPILE_FLAGS "-DSTEP=2")
add_library(arm64_pass3 OBJECT ${DYNAREC_PASS})
set_target_properties(arm64_pass3 PROPERTIES COMPILE_FLAGS "-DSTEP=3")
add_dependencies(arm64_pass0 WRAPPERS)
add_dependencies(arm64_pass1 WRAPPERS)
add_dependencies(arm64_pass2 WRAPPERS)
add_dependencies(arm64_pass3 WRAPPERS)
add_library(dynarec STATIC
$<TARGET_OBJECTS:dynarec_native>
$<TARGET_OBJECTS:native_pass0>
$<TARGET_OBJECTS:native_pass1>
$<TARGET_OBJECTS:native_pass2>
$<TARGET_OBJECTS:native_pass3>
$<TARGET_OBJECTS:dynarec_arm>
$<TARGET_OBJECTS:arm64_pass0>
$<TARGET_OBJECTS:arm64_pass1>
$<TARGET_OBJECTS:arm64_pass2>
$<TARGET_OBJECTS:arm64_pass3>
)
endif()
# creates git_head.h
if(DYNAREC)
if(ARM_DYNAREC)
add_custom_command(
OUTPUT "${BOX64_ROOT}/src/git_head.h"
COMMAND bash -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX64_ROOT}/src/git_head.h\""
@@ -542,9 +462,8 @@ add_executable(${BOX64} ${ELFLOADER_SRC} ${WRAPPEDS} "${BOX64_ROOT}/src/git_head
set_target_properties(${BOX64} PROPERTIES ENABLE_EXPORTS ON)
add_dependencies(${BOX64} WRAPPERS)
#add_dependencies(${BOX64} PRINTER)
#target_link_libraries(${BOX64} c m dl rt pthread resolv)
set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-Wl,--no-as-needed -lc -lm -ldl -lrt -lpthread -lresolv -Wl,--as-needed -pthread")
if(DYNAREC)
target_link_libraries(${BOX64} c m dl rt pthread)
if(ARM_DYNAREC)
target_link_libraries(${BOX64} dynarec)
endif()
@@ -582,7 +501,6 @@ if(NOT _x86 AND NOT _x86_64)
install(FILES ${CMAKE_BINARY_DIR}/system/box64.conf DESTINATION /etc/binfmt.d/)
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.6 DESTINATION /usr/lib/x86_64-linux-gnu/)
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libgcc_s.so.1 DESTINATION /usr/lib/x86_64-linux-gnu/)
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libpng12.so.0 DESTINATION /usr/lib/x86_64-linux-gnu/)
endif()
if(NOT TARGET uninstall)
@@ -625,108 +543,101 @@ endif()
set(CPACK_DEBIAN_FILE_NAME "${BOX64}-${BOX64_MAJOR}.${BOX64_MINOR}.${BOX64_REVISION}_Linux-${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
INCLUDE(CPack)
add_test(test01 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01 -D TEST_OUTPUT=tmpfile01.txt
add_test(test01 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref01.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test02 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test02 -D TEST_OUTPUT=tmpfile02.txt
add_test(test02 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test02 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref02.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test03 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test03 -D TEST_OUTPUT=tmpfile03.txt
add_test(test03 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test03 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref03.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test04 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test04 -D TEST_ARGS2=yeah -D TEST_OUTPUT=tmpfile04.txt
add_test(test04 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test04 -D TEST_ARGS2=yeah -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref04.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test05 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test05 -D TEST_ARGS2=7 -D TEST_OUTPUT=tmpfile05.txt
add_test(test05 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test05 -D TEST_ARGS2=7 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref05.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test06 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test06 -D TEST_OUTPUT=tmpfile06.txt
add_test(test06 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test06 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref06.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test07 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test07 -D TEST_OUTPUT=tmpfile07.txt
add_test(test07 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test07 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref07.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test08 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test08 -D TEST_OUTPUT=tmpfile08.txt
add_test(test08 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test08 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref08.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test09 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test09 -D TEST_OUTPUT=tmpfile09.txt
add_test(test09 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test09 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref09.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test10 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test10 -D TEST_OUTPUT=tmpfile10.txt
add_test(test10 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test10 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref10.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test11 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test11 -D TEST_OUTPUT=tmpfile11.txt
add_test(test11 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test11 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref11.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test12 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test12 -D TEST_OUTPUT=tmpfile12.txt
add_test(test12 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test12 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref12.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test13 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test13 -D TEST_OUTPUT=tmpfile13.txt
add_test(test13 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test13 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref13.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
#add_test(test14 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test14 -D TEST_OUTPUT=tmpfile14.txt
#add_test(test14 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test14 -D TEST_OUTPUT=tmpfile.txt
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref14.txt
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test15 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test15 -D TEST_OUTPUT=tmpfile15.txt
add_test(test15 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test15 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref15.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test16 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test16 -D TEST_OUTPUT=tmpfile16.txt
add_test(test16 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test16 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref16.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(sse ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test17 -D TEST_OUTPUT=tmpfile17.txt
add_test(test17 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test17 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref17.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
set_tests_properties(sse PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0")
add_test(aes ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test18 -D TEST_OUTPUT=tmpfile18.txt
add_test(aes ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test18 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref18.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(backtrace ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test19 -D TEST_OUTPUT=tmpfile19.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref19.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
foreach(file ${extension_tests})
get_filename_component(testname "${file}" NAME_WE)
add_test(NAME "${testname}" COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/extensions/${testname} -D TEST_OUTPUT=tmpfile-${testname}.txt
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/extensions/${testname} -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/extensions/${testname}.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake)
endforeach()
-29
View File
@@ -1,29 +0,0 @@
box64 (0.1.8) unstable; urgency=low
* Added an option to get generated -NAN on SSE2 operation
* Many small fixes and improvement to get SteamPlay (i.e. proton) working (along with box86)
* Added some workaround for program calling uname to mimic x86_64 system
* Added some granularity to mmap, and generic memory protection tracking improvment, to mimic x86 system (for wine stagging and proton)
* Better clone syscall and libc implementation
* Improved wrapping of GTK libs
* More wrapped libs (more gtk libs, like gstreamer-1.0 among other non-gtk libs too)
* More wrapped functions(with some tricky one, like dladdr1)
* Some fixes and improvment to some wrapped functions
* Refactor Dynarec:
* - better handling of SSE/x87 registers
* - optimisation to limit float/double conversion
* - better handling of "internal" jump inside a dynablock
* - make adding new architecture easier, by sharing as much infrastructure as possible
* Improved elfloader
* Improved some tests
* Improved a bit the "Hotpage" handling and messages
* Added more dynarec opcodes
* A few fixes in some Dynarec opcodes
* A bit more optimisation in some Dynarec opcodes
* Don't quit on unsupported syscall, return -1 / ENOSYS error
* Added some more Syscall
* Wrapped Vulkan library. Vulkan and dxvk now supported!
* Support building on PPC64LE (interpretor only)
* Added support for Risc-V (interpretor only)
-- Sebastien Chevalier <[email protected]> Tue, 18 Jan 2022 11:20:33 -0500
-1
View File
@@ -1 +0,0 @@
11
-14
View File
@@ -1,14 +0,0 @@
Source: box64
Section: utils
Priority: optional
Maintainer: Ryan Fortner <[email protected]>
Build-Depends: cmake, debhelper (>=11~), python3
Standards-Version: 4.1.4
Homepage: https://github.com/ptitSeb/box64
Package: box64
Architecture: any
Multi-Arch: foreign
Depends: ${misc:Depends}, ${shlibs:Depends}
Description: Linux Userspace x86_64 Emulator with a twist, targeted at ARM Linux devices
Box86 lets you run x86_64 Linux programs (such as games) on non-x86 Linux systems, like ARM (host system needs to be 64bit little-endian).
-26
View File
@@ -1,26 +0,0 @@
Format-Specification: http://dep.debian.net/deps/dep5/
Files: *
Copyright: © 2022 Sebastien Chevalier
License: MIT
License: MIT
Copyright (c) 2018-2021 Sebastien Chevalier ("ptitSeb")
.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-1
View File
@@ -1 +0,0 @@
box64: no-manual-page
-12
View File
@@ -1,12 +0,0 @@
#!/usr/bin/make -f
%:
dh $@
override_dh_auto_configure:
dh_auto_configure -- \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DARM_DYNAREC=1
override_dh_shlibdeps:
dh_shlibdeps --exclude=libgcc_s.so.1 --exclude=libpng12.so.0 --exclude=libstdc++.so.6
-1
View File
@@ -1 +0,0 @@
3.0 (quilt)
-5
View File
@@ -1,5 +0,0 @@
Bug-Database: https://github.com/ptitSeb/box64/issues
Bug-Submit: https://github.com/ptitSeb/box64/issues/new
Repository: https://github.com/ptitSeb/box64.git
Repository-Browse: https://github.com/ptitSeb/box64
Security-Contact: [email protected]
-1
View File
@@ -1 +0,0 @@
version=3
+1 -32
View File
@@ -1,36 +1,5 @@
v0.1.8
Current Version
======
* Added an option to get generated -NAN on SSE2 operation
* Many small fixes and improvement to get SteamPlay (i.e. proton) working (along with box86)
* Added some workaround for program calling uname to mimic x86_64 system
* Added some granularity to mmap, and generic memory protection tracking improvment, to mimic x86 system (for wine stagging and proton)
* Better clone syscall and libc implementation
* Improved wrapping of GTK libs
* More wrapped libs (more gtk libs, like gstreamer-1.0 among other non-gtk libs too)
* More wrapped functions(with some tricky one, like dladdr1)
* Some fixes and improvment to some wrapped functions
* Refactor Dynarec:
* better handling of SSE/x87 registers
* optimisation to limit float/double conversion
* better handling of "internal" jump inside a dynablock
* make adding new architecture easier, by sharing as much infrastructure as possible
* Improved elfloader
* Improved some tests
* Improved a bit the "Hotpage" handling and messages
* Added more dynarec opcodes
* A few fixes in some Dynarec opcodes
* A bit more optimisation in some Dynarec opcodes
* Don't quit on unsupported syscall, return -1 / ENOSYS error
* Added some more Syscall
* Wrapped Vulkan library. Vulkan and dxvk now supported!
* Support building on PPC64LE (interpretor only)
* Added support for Risc-V (interpretor only)
v0.1.6
======
* Introduce "HotPage", to temporarily disable Dynarec on a page were writing is also occuring (can help speed up C# code)
* Some work on Dynarec to limit the number of mutex use, and also allow smaller block to be built (for JIT'd programs)
* Introduce BOX64_DYNAREC_STRONGMEM for the (Arm) dynarec to emulate StrngMemory Model (needed by some games, like RimWorld)
* More functions wrapped
* Improve speed of the custom allocator used by dynarec and Hash (speedup loading)
* Added a workaround for streamwebhelper to not load it
+20 -94
View File
@@ -2,7 +2,7 @@ Compiling
----
#### for RK3399
Using a 64bit OS:
Using a 64bits OS:
```
git clone https://github.com/ptitSeb/box64
cd box64
@@ -17,7 +17,7 @@ sudo systemctl restart systemd-binfmt
#### for PI4
Warning, you need a 64bit OS:
Warning, you need a 64bits OS:
```
git clone https://github.com/ptitSeb/box64
@@ -33,7 +33,7 @@ sudo systemctl restart systemd-binfmt
#### for TEGRA X1
Using a 64bit OS:
Using a 64bits OS:
```
git clone https://github.com/ptitSeb/box64
@@ -49,7 +49,7 @@ sudo systemctl restart systemd-binfmt
#### for Snapdragon 845
Using a 64bit OS:
Using a 64bits OS:
```
git clone https://github.com/ptitSeb/box64
@@ -67,7 +67,7 @@ sudo systemctl restart systemd-binfmt
----
#### for Phytium
Using a 64bit OS:
Using a 64bits OS:
```
git clone https://github.com/ptitSeb/box64
cd box64
@@ -80,30 +80,9 @@ If it's the first install, you also need:
sudo systemctl restart systemd-binfmt
```
#### for M1
Only test on Asahi for now, using the default "16K page" kernel
```
git clone https://github.com/ptitSeb/box64
cd box64
mkdir build; cd build; cmake .. -DM1=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
make -j4
sudo make install
```
If it's the first install, you also need:
```
sudo systemctl restart systemd-binfmt
```
#### for Other ARM64 Linux platforms
`mkdir build; cd build; cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j$(nproc)`
#### for LoongArch
Using a 64bit OS:
Using a 64bits OS:
```
git clone https://github.com/ptitSeb/box64
@@ -117,59 +96,15 @@ If it's the first install, you also need:
sudo systemctl restart systemd-binfmt
```
#### for RISCV
#### for Other ARM64 Linux platforms
Using a 64bit OS:
```
git clone https://github.com/ptitSeb/box64
cd box64
mkdir build; cd build; cmake .. -DRV64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
make -j4
sudo make install
```
If it's the first install, you also need:
```
sudo systemctl restart systemd-binfmt
```
#### for PowerPC 64 LE
Using a 64bit OS:
```
git clone https://github.com/ptitSeb/box64
cd box64
mkdir build; cd build; cmake .. -DPPC64LE=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
make -j4
sudo make install
```
If it's the first install, you also need:
```
sudo systemctl restart systemd-binfmt
```
#### for LX2160A
Using a 64bit OS:
```
git clone https://github.com/ptitSeb/box64
cd box64
mkdir build; cd build; cmake .. -DLX2160A=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
make -j$(nproc)
sudo make install
```
If it's the first install, you also need:
```
sudo systemctl restart systemd-binfmt
```
`mkdir build; cd build; cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j$(nproc)`
#### for x86_64 Linux
`mkdir build; cd build; cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j$(nproc)`
If you encounter some linking errors, try using `NOLOADADDR=ON` (`cmake -DNOLOADADDR=ON; make -j$(nproc)`).
If you encounter some linking errors, try activating `NOLOADADDR` (`cmake -DNOLOADADDR=ON; make -j$(nproc)`).
### use ccmake
@@ -177,39 +112,30 @@ Alternatively, you can **use the curses-bases ccmake (or any other gui frontend
### Customize your build
#### Use ccache if you have it
*Use ccache if you have it*
Add `-DUSE_CCACHE=1` if you have ccache (it's better if you plan to touch the sources)
#### To have some debug info
*To have some debug info*
The `-DCMAKE_BUILD_TYPE=RelWithDebInfo` argument makes a build that is both optimized for speed, and has debug information embedded. That way, if you have a crash or try to analyse performance, you'll have some symbols.
#### To have a Trace Enabled build
*To have a Trace Enabled build*
To have a trace enabled build (***the interpreter will be slightly slower***), add `-DHAVE_TRACE=1`. But you will need to have the [Zydis library](https://github.com/zyantific/zydis) in your `LD_LIBRARY_PATH` or in the system library folders at runtime.
To have a trace enabled build ( ***the interpretor will be slightly slower***), add `-DHAVE_TRACE=1` but you will need, at runtime, to have the [Zydis library](https://github.com/zyantific/zydis) library in your `LD_LIBRARY_PATH` or in the system library folders.
#### To have ARM Dynarec
*To have ARM Dynarec*
Dynarec is only available on ARM (for the meantime), Activate it by using `-DARM_DYNAREC=1`.
###### *Note: VFPv3 and NEON are required for Dynarec.*
The Dynarec is only available on the ARM architecture(Right now, anyways.). Notes also that VFPv3 and NEON are required for the Dynarec. Activate it by using `-DARM_DYNAREC=1`.
#### Not building from a git clone
*Not building from a git clone*
If you are not building from a git clone (for example, downloading a release source code zip from github), you need to use `-DNOGIT=1` from cmake to be able to build (box64 uses git SHA1 to show last commit in version number).
If you are not building from a git clone (for example, downloading a release source zipped from github), you need to activate `-DNOGIT=1` from cmake to be able to build (normal process include git sha1 of HEAD in the version that box64 print).
----
Testing
----
A few tests are included with box64.
They can be launched using the `ctest` command.
The tests are very basic and only tests some functionality for now.
----
Debian Packaging
----
Box64 can also be packaged into a .deb file with `DEB_BUILD_OPTIONS=nostrip dpkg-buildpackage -us -uc -nc`.
A few tests are included.
They can be launched with `ctest`
They are very basic and don't test much for now.
+27 -27
View File
@@ -1,20 +1,20 @@
![Official logo](img/Box64Logo.png "Official Logo")
# box64
![Official logo](img/Box64Logo.png "Official Logo")
Linux Userspace x86_64 Emulator with a twist
[View changelog](https://github.com/ptitSeb/box64/blob/main/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box64/blob/main/docs/README_CN.md) | [Report an error](https://github.com/ptitSeb/box64/issues/new)
![build](https://app.travis-ci.com/ptitSeb/box64.svg?branch=main) ![stars](https://img.shields.io/github/stars/ptitSeb/box64) ![forks](https://img.shields.io/github/forks/ptitSeb/box64) ![contributors](https://img.shields.io/github/contributors/ptitSeb/box64) ![prs](https://img.shields.io/github/issues-pr/ptitSeb/box64) ![issues](https://img.shields.io/github/issues/ptitSeb/box64)
----
![box64 build status](https://app.travis-ci.com/ptitSeb/box64.svg?branch=main)
Box64 lets you run x86_64 Linux programs (such as games) on non-x86_64 Linux systems, like ARM (host system needs to be 64-bit little-endian).
[中文](README_CN.md)
You can find many Box64 videos on the [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ), [Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) or [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA) YouTube channels.
Box64 lets you run x86_64 Linux programs (such as games) on non-x86_64 Linux systems, like ARM (host system needs to be 64bit little-endian).
Since Box64 uses the native versions of some "system" libraries, like libc, libm, SDL, and OpenGL, it's easy to integrate and use with most applications, and performance can be surprisingly high in many cases. Take a look at thoses bench analysis for an example [here](https://box86.org/index.php/2021/06/game-performances/).
You can find many more Box64 video on Youtube in the [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ), [Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) or [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA) Channels
Box64 integrates with DynaRec (dynamic recompiler) for the ARM64 platform, providing a speed boost between 5 to 10 times faster than using only the interpreter. Some high level information on how DynaRec works can be found [here](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/).
Because Box64 uses the native versions of some "system" libraries, like libc, libm, SDL, and OpenGL, it's easy to integrate and use with most applications, and performance can be surprisingly high in many cases. Take a look at thoses bench analysis for an example [here](https://box86.org/index.php/2021/06/game-performances/).
Box64 integrates a DynaRec (dynamic recompiler) for the ARM64 platform, providing a speed boost between 5 to 10 times faster than only using the interpreter. Some high level information on how the Dynarec work can be found [here](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/).
Some x64 internal opcodes use parts of "Realmode X86 Emulator Library", see [x64primop.c](../src/emu/x64primop.c) for copyright details
@@ -29,7 +29,7 @@ Usage
There are a few environment variables to control the behaviour of Box64.
See [here](USAGE.md) for all the environment variables and what they do.
See [here](USAGE.md) for all environment variables and what they do.
Note: Box64's Dynarec uses a mechanism with Memory Protection and a SegFault signal handler to handle JIT code. In simpler terms, if you want to use GDB to debug a running program that use JIT'd code (like mono/Unity3D), you will still have many "normal" segfaults triggering. It is suggested to use something like `handle SIGSEGV nostop` in GDB to not stop at each segfault, and maybe put a breakpoint inside `my_memprotectionhandler` in `signals.c` if you want to trap SegFaults.
@@ -37,24 +37,24 @@ Note: Box64's Dynarec uses a mechanism with Memory Protection and a SegFault sig
Compiling/Installation
----
> Compilation instructions can be found [here](COMPILE.md).
> Compilation instructions can be found [here](COMPILE.md)
----
Version history/Change log
Version history
----
The change log is available [here](CHANGELOG.md).
The change log is available [here](CHANGELOG.md)
----
Notes about 32-bit platforms
----
Because Box64 works by directly translating function calls from x86_64 to host system, the host system (the one Box64 is running on) needs to have 64-bit libraries. Box64 doesn't include any 64-bit <-> 32-bit translation.
Because Box64 works by directly translating function calls from x86_64 to host system, the host system (the one Box64 is running on) needs to have 64-bits libraries. Box64 doesn't include any 64-bits <-> 32-bits translation.
So understand that box64 will only runs 64-bit linux binaries. For 32-bit binaries, you need box86 (with all the multiarch or proot trickery it imply on 64-bit OS).
Note that many installer (mojo setup based) will fall back to "x86" when detecting ARM64 OS, and so will try to use box86 for the setup, even if an x86_64 version exist. You can hack your way around with a fake "uname" that return "x86_64" when the argument is "-m"
So understand that box64 will only runs 64bits linux binaries. For 32bits binaries, you need box86 (with all the multiarch or proot trickery it imply on 64bits OS).
Note that many installer (mojo setup based) will fall back to "x86" when detecting ARM64 OS, and so will try to use box86 for the setup, even if an x86_64 version exist. You can hack your way around with a fake "uname" that return "x86_64" when argument is "-m"
----
@@ -62,53 +62,53 @@ Notes about Unity game emulation
----
Running Unity games is a hit or miss for now. Unity uses Mono (which uses signals that are not always emulated in a 100% accurate way).
You should also note that some Unity3D games require OpenGL 3+ which can be tricky to provide on ARM SBC (single-board computers).
So, not all Unity games work and can require a high OpenGL profile, but many actualy work 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.
You should also note that some Unity3D games require OpenGL 3+ which can be tricky to provide on ARM SBC (single-board computers) for now.
So, not all Unity games work and can require a high OpenGL profile, but many actualy works 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 start then quit before showing anything.
----
Notes about GTK programs
----
GTK libraries are now wrapped on box64, bu only gtk2, not gtk3 (contrary to box86).
GTK libraries are not wrapped yet on box64 (contrary to box86). Many games use gtk (setup too), like Unity game for the Screen Selection dialog. While Unity game can run without that dialog (using default setup), many just can't. For now, you'll need o put the set of gtk x86_64 libraries in the game folder (or some other folder known by box64) to get gtk support. GTK Wrapping is planned on box64.
----
Notes about Steam
----
Note that Steam is a hybrid 32-bit / 64-bit. You NEED box86 to run Steam, as the client app is a 32-bit binary. It also uses a 64-bit local server binaries, but like most stuff using libcef/chromium, it's not working correctly on box64 for now.
So, no Steam for now on box64.
Not that Steam is an hybrid 32bits / 64bits. You NEED box86 to run steam, as the client app is a 32bits binaries. It also use a 64bits local server binaries, but like most stuff using libcef/chromium. it's not working correctly on box64 for now.
So: no Steam for now on box64.
----
Notes about Wine
----
Wine64 is supported on box64. Proton should also work. Be aware that 64-bit Wine also includes 32-bit components, to be able to run 32-bit Windows programs. The 32-bit apps will need box86 and will not run without it. On a system where both box64 and box86 are present and working, a wine 64-bit setup can run both 32-bit and 64-bit Windows programs (just use `wine` and `wine64` respectively)
Wine 64bits is supported on box64. Be aware that 64bits wine also include 32bits componant, to be able to run 32bits windws programs. The 32bits will need box86 and will not run without it. On a system where both box64 and box86 are present and working, a wine 64bits setup can run both 32bits and 64bits windows program (just use `wine` and `wine64` respectivelly)
----
Notes about Vulkan
----
Box64 wraps Vulkan libraries, but note that it as only been tested with a RX550 card, some extensions may be missing depending on your graphics card.
Box64 Does not wrap Vulkan libraries yet. It's planned, but for now, vulkan program will not run on box64.
----
Final word
----
I want to thank everyone who has contributed to box64 development.
I want to thank everyone who has contributed to box64 developpement.
There are many ways to contribute: code contribution, financial, hardware and advertisement!
So, in no particular order, I want to thank:
* For their major code contribution: rajdakin, mogery
* For their major financial contribution: FlyingFathead, stormchaser3000
* For hardware contribution and LoongArch migration: [xiaoji](https://www.linuxgame.cn/), Deepin Beijing Develop Team
* For their hardware contribution: [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [StarFive](https://rvspace.org/)
* For their hardware contribution: [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/)
* For their continous advertisement of box64 project: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS](https://twisteros.com/) team, [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
And I also thank the many other people who participated even once in this project.
And I also thank the many other people who participated even once in the project.
(If you use Box64 in your project, please don't forget to mention it!)
+3 -3
View File
@@ -77,7 +77,7 @@ Box64的工作原理是直接将函数调用从x86_64转换到主机系统,主
关于GTK程序的注意事项
----
GTK 庫現在包裝在 box64 上,但只有 gtk2,而不是 gtk3(與 box86 相反)。
GTK库尚未封装在Box64内(与Box86相反)。许多游戏(包括设置)都使用gtk,例如Unity游戏的屏幕选择对话框。有些Unity游戏可以在没有该对话框的情况下运行(使用默认设置),还有一些不能。您需要将一套gtk x86_64库放在游戏目录(或其他一些Box64识别的目录)中以获得gtk支持。Box64有计划封装GTK原生库。
----
@@ -98,7 +98,7 @@ box64支持64位Wine,但请注意,64位的Wine还包含32位的组件,以
关于Vulkan注意事项
----
Box64 包裝 Vulkan 庫。但請注意,它僅使用 RX550 卡進行了測試,根據您的圖形卡,可能會缺少某些擴展。
Box64尚未封装原生Vulkan库,有计划这么做,但目前,vulkan程序不能在box64上运行。
----
@@ -110,7 +110,7 @@ Box64 包裝 Vulkan 庫。但請注意,它僅使用 RX550 卡進行了測試
以下感谢不分先后:
* 代码贡献:rajdakin, mogery
* 财务帮助:FlyingFathead, stormchaser3000
* 硬件捐赠:[Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [StarFive](https://rvspace.org/)
* 硬件捐赠:[Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/)
* 硬件捐赠和LoongArch迁移:[xiaoji](https://www.linuxgame.cn)
* 为本项目持续的宣传:salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS](https://twisteros.com/) team, [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
+1 -46
View File
@@ -78,11 +78,6 @@ Disable handling of SigILL (to ease debugging mainly).
* 0 : Let x86 program set sighandler for Illegal Instruction
* 1 : Disables the handling of SigILL
#### BOX64_SHOWSEGV
Show Segfault signal even if a signal handler is present
* 0 : Don"t force show the SIGSEGV analysis (Default.)
* 1 : Show SIGSEGV detail, even if a signal handler is present
#### BOX64_X11THREADS
Call XInitThreads when loading X11. (This is mostly for old Loki games with the Loki_Compat library.)
* 0 : Don't force call XInitThreads. (Default.)
@@ -120,27 +115,6 @@ 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)
#### BOX64_DYNAREC_BIGBLOCK
Enables/Disables Box64'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)
* 1 : Build Dynarec block as big as possible (Default.)
#### BOX64_DYNAREC_STRONGMEM
Enable/Disable simulation of Strong Memory model
* 0 : Don't try anything special (Default.)
* 1 : Enable some Memory Barrier when reading from memory (on some MOV opcode) to simulate Strong Memory Model while trying to limit performance impact (Default when libmonobdwgc-2.0.so is loaded)
* 2 : Enable some Memory Barrier when reading from memory (on some MOV opcode) to simulate Strong Memory Model
#### BOX64_DYNAREC_X87DOUBLE
Force the use of Double for x87 emulation
* 0 : Try to use float when possible for x87 emulation (faster)
* 1 : Only use Double for x87 emulation (slower, may be needed for some specific games, like Crysis)
#### BOX64_DYNAREC_FASTNAN
Enable/Disable generation of -NAN
* 0 : Generate -NAN like on x86 (Default.)
* 1 : Don't do anything special with NAN, to go as fast as possible (was default before this option exsted)
#### BOX64_LIBGL
* libXXXX set the name for libGL (defaults to libGL.so.1).
* /PATH/TO/libGLXXX : Sets the name and path for libGL
@@ -160,32 +134,13 @@ Allow Box64 to continue even if a library is missing.
* 0 : Box64 will stop if a library cannot be loaded. (Default.)
* 1 : Continue even if a needed library cannot be loaded. Unadvised, this will, in most cases, crash later on.
#### BOX64_PREFER_WRAPPED
Box64 will use wrapped libs even if the lib is specified with absolute path
* 0 : Try to use emulated libs when they are defined with absolute path (Default.)
* 1 : Use Wrapped native libs even if path is absolute
#### BOX64_PREFER_EMULATED
Box64 will prefer emulated libs first (execpt for glibc, alsa, pulse, GL, vulkan and X11
* 0 : Native libs are prefered (Default.)
* 1 : Emulated libs are prefered (Default for program running inside pressure-vessel)
#### BOX64_NOPULSE
Disables the load of pulseaudio libraries.
* 0 : Load pulseaudio libraries if found. (Default.)
* 1 : Disables the load of pulse audio libraries (libpulse and libpulse-simple), both the native library and the x86 library
#### BOX64_NOGTK
Disables the loading of wrapped GTK libraries.
* 0 : Load wrapped GTK libraries if found. (Default.)
* 1 : Disables loading wrapped GTK libraries.
#### BOX64_NOVULKAN
Disables the load of vulkan libraries.
* 0 : Load vulkan libraries if found.
* 1 : Disables the load of vulkan libraries, both the native and the i386 version (can be useful on Pi4, where the vulkan driver is not quite there yet.)
#### BOX64_JITGDB
* 0 : Just print the Segfault message on segfault (default)
* 1 : Launch `gdb` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process and go in an endless loop, waiting.
When in gdb, you need to find the correct thread yourself (the one with `my_box64signalhandler` in is stack)
+2 -2
View File
@@ -1,7 +1,7 @@
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>
# Maintainer: Jai-JAP <parjailu@gmail.com>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-arm64-git
pkgver=r1495.e6e9fae
pkgver=1116.9243ea4
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
+2 -2
View File
@@ -1,7 +1,7 @@
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>
# Maintainer: Jai-JAP <parjailu@gmail.com>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-arm64-git
pkgver=r1495.e6e9fae
pkgver=1116.9243ea4
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
-44
View File
@@ -1,44 +0,0 @@
# Maintainer: Jai-JAP <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-lx2160a-git
pkgver=r1495.e6e9fae
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
url="https://github.com/ptitSeb/box64"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-lx2160a-git}-git" "${pkgname%-lx2160a-git}")
conflicts=("${pkgname%-git}" "${pkgname%-lx2160a-git}-git" "${pkgname%-lx2160a-git}")
source=('git+https://github.com/ptitSeb/box64')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-lx2160a-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-lx2160a-git}"
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DLX2160A=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
fi
}
build() {
cd "$srcdir/${pkgname%-lx2160a-git}/build"
make -j$(nproc)
}
package() {
cd "$srcdir/${pkgname%-lx2160a-git}/build"
make DESTDIR="${pkgdir}/" install
# /usr/local/bin isn't in PATH by the default,
# we should move it to /usr/bin
cd ${pkgdir}
mv usr/local/bin/ usr/bin/
# cleanup when dir is empty
rmdir usr/local || exit 0
}
-44
View File
@@ -1,44 +0,0 @@
# Maintainer: Jai-JAP <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-lx2160a-git
pkgver=r1495.e6e9fae
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
url="https://github.com/ptitSeb/box64"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-lx2160a-git}-git" "${pkgname%-lx2160a-git}")
conflicts=("${pkgname%-git}" "${pkgname%-lx2160a-git}-git" "${pkgname%-lx2160a-git}")
source=('git+https://github.com/ptitSeb/box64')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-lx2160a-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-lx2160a-git}"
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DLX2160A=1 -DCMAKE_BUILD_TYPE=Debug
fi
}
build() {
cd "$srcdir/${pkgname%-lx2160a-git}/build"
make -j$(nproc)
}
package() {
cd "$srcdir/${pkgname%-lx2160a-git}/build"
make DESTDIR="${pkgdir}/" install
# /usr/local/bin isn't in PATH by the default,
# we should move it to /usr/bin
cd ${pkgdir}
mv usr/local/bin/ usr/bin/
# cleanup when dir is empty
rmdir usr/local || exit 0
}
+3 -3
View File
@@ -1,7 +1,7 @@
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>
# Maintainer: Jai-JAP <parjailu@gmail.com>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box86-rk3399-git
pkgver=r1495.e6e9fae
pkgver=1116.9243ea4
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
@@ -41,4 +41,4 @@ package() {
mv usr/local/bin/ usr/bin/
# cleanup when dir is empty
rmdir usr/local || exit 0
}
}
+2 -2
View File
@@ -1,7 +1,7 @@
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>
# Maintainer: Jai-JAP <parjailu@gmail.com>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box86-rk3399-git
pkgver=r1495.e6e9fae
pkgver=1116.9243ea4
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
+2 -2
View File
@@ -1,7 +1,7 @@
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>
# Maintainer: Jai-JAP <parjailu@gmail.com>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-rpi-git
pkgver=r1495.e6e9fae
pkgver=1116.9243ea4
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
+2 -2
View File
@@ -1,7 +1,7 @@
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>
# Maintainer: Jai-JAP <parjailu@gmail.com>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-rpi-git
pkgver=r1495.e6e9fae
pkgver=1116.9243ea4
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
+2 -2
View File
@@ -1,7 +1,7 @@
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>
# Maintainer: Jai-JAP <parjailu@gmail.com>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-tegra-git
pkgver=r1495.e6e9fae
pkgver=1116.9243ea4
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
+2 -2
View File
@@ -1,7 +1,7 @@
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>
# Maintainer: Jai-JAP <parjailu@gmail.com>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-tegra-git
pkgver=r1495.e6e9fae
pkgver=1116.9243ea4
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
+2 -2
View File
@@ -1,7 +1,7 @@
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>
# Maintainer: Jai-JAP <parjailu@gmail.com>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-x64-git
pkgver=r1495.e6e9fae
pkgver=1116.9243ea4
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
+2 -2
View File
@@ -1,7 +1,7 @@
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>
# Maintainer: Jai-JAP <parjailu@gmail.com>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box64-x64-git
pkgver=r1495.e6e9fae
pkgver=1116.9243ea4
pkgrel=1
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
arch=('aarch64')
+4 -4
View File
@@ -12,13 +12,13 @@ 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).
All specified in [COMPILE.md](../COMPILE.md).
### 3. Any advantages with this solution?
This might give you some advantages like:
### 3. Any advantages with that sollution?
This might give you some advantages like those:
- automatic updates (with some AUR frontends like [`pamac-aur`](https://aur.archlinux.org/packages/pamac-aur/) or [`yay`](https://aur.archlinux.org/packages/yay));
- easily uninstall with `pacman -R` when no needed (no need other scripts nor Makefile to do this);
- your `box64` installation is recognized as a package (where it wasn't when installing with `make install`).
### Note: You can use [makedeb](https://github.com/makedeb/makedeb) (or) [pkgbuild2spec](https://github.com/prozum/pkgbuild2spec) to compile box64 to .deb or .rpm installer files.
### Note: You can use [makedeb](https://github.com/makedeb/makedeb) (or) [pkgbuild2spec](https://github.com/prozum/pkgbuild2spec) to compile box64 to .deb or .rpm installer files.
-11
View File
@@ -32,9 +32,6 @@ execute_process(
# if the return value is !=0 bail out
if( TEST_RESULT )
get_filename_component(TESTNAME "${TEST_ARGS}" NAME)
file(RENAME "${TEST_OUTPUT}" "${CMAKE_BINARY_DIR}/${TESTNAME}.out")
file(WRITE "${CMAKE_BINARY_DIR}/${TESTNAME}.err" ${TEST_ERROR})
message( FATAL_ERROR "Failed: Test program ${TEST_PROGRAM} exited != 0.\n${TEST_ERROR}" )
endif( TEST_RESULT )
@@ -46,16 +43,8 @@ execute_process(
# again, if return value is !=0 scream and shout
if( TEST_RESULT )
get_filename_component(TESTNAME "${TEST_ARGS}" NAME)
file(RENAME "${TEST_OUTPUT}" "${CMAKE_BINARY_DIR}/${TESTNAME}.out")
file(WRITE "${CMAKE_BINARY_DIR}/${TESTNAME}.err" ${TEST_ERROR})
message( FATAL_ERROR "Failed: The output of ${TEST_PROGRAM} did not match ${TEST_REFERENCE}")
endif( TEST_RESULT )
# remove the temporary files if they exist
if( EXISTS ${TEST_OUTPUT} )
file(REMOVE "${TEST_OUTPUT}")
endif()
# everything went fine...
message( "Passed: The output of ${TEST_PROGRAM} matches ${TEST_REFERENCE}" )
+35 -22
View File
@@ -5,8 +5,10 @@
#include <dlfcn.h>
#include <signal.h>
#include <sys/mman.h>
#include <pthread.h>
#ifdef DYNAREC
#include "dynarec/arm64_lock.h"
#endif
#include "box64context.h"
#include "debug.h"
#include "elfloader.h"
@@ -124,11 +126,11 @@ static void init_mutexes(box64context_t* context)
pthread_mutex_init(&context->mutex_once, &attr);
pthread_mutex_init(&context->mutex_once2, &attr);
pthread_mutex_init(&context->mutex_trace, &attr);
#ifndef DYNAREC
pthread_mutex_init(&context->mutex_lock, &attr);
#else
#ifdef DYNAREC
pthread_mutex_init(&context->mutex_dyndump, &attr);
#endif
#else
pthread_mutex_init(&context->mutex_lock, &attr);
#endif
pthread_mutex_init(&context->mutex_tls, &attr);
pthread_mutex_init(&context->mutex_thread, &attr);
pthread_mutex_init(&context->mutex_bridge, &attr);
@@ -136,10 +138,24 @@ static void init_mutexes(box64context_t* context)
pthread_mutexattr_destroy(&attr);
}
void startMailbox(void);
void haltMailbox(void);
static void atfork_prepare_box64context(void)
{
// semaphores will go in undetermined state
haltMailbox();
}
static void atfork_parent_box64context(void)
{
// reinit mailbox only
init_mutexes(my_context);
startMailbox();
}
static void atfork_child_box64context(void)
{
// (re)init mutex if it was lock before the fork
// reinit mutexes and mailbox
init_mutexes(my_context);
startMailbox();
}
EXPORTDYN
@@ -181,7 +197,7 @@ box64context_t *NewBox64Context(int argc)
context->argv = (char**)calloc(context->argc+1, sizeof(char*));
init_mutexes(context);
pthread_atfork(NULL, NULL, atfork_child_box64context);
pthread_atfork(atfork_prepare_box64context, atfork_parent_box64context, atfork_child_box64context);
pthread_key_create(&context->tlskey, free_tlsdatasize);
@@ -260,9 +276,6 @@ void FreeBox64Context(box64context_t** context)
freeGLProcWrapper(ctx);
freeALProcWrapper(ctx);
if(ctx->stack_clone)
free(ctx->stack_clone);
void* ptr;
if ((ptr = pthread_getspecific(ctx->tlskey)) != NULL) {
@@ -274,6 +287,18 @@ void FreeBox64Context(box64context_t** context)
if(ctx->tlsdata)
free(ctx->tlsdata);
pthread_mutex_destroy(&ctx->mutex_once);
pthread_mutex_destroy(&ctx->mutex_once2);
pthread_mutex_destroy(&ctx->mutex_trace);
#ifdef DYNAREC
pthread_mutex_destroy(&ctx->mutex_dyndump);
#else
pthread_mutex_destroy(&ctx->mutex_lock);
#endif
pthread_mutex_destroy(&ctx->mutex_tls);
pthread_mutex_destroy(&ctx->mutex_thread);
pthread_mutex_destroy(&ctx->mutex_bridge);
free_neededlib(&ctx->neededlibs);
if(ctx->emu_sig)
@@ -281,18 +306,6 @@ void FreeBox64Context(box64context_t** context)
finiAllHelpers(ctx);
pthread_mutex_destroy(&ctx->mutex_once);
pthread_mutex_destroy(&ctx->mutex_once2);
pthread_mutex_destroy(&ctx->mutex_trace);
#ifndef DYNAREC
pthread_mutex_destroy(&ctx->mutex_lock);
#else
pthread_mutex_destroy(&ctx->mutex_dyndump);
#endif
pthread_mutex_destroy(&ctx->mutex_tls);
pthread_mutex_destroy(&ctx->mutex_thread);
pthread_mutex_destroy(&ctx->mutex_bridge);
free(ctx);
}
+1 -1
View File
@@ -3,6 +3,6 @@
#define BOX64_MAJOR 0
#define BOX64_MINOR 1
#define BOX64_REVISION 8
#define BOX64_REVISION 5
#endif //__BOX64_VERSION_H_
+291 -384
View File
@@ -4,7 +4,6 @@
#include <string.h>
#include <dlfcn.h>
#include <signal.h>
#include <pthread.h>
#include "box64context.h"
#include "elfloader.h"
@@ -25,13 +24,14 @@
#include "threads.h"
#ifdef DYNAREC
#include "dynablock.h"
#include "dynarec/native_lock.h"
#include "dynarec/arm64_lock.h"
//#define USE_MMAP
// init inside dynablocks.c
KHASH_MAP_INIT_INT64(dynablocks, dynablock_t*)
static dynablocklist_t*** dynmap123[1<<DYNAMAP_SHIFT]; // 64bits.. in 4x16bits array
static pthread_mutex_t mutex_mmap;
static mmaplist_t *mmaplist = NULL;
static size_t mmapsize = 0;
static size_t mmapcap = 0;
@@ -41,26 +41,13 @@ static uintptr_t** box64_jmptbldefault2[1<<JMPTABL_SHIFT];
static uintptr_t* box64_jmptbldefault1[1<<JMPTABL_SHIFT];
static uintptr_t box64_jmptbldefault0[1<<JMPTABL_SHIFT];
#endif
static pthread_mutex_t mutex_prot;
#if defined(PAGE16K)
#define MEMPROT_SHIFT 14
#define MEMPROT_SHIFT2 (16+14)
#else
#define MEMPROT_SHIFT 12
#define MEMPROT_SHIFT2 (16+12)
#endif
#define MEMPROT_SIZE (1<<16)
static uint8_t *volatile memprot[1<<20]; // x86_64 mem is 48bits, page is 12bits, so memory is tracked as [20][16][page protection]
static uint8_t memprot_default[MEMPROT_SIZE];
#define MEMPROT_SHIFT2 (32-MEMPROT_SHIFT)
#define MEMPROT_SIZE (1<<(32-MEMPROT_SHIFT))
KHASH_MAP_INIT_INT(memprot, uint8_t*)
static kh_memprot_t *memprot;
static int inited = 0;
typedef struct mapmem_s {
uintptr_t begin, end;
struct mapmem_s *next;
} mapmem_t;
static mapmem_t *mapmem = NULL;
typedef struct blocklist_s {
void* block;
size_t maxfree;
@@ -509,9 +496,11 @@ uintptr_t AllocDynarecMap(dynablock_t* db, size_t size)
if(!size)
return 0;
if(size>MMAPSIZE-2*sizeof(blockmark_t)) {
//pthread_mutex_lock(&mutex_mmap);
#ifndef USE_MMAP
void *p = NULL;
if(posix_memalign(&p, box64_pagesize, size)) {
//pthread_mutex_unlock(&mutex_mmap);
dynarec_log(LOG_INFO, "Cannot create dynamic map of %zu bytes\n", size);
return 0;
}
@@ -519,6 +508,7 @@ uintptr_t AllocDynarecMap(dynablock_t* db, size_t size)
#else
void* p = mmap(NULL, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
if(p==(void*)-1) {
//pthread_mutex_unlock(&mutex_mmap);
dynarec_log(LOG_INFO, "Cannot create dynamic map of %zu bytes\n", size);
return 0;
}
@@ -533,14 +523,18 @@ uintptr_t AllocDynarecMap(dynablock_t* db, size_t size)
int ret;
k = kh_put(dynablocks, blocks, (uintptr_t)p, &ret);
kh_value(blocks, k) = db;
//pthread_mutex_unlock(&mutex_mmap);
return (uintptr_t)p;
}
//pthread_mutex_lock(&mutex_mmap);
uintptr_t ret = FindFreeDynarecMap(db, size);
if(!ret)
ret = AddNewDynarecMap(db, size);
//pthread_mutex_unlock(&mutex_mmap);
return ret;
}
@@ -549,6 +543,7 @@ void FreeDynarecMap(dynablock_t* db, uintptr_t addr, size_t size)
if(!addr || !size)
return;
if(size>MMAPSIZE-2*sizeof(blockmark_t)) {
//pthread_mutex_lock(&mutex_mmap);
#ifndef USE_MMAP
free((void*)addr);
#else
@@ -560,9 +555,12 @@ void FreeDynarecMap(dynablock_t* db, uintptr_t addr, size_t size)
if(k!=kh_end(blocks))
kh_del(dynablocks, blocks, k);
}
//pthread_mutex_unlock(&mutex_mmap);
return;
}
//pthread_mutex_lock(&mutex_mmap);
ActuallyFreeDynarecMap(db, addr, size);
//pthread_mutex_unlock(&mutex_mmap);
}
dynablocklist_t* getDB(uintptr_t idx)
@@ -592,17 +590,17 @@ void addDBFromAddressRange(uintptr_t addr, size_t size)
int idx1 = (i )&((1<<DYNAMAP_SHIFT)-1);
if(!dynmap123[idx3]) {
dynablocklist_t*** p = (dynablocklist_t***)calloc(1<<DYNAMAP_SHIFT, sizeof(dynablocklist_t**));
if(native_lock_storeifnull(&dynmap123[idx3], p)!=p)
if(arm64_lock_storeifnull(&dynmap123[idx3], (uint64_t)p)!=(uint64_t)p)
free(p);
}
if(!dynmap123[idx3][idx2]) {
dynablocklist_t** p = (dynablocklist_t**)calloc(1<<DYNAMAP_SHIFT, sizeof(dynablocklist_t*));
if(native_lock_storeifnull(&dynmap123[idx3][idx2], p)!=p)
if(arm64_lock_storeifnull(&dynmap123[idx3][idx2], (uint64_t)p)!=(uint64_t)p)
free(p);
}
if(!dynmap123[idx3][idx2][idx1]) {
dynablocklist_t* p = NewDynablockList(i<<DYNAMAP_SHIFT, 1<<DYNAMAP_SHIFT, 0);
if(native_lock_storeifnull(&dynmap123[idx3][idx2][idx1], p)!=p)
if(arm64_lock_storeifnull(&dynmap123[idx3][idx2][idx1], (uint64_t)p)!=(uint64_t)p)
FreeDynablockList(&p);
}
}
@@ -631,13 +629,13 @@ void cleanDBFromAddressRange(uintptr_t addr, size_t size, int destroy)
if(destroy) {
if(FreeRangeDynablock(dblist, addr, size) && 0) { // dblist is empty, check if we can delete more...
// disabling this for now. It seems to cause random crash in Terraria
if(!native_lock_storeifref(&dynmap123[idx3][idx2][idx1], NULL, dblist)) {
if(!arm64_lock_storeifref(&dynmap123[idx3][idx2][idx1], 0, (uint64_t)dblist)) {
dynablocklist_t** p = dynmap123[idx3][idx2];
if(dynmapempty((void**)p)) {
if(!native_lock_storeifref(&dynmap123[idx3][idx2], NULL, p)) {
if(!arm64_lock_storeifref(&dynmap123[idx3][idx2], 0, (uint64_t)p)) {
dynablocklist_t*** p2 = dynmap123[idx3];
if(dynmapempty((void**)p2)) {
if(!native_lock_storeifref(&dynmap123[idx3], NULL, p2)) {
if(!arm64_lock_storeifref(&dynmap123[idx3], 0, (uint64_t)p2)) {
free(p2);
}
}
@@ -656,12 +654,6 @@ void cleanDBFromAddressRange(uintptr_t addr, size_t size, int destroy)
#ifdef ARM64
void arm64_next(void);
#define native_next arm64_next
#elif defined(LA464)
void la464_next(void);
#define native_next la464_next
#else
#error Unsupported architecture
#endif
void addJumpTableIfDefault64(void* addr, void* jmp)
@@ -675,25 +667,25 @@ void addJumpTableIfDefault64(void* addr, void* jmp)
uintptr_t*** tbl = (uintptr_t***)malloc((1<<JMPTABL_SHIFT)*sizeof(uintptr_t**));
for(int i=0; i<(1<<JMPTABL_SHIFT); ++i)
tbl[i] = box64_jmptbldefault1;
if(native_lock_storeifref(&box64_jmptbl3[idx3], tbl, box64_jmptbldefault2)!=tbl)
if(arm64_lock_storeifref(&box64_jmptbl3[idx3], (uint64_t)tbl, (uint64_t)box64_jmptbldefault2)!=(uint64_t)tbl)
free(tbl);
}
if(box64_jmptbl3[idx3][idx2] == box64_jmptbldefault1) {
uintptr_t** tbl = (uintptr_t**)malloc((1<<JMPTABL_SHIFT)*sizeof(uintptr_t*));
for(int i=0; i<(1<<JMPTABL_SHIFT); ++i)
tbl[i] = box64_jmptbldefault0;
if(native_lock_storeifref(&box64_jmptbl3[idx3][idx2], tbl, box64_jmptbldefault1)!=tbl)
if(arm64_lock_storeifref(&box64_jmptbl3[idx3][idx2], (uint64_t)tbl, (uint64_t)box64_jmptbldefault1)!=(uint64_t)tbl)
free(tbl);
}
if(box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0) {
uintptr_t* tbl = (uintptr_t*)malloc((1<<JMPTABL_SHIFT)*sizeof(uintptr_t));
for(int i=0; i<(1<<JMPTABL_SHIFT); ++i)
tbl[i] = (uintptr_t)native_next;
if(native_lock_storeifref(&box64_jmptbl3[idx3][idx2][idx1], tbl, box64_jmptbldefault0)!=tbl)
tbl[i] = (uintptr_t)arm64_next;
if(arm64_lock_storeifref(&box64_jmptbl3[idx3][idx2][idx1], (uint64_t)tbl, (uint64_t)box64_jmptbldefault0)!=(uint64_t)tbl)
free(tbl);
}
native_lock_storeifref(&box64_jmptbl3[idx3][idx2][idx1][idx0], jmp, native_next);
arm64_lock_storeifref(&box64_jmptbl3[idx3][idx2][idx1][idx0], (uint64_t)jmp, (uint64_t)arm64_next);
}
void setJumpTableDefault64(void* addr)
{
@@ -708,9 +700,9 @@ void setJumpTableDefault64(void* addr)
return;
if(box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0)
return;
if(box64_jmptbl3[idx3][idx2][idx1][idx0]==(uintptr_t)native_next)
if(box64_jmptbl3[idx3][idx2][idx1][idx0]==(uintptr_t)arm64_next)
return;
box64_jmptbl3[idx3][idx2][idx1][idx0] = (uintptr_t)native_next;
box64_jmptbl3[idx3][idx2][idx1][idx0] = (uintptr_t)arm64_next;
}
int isJumpTableDefault64(void* addr)
{
@@ -725,9 +717,9 @@ int isJumpTableDefault64(void* addr)
return 1;
if(box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0)
return 1;
if(box64_jmptbl3[idx3][idx2][idx1][idx0]==(uintptr_t)native_next)
if(box64_jmptbl3[idx3][idx2][idx1][idx0]==(uintptr_t)arm64_next)
return 1;
return (box64_jmptbl3[idx3][idx2][idx1][idx0]==(uintptr_t)native_next)?1:0;
return (box64_jmptbl3[idx3][idx2][idx1][idx0]==(uintptr_t)arm64_next)?1:0;
}
uintptr_t getJumpTable64()
{
@@ -745,21 +737,21 @@ uintptr_t getJumpTableAddress64(uintptr_t addr)
uintptr_t*** tbl = (uintptr_t***)malloc((1<<JMPTABL_SHIFT)*sizeof(uintptr_t**));
for(int i=0; i<(1<<JMPTABL_SHIFT); ++i)
tbl[i] = box64_jmptbldefault1;
if(native_lock_storeifref(&box64_jmptbl3[idx3], tbl, box64_jmptbldefault2)!=tbl)
if(arm64_lock_storeifref(&box64_jmptbl3[idx3], (uint64_t)tbl, (uint64_t)box64_jmptbldefault2)!=(uint64_t)tbl)
free(tbl);
}
if(box64_jmptbl3[idx3][idx2] == box64_jmptbldefault1) {
uintptr_t** tbl = (uintptr_t**)malloc((1<<JMPTABL_SHIFT)*sizeof(uintptr_t*));
for(int i=0; i<(1<<JMPTABL_SHIFT); ++i)
tbl[i] = box64_jmptbldefault0;
if(native_lock_storeifref(&box64_jmptbl3[idx3][idx2], tbl, box64_jmptbldefault1)!=tbl)
if(arm64_lock_storeifref(&box64_jmptbl3[idx3][idx2], (uint64_t)tbl, (uint64_t)box64_jmptbldefault1)!=(uint64_t)tbl)
free(tbl);
}
if(box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0) {
uintptr_t* tbl = (uintptr_t*)malloc((1<<JMPTABL_SHIFT)*sizeof(uintptr_t));
for(int i=0; i<(1<<JMPTABL_SHIFT); ++i)
tbl[i] = (uintptr_t)native_next;
if(native_lock_storeifref(&box64_jmptbl3[idx3][idx2][idx1], tbl, box64_jmptbldefault0)!=tbl)
tbl[i] = (uintptr_t)arm64_next;
if(arm64_lock_storeifref(&box64_jmptbl3[idx3][idx2][idx1], (uint64_t)tbl, (uint64_t)box64_jmptbldefault0)!=(uint64_t)tbl)
free(tbl);
}
@@ -767,281 +759,164 @@ uintptr_t getJumpTableAddress64(uintptr_t addr)
}
// Remove the Write flag from an adress range, so DB can be executed safely
void protectDB(uintptr_t addr, uintptr_t size)
void internalProtectDB(uintptr_t addr, uintptr_t size)
{
dynarec_log(LOG_DEBUG, "protectDB %p -> %p\n", (void*)addr, (void*)(addr+size-1));
dynarec_log(LOG_DEBUG, "internalProtectDB %p -> %p\n", (void*)addr, (void*)(addr+size-1));
uintptr_t idx = (addr>>MEMPROT_SHIFT);
uintptr_t end = ((addr+size-1LL)>>MEMPROT_SHIFT);
if(end>=(1LL<<(48-MEMPROT_SHIFT)))
end = (1LL<<(48-MEMPROT_SHIFT))-1;
if(end<idx) // memory addresses higher than 48bits are not tracked
return;
pthread_mutex_lock(&mutex_prot);
int ret;
for (uintptr_t i=(idx>>16); i<=(end>>16); ++i)
if(memprot[i]==memprot_default) {
uint8_t* newblock = calloc(1<<16, sizeof(uint8_t));
/*if (native_lock_storeifref(&memprot[i], newblock, memprot_default) != newblock) {
free(newblock);
}*/
memprot[i] = newblock;
}
for (uintptr_t i=idx; i<=end; ++i) {
uint32_t prot = memprot[i>>16][i&0xffff];
if(!prot)
prot = PROT_READ | PROT_WRITE | PROT_EXEC; // comes from malloc & co, so should not be able to execute
if((prot&PROT_WRITE)) {
prot&=~PROT_WRITE;
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot);
memprot[i>>16][i&0xffff] = prot|PROT_DYNAREC; // need to use atomic exchange?
const uint32_t key = (i>>MEMPROT_SHIFT2)&0xffffffff;
khint_t k = kh_put(memprot, memprot, key, &ret);
if(ret) {
uint8_t *m = (uint8_t*)calloc(1, MEMPROT_SIZE);
kh_value(memprot, k) = m;
}
const uintptr_t ii = i&(MEMPROT_SIZE-1);
uint8_t prot = kh_value(memprot, k)[ii];
if(!(prot&PROT_DYNAREC)) {
if(!prot)
prot = PROT_READ | PROT_WRITE; // comes from malloc & co, so should not be able to execute
kh_value(memprot, k)[ii] = prot|PROT_DYNAREC;
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~(PROT_WRITE|PROT_CUSTOM));
}
}
pthread_mutex_unlock(&mutex_prot);
}
int internalIsprotectedDB(uintptr_t addr, size_t size)
{
uintptr_t idx = (addr>>MEMPROT_SHIFT);
uintptr_t end = ((addr+size-1LL)>>MEMPROT_SHIFT);
int ret;
for (uintptr_t i=idx; i<=end; ++i) {
const uint32_t key = (i>>MEMPROT_SHIFT2)&0xffffffff;
khint_t k = kh_put(memprot, memprot, key, &ret);
if(ret) {
uint8_t *m = (uint8_t*)calloc(1, MEMPROT_SIZE);
kh_value(memprot, k) = m;
}
const uintptr_t ii = i&(MEMPROT_SIZE-1);
uint8_t prot = kh_value(memprot, k)[ii];
if(!(prot&PROT_DYNAREC)) {
return 0;
}
}
return 1;
}
// Add the Write flag from an adress range, and mark all block as dirty
// no log, as it can be executed inside a signal handler
void unprotectDB(uintptr_t addr, size_t size)
void internalUnprotectDB(uintptr_t addr, size_t size)
{
dynarec_log(LOG_DEBUG, "unprotectDB %p -> %p\n", (void*)addr, (void*)(addr+size-1));
dynarec_log(LOG_DEBUG, "internalUnprotectDB %p -> %p\n", (void*)addr, (void*)(addr+size-1));
uintptr_t idx = (addr>>MEMPROT_SHIFT);
uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
if(end>=(1LL<<(48-MEMPROT_SHIFT)))
end = (1LL<<(48-MEMPROT_SHIFT))-1;
if(end<idx) // memory addresses higher than 48bits are not tracked
return;
pthread_mutex_lock(&mutex_prot);
for (uintptr_t i=(idx>>16); i<=(end>>16); ++i)
if(memprot[i]==memprot_default) {
uint8_t* newblock = calloc(1<<16, sizeof(uint8_t));
/*if (native_lock_storeifref(&memprot[i], newblock, memprot_default) != newblock) {
free(newblock);
}*/
memprot[i] = newblock;
}
uintptr_t end = ((addr+size-1LL)>>MEMPROT_SHIFT);
int ret;
for (uintptr_t i=idx; i<=end; ++i) {
uint32_t prot = memprot[i>>16][i&0xffff];
const uint32_t key = (i>>MEMPROT_SHIFT2)&0xffffffff;
khint_t k = kh_put(memprot, memprot, key, &ret);
if(ret) {
uint8_t *m = (uint8_t*)calloc(1, MEMPROT_SIZE);
kh_value(memprot, k) = m;
}
const uintptr_t ii = i&(MEMPROT_SIZE-1);
uint8_t prot = kh_value(memprot, k)[ii];
if(prot&PROT_DYNAREC) {
prot&=~PROT_DYNAREC;
prot|=PROT_WRITE;
kh_value(memprot, k)[ii] = prot&~PROT_DYNAREC;
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_CUSTOM);
cleanDBFromAddressRange((i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, 0);
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot);
memprot[i>>16][i&0xffff] = prot; // need to use atomic exchange?
}
}
pthread_mutex_unlock(&mutex_prot);
}
int isprotectedDB(uintptr_t addr, size_t size)
#endif
void internalUpdateProtection(uintptr_t addr, size_t size, uint32_t prot)
{
dynarec_log(LOG_DEBUG, "isprotectedDB %p -> %p => ", (void*)addr, (void*)(addr+size-1));
dynarec_log(LOG_DEBUG, "internalUpdateProtection %p:%p 0x%x\n", (void*)addr, (void*)(addr+size-1), prot);
uintptr_t idx = (addr>>MEMPROT_SHIFT);
uintptr_t end = ((addr+size-1LL)>>MEMPROT_SHIFT);
if(end>=(1LL<<(48-MEMPROT_SHIFT)))
end = (1LL<<(48-MEMPROT_SHIFT))-1LL;
if(end<idx) { // memory addresses higher than 48bits are not tracked
dynarec_log(LOG_DEBUG, "00\n");
return 0;
}
int ret;
uintptr_t last = idx<<MEMPROT_SHIFT;
uint8_t oldprot = 0xff;
for (uintptr_t i=idx; i<=end; ++i) {
uint32_t prot = memprot[i>>16][i&0xffff];
if((prot&PROT_WRITE)) {
dynarec_log(LOG_DEBUG, "0\n");
return 0;
const uint32_t key = (i>>MEMPROT_SHIFT2)&0xffffffff;
khint_t k = kh_put(memprot, memprot, key, &ret);
if(ret) {
uint8_t *m = (uint8_t*)calloc(1, MEMPROT_SIZE);
kh_value(memprot, k) = m;
}
}
dynarec_log(LOG_DEBUG, "1\n");
return 1;
}
#endif
void printMapMem()
{
mapmem_t* m = mapmem;
while(m) {
printf_log(LOG_INFO, " %p-%p\n", (void*)m->begin, (void*)m->end);
m = m->next;
}
}
void addMapMem(uintptr_t begin, uintptr_t end)
{
begin &=~0xfff;
end = (end&~0xfff)+0xfff; // full page
// sanitize values
if(end<0x10000) return;
if(!begin) begin = 0x10000;
// find attach point (cannot be the 1st one by construction)
mapmem_t* m = mapmem;
while(m->next && begin>m->next->begin) {
m = m->next;
}
// attach at the end of m
mapmem_t* newm;
if(m->end>=begin-1) {
if(end<=m->end)
return; // zone completly inside current block, nothing to do
m->end = end; // enlarge block
newm = m;
} else {
// create a new block
newm = (mapmem_t*)calloc(1, sizeof(mapmem_t));
newm->next = m->next;
newm->begin = begin;
newm->end = end;
m->next = newm;
}
while(newm && newm->next && (newm->next->begin-1)<=newm->end) {
// fuse with next
if(newm->next->end>newm->end)
newm->end = newm->next->end;
mapmem_t* tmp = newm->next;
newm->next = tmp->next;
free(tmp);
}
// all done!
}
void removeMapMem(uintptr_t begin, uintptr_t end)
{
begin &=~0xfff;
end = (end&~0xfff)+0xfff; // full page
// sanitize values
if(end<0x10000) return;
if(!begin) begin = 0x10000;
mapmem_t* m = mapmem, *prev = NULL;
while(m) {
// check if block is beyond the zone to free
if(m->begin > end)
return;
// check if the block is completly inside the zone to free
if(m->begin>=begin && m->end<=end) {
// just free the block
mapmem_t *tmp = m;
if(prev) {
prev->next = m->next;
m = prev;
} else {
mapmem = m->next; // change attach, but should never happens
m = mapmem;
prev = NULL;
}
free(tmp);
} else if(begin>m->begin && end<m->end) { // the zone is totaly inside the block => split it!
mapmem_t* newm = (mapmem_t*)calloc(1, sizeof(mapmem_t)); // create a new "next"
newm->end = m->end;
m->end = begin - 1;
newm->begin = end + 1;
newm->next = m->next;
m->next = newm;
// nothing more to free
return;
} else if(begin>m->begin && begin<m->end) { // free the tail of the block
m->end = begin - 1;
} else if(end>m->begin && end<m->end) { // free the head of the block
m->begin = end + 1;
}
prev = m;
m = m->next;
}
}
void updateProtection(uintptr_t addr, size_t size, uint32_t prot)
{
dynarec_log(LOG_DEBUG, "updateProtection %p:%p 0x%x\n", (void*)addr, (void*)(addr+size-1), prot);
addMapMem(addr, addr+size-1);
uintptr_t idx = (addr>>MEMPROT_SHIFT);
uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
if(end>=(1LL<<(48-MEMPROT_SHIFT)))
end = (1LL<<(48-MEMPROT_SHIFT))-1;
if(end<idx) // memory addresses higher than 48bits are not tracked
return;
pthread_mutex_lock(&mutex_prot);
for (uintptr_t i=(idx>>16); i<=(end>>16); ++i)
if(memprot[i]==memprot_default) {
uint8_t* newblock = calloc(1<<16, sizeof(uint8_t));
#if 0 //def ARM64 //disabled for now, not usefull with the mutex
if (native_lock_storeifref(&memprot[i], newblock, memprot_default) != newblock) {
free(newblock);
}
#else
memprot[i] = newblock;
#endif
}
for (uintptr_t i=idx; i<=end; ++i) {
uint32_t dyn=(memprot[i>>16][i&0xffff]&PROT_DYNAREC);
if(dyn && (prot&PROT_WRITE)) // need to remove the write protection from this block
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_WRITE);
memprot[i>>16][i&0xffff] = prot|dyn;
}
pthread_mutex_unlock(&mutex_prot);
}
void setProtection(uintptr_t addr, size_t size, uint32_t prot)
{
addMapMem(addr, addr+size-1);
uintptr_t idx = (addr>>MEMPROT_SHIFT);
uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
if(end>=(1LL<<(48-MEMPROT_SHIFT)))
end = (1LL<<(48-MEMPROT_SHIFT))-1;
if(end<idx) // memory addresses higher than 48bits are not tracked
return;
pthread_mutex_lock(&mutex_prot);
for (uintptr_t i=(idx>>16); i<=(end>>16); ++i)
if(memprot[i]==memprot_default) {
uint8_t* newblock = calloc(MEMPROT_SIZE, sizeof(uint8_t));
#if 0 //def ARM64 //disabled for now, not usefull with the mutex
if (native_lock_storeifref(&memprot[i], newblock, memprot_default) != newblock) {
free(newblock);
}
#else
memprot[i] = newblock;
#endif
}
for (uintptr_t i=idx; i<=end; ++i)
memprot[i>>16][i&0xffff] = prot;
pthread_mutex_unlock(&mutex_prot);
}
void allocProtection(uintptr_t addr, size_t size, uint32_t prot)
{
dynarec_log(LOG_DEBUG, "allocProtection %p:%p 0x%x\n", (void*)addr, (void*)(addr+size-1), prot);
addMapMem(addr, addr+size-1);
uintptr_t idx = (addr>>MEMPROT_SHIFT);
uintptr_t end = ((addr+size-1LL)>>MEMPROT_SHIFT);
if(end>=(1LL<<(48-MEMPROT_SHIFT)))
end = (1LL<<(48-MEMPROT_SHIFT))-1;
if(end<idx) // memory addresses higher than 48bits are not tracked
return;
pthread_mutex_lock(&mutex_prot);
for (uintptr_t i=(idx>>16); i<=(end>>16); ++i)
if(memprot[i]==memprot_default) {
uint8_t* newblock = calloc(1<<16, sizeof(uint8_t));
#if 0 //def ARM64 //disabled for now, not usefull with the mutex
if (native_lock_storeifref(&memprot[i], newblock, memprot_default) != newblock) {
free(newblock);
}
#else
memprot[i] = newblock;
#endif
}
for (uintptr_t i=idx; i<=end; ++i) {
const uintptr_t start = i&(MEMPROT_SIZE-1);
const uintptr_t finish = (((i|(MEMPROT_SIZE-1))<end)?(MEMPROT_SIZE-1):end)&(MEMPROT_SIZE-1);
uint8_t* block = memprot[i>>16];
uint8_t* block = kh_value(memprot, k);
for(uintptr_t ii = start; ii<=finish; ++ii) {
uint32_t dyn = block[ii]&PROT_DYNAREC;
if(dyn && (prot&PROT_WRITE)) { // need to remove the write protection from this block
if(oldprot!=prot) {
if(oldprot!=0xff)
mprotect((void*)last, (i<<MEMPROT_SHIFT)-last, oldprot&~PROT_CUSTOM); // need to optimize
last = i<<MEMPROT_SHIFT;
oldprot = prot;
}
} else if(prot!=0xff) {
mprotect((void*)last, (i<<MEMPROT_SHIFT)-last, oldprot&~PROT_CUSTOM); // need to optimize
last = i << MEMPROT_SHIFT;
oldprot = 0xff;
}
block[ii] = prot|dyn|PROT_ALLOC;
}
i+=finish-start; // +1 from the "for" loop
}
if(oldprot!=0xff)
mprotect((void*)last, (end<<MEMPROT_SHIFT)-last, oldprot&~PROT_CUSTOM); // need to optimize
}
void internalSetProtection(uintptr_t addr, size_t size, uint32_t prot)
{
dynarec_log(LOG_DEBUG, "internalSetProtection %p:%p 0x%x\n", (void*)addr, (void*)(addr+size-1), prot);
uintptr_t idx = (addr>>MEMPROT_SHIFT);
uintptr_t end = ((addr+size-1LL)>>MEMPROT_SHIFT);
int ret;
for (uintptr_t i=idx; i<=end; ++i) {
const uint32_t key = (i>>MEMPROT_SHIFT2)&0xffffffff;
khint_t k = kh_put(memprot, memprot, key, &ret);
if(ret) {
uint8_t *m = (uint8_t*)calloc(1, MEMPROT_SIZE);
kh_value(memprot, k) = m;
}
const uintptr_t start = i&(MEMPROT_SIZE-1);
const uintptr_t finish = (((i|(MEMPROT_SIZE-1))<end)?(MEMPROT_SIZE-1):end)&(MEMPROT_SIZE-1);
memset(kh_value(memprot, k)+start, prot|PROT_ALLOC, finish-start+1);
i+=finish-start; // +1 from the "for" loop
}
}
void internalAllocProtection(uintptr_t addr, size_t size, uint32_t prot)
{
dynarec_log(LOG_DEBUG, "internalAllocProtection %p:%p 0x%x\n", (void*)addr, (void*)(addr+size-1), prot);
uintptr_t idx = (addr>>MEMPROT_SHIFT);
uintptr_t end = ((addr+size-1LL)>>MEMPROT_SHIFT);
int ret;
for (uintptr_t i=idx; i<=end; ++i) {
const uint32_t key = (i>>MEMPROT_SHIFT2)&0xffffffff;
khint_t k = kh_put(memprot, memprot, key, &ret);
if(ret) {
uint8_t *m = (uint8_t*)calloc(1, MEMPROT_SIZE);
kh_value(memprot, k) = m;
}
const uintptr_t start = i&(MEMPROT_SIZE-1);
const uintptr_t finish = (((i|(MEMPROT_SIZE-1))<end)?(MEMPROT_SIZE-1):end)&(MEMPROT_SIZE-1);
uint8_t* block = kh_value(memprot, k);
for(uintptr_t ii = start; ii<=finish; ++ii) {
if(!block[ii])
block[ii] = prot;
}
i+=finish-start; // +1 from the "for" loop
}
pthread_mutex_unlock(&mutex_prot);
}
void loadProtectionFromMap()
void internalLoadProtectionFromMap()
{
if(box64_mapclean)
return;
char buf[500];
FILE *f = fopen("/proc/self/maps", "r");
if(!f)
@@ -1053,120 +928,160 @@ void loadProtectionFromMap()
uintptr_t s, e;
if(sscanf(buf, "%lx-%lx %c%c%c", &s, &e, &r, &w, &x)==5) {
int prot = ((r=='r')?PROT_READ:0)|((w=='w')?PROT_WRITE:0)|((x=='x')?PROT_EXEC:0);
allocProtection(s, e-s, prot);
internalAllocProtection(s, e-s, prot);
}
}
fclose(f);
box64_mapclean = 1;
}
static int blockempty(uint8_t* mem)
{
uint32_t *p4 = (uint32_t*)mem;
for (int i=0; i<(MEMPROT_SIZE)/4; ++i, ++p4)
if(*p4)
for (int i=0; i<(MEMPROT_SIZE); ++i)
if(mem[i])
return 0;
return 1;
}
void freeProtection(uintptr_t addr, size_t size)
void internalFreeProtection(uintptr_t addr, size_t size)
{
dynarec_log(LOG_DEBUG, "freeProtection %p:%p\n", (void*)addr, (void*)(addr+size-1));
removeMapMem(addr, addr+size-1);
dynarec_log(LOG_DEBUG, "internalFreeProtection %p:%p\n", (void*)addr, (void*)(addr+size-1));
uintptr_t idx = (addr>>MEMPROT_SHIFT);
uintptr_t end = ((addr+size-1LL)>>MEMPROT_SHIFT);
if(end>=(1LL<<(48-MEMPROT_SHIFT)))
end = (1LL<<(48-MEMPROT_SHIFT))-1;
if(end<idx) // memory addresses higher than 48bits are not tracked
return;
pthread_mutex_lock(&mutex_prot);
for (uintptr_t i=idx; i<=end; ++i) {
const uint32_t key = (i>>16);
if(memprot[key]!=memprot_default) {
const uint32_t key = (i>>MEMPROT_SHIFT2)&0xffffffff;
khint_t k = kh_get(memprot, memprot, key);
if(k!=kh_end(memprot)) {
const uintptr_t start = i&(MEMPROT_SIZE-1);
const uintptr_t finish = (((i|(MEMPROT_SIZE-1))<end)?(MEMPROT_SIZE-1):end)&(MEMPROT_SIZE-1);
uint8_t *block = memprot[key];
uint8_t *block = kh_value(memprot, k);
memset(block+start, 0, finish-start+1);
#if 0 //def ARM64 //disabled for now, not usefull with the mutex
if (blockempty(block)) {
block = (void*)native_lock_xchg(&memprot[key], (uintptr_t)memprot_default);
if(!blockempty(block)) {
block = (void*)native_lock_xchg(&memprot[key], (uintptr_t)block);
for (int i = 0; i < 0x10000; ++i) {
memprot[key][i] |= block[i];
}
}
if (block != memprot_default) free(block);
}
#else
if(blockempty(block)) {
memprot[key] = memprot_default;
free(block);
kh_del(memprot, memprot, k);
}
#endif
i+=finish-start; // +1 from the "for" loop
}
}
pthread_mutex_unlock(&mutex_prot);
}
uint32_t getProtection(uintptr_t addr)
uint32_t internalGetProtection(uintptr_t addr)
{
if(addr>=(1LL<<48))
return 0;
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
uint32_t ret = memprot[idx>>16][idx&0xffff];
const uint32_t key = (addr>>32)&0xffffffff;
khint_t k = kh_get(memprot, memprot, key);
if (k == kh_end(memprot)) return 0;
const uintptr_t idx = ((addr&0xffffffff)>>MEMPROT_SHIFT);
uint32_t ret = kh_val(memprot, k)[idx];
return ret;
}
#define LOWEST (void*)0x10000
void* find32bitBlock(size_t size)
#define LOWEST (void*)0x20000
int availableBlock(uint8_t* p, size_t n)
{
return findBlockNearHint(LOWEST, size);
for (size_t i=0; i<n; ++i, ++p)
if(*p)
return 0;
return 1;
}
void* find47bitBlock(size_t size)
static uintptr_t nextFree(uintptr_t addr)
{
void* ret = find47bitBlockNearHint((void*)0x100000000LL, size);
if(!ret)
ret = find32bitBlock(size);
return ret;
do {
const uint32_t key = (addr>>32)&0xffffffff;
khint_t k = kh_get(memprot, memprot, key);
if(k==kh_end(memprot)) {
return addr;
}
uint8_t *block = kh_value(memprot, k);
for (uintptr_t i=(addr&0xffffffffLL)>>MEMPROT_SHIFT; i<MEMPROT_SIZE; ++i)
if(!block[i]) {
return (addr&~0xffffffffLL)+(i<<MEMPROT_SHIFT);
}
addr += 0x100000000LL;
addr &= ~0xffffffffLL;
} while(1);
}
void* find47bitBlockNearHint(void* hint, size_t size)
static uintptr_t maxFree(uintptr_t addr, uintptr_t sz)
{
mapmem_t* m = mapmem;
uintptr_t h = (uintptr_t)hint;
if(hint<LOWEST) hint = LOWEST;
while(m && m->end<0x800000000000LL) {
// granularity 0x10000
uintptr_t addr = (m->end+1+0xffff)&~0xffff;
uintptr_t end = (m->next)?(m->next->begin-1):0xffffffffffffffffLL;
// check hint and available size
if(addr<=h && end>=h && end-h+1>=size)
return hint;
if(addr>=h && end-addr+1>=size)
uintptr_t mfree = 0;
do {
const uint32_t key = (addr>>32)&0xffffffff;
khint_t k = kh_get(memprot, memprot, key);
if(k==kh_end(memprot)) {
mfree+=0x100000000LL;
if(mfree>sz) {
return addr;
}
} else {
uint8_t *block = kh_value(memprot, k);
for (uintptr_t i=(addr&0xffffffffLL)>>MEMPROT_SHIFT; i<MEMPROT_SIZE; ++i)
if(!block[i]) {
mfree+=1<<MEMPROT_SHIFT;
} else
return mfree;
}
addr += 0x100000000LL;
addr &= ~0xffffffffLL;
} while(1);
}
void* internalFind47bitBlock(size_t size)
{
// slow iterative search... Would need something better one day
uintptr_t addr = 0x100000000LL;
do {
addr = nextFree(addr);
uintptr_t sz = maxFree(addr, size);
if(sz>=size) {
return (void*)addr;
m = m->next;
}
}
addr += sz;
} while(addr<0x800000000000LL);
// search in 32bits as a backup
addr = (uintptr_t)LOWEST;
do {
addr = nextFree(addr);
uintptr_t sz = maxFree(addr, size);
if(sz>=size) {
return (void*)addr;
}
addr += sz;
} while(addr<0x100000000LL);
printf_log(LOG_NONE, "Warning: cannot find a 0x%zx block in 47bits address space\n", size);
return NULL;
}
void* findBlockNearHint(void* hint, size_t size)
void* internalFind47bitBlockNearHint(void* hint, size_t size)
{
mapmem_t* m = mapmem;
uintptr_t h = (uintptr_t)hint;
if(hint<LOWEST) hint = LOWEST;
while(m && m->end<0x100000000LL) {
// granularity 0x10000
uintptr_t addr = (m->end+1+0xffff)&~0xffff;
uintptr_t end = (m->next)?(m->next->begin-1):0xffffffffffffffffLL;
// check hint and available size
if(addr<=h && end>=h && end-h+1>=size)
return hint;
if(addr>=h && end-addr+1>=size)
// slow iterative search... Would need something better one day
uintptr_t addr = (uintptr_t)hint;
do {
addr = nextFree(addr);
uintptr_t sz = maxFree(addr, size);
if(sz>=size) {
return (void*)addr;
m = m->next;
}
return hint;
}
addr += sz;
} while(addr<0x800000000000LL);
printf_log(LOG_NONE, "Warning: cannot find a 0x%zx block in 32bits address space\n", size);
return NULL;
}
void* internalFindBlockNearHint(void* hint, size_t size)
{
// slow iterative search... Would need something better one day
uintptr_t addr = (uintptr_t)hint;
do {
addr = nextFree(addr);
uintptr_t sz = maxFree(addr, size);
if(sz>=size) {
return (void*)addr;
}
addr += sz;
} while(addr<0x100000000LL);
printf_log(LOG_NONE, "Warning: cannot find a 0x%zx block in 32bits address space\n", size);
return NULL;
}
void* internalFind32bitBlock(size_t size)
{
return internalFindBlockNearHint(LOWEST, size);
}
#undef LOWEST
int unlockCustommemMutex()
{
@@ -1178,7 +1093,9 @@ int unlockCustommemMutex()
ret|=(1<<B); \
}
GO(mutex_blocks, 0)
GO(mutex_prot, 1)
#ifdef DYNAREC
GO(mutex_mmap, 2)
#endif
#undef GO
return ret;
}
@@ -1190,7 +1107,9 @@ void relockCustommemMutex(int locks)
pthread_mutex_lock(&A); \
GO(mutex_blocks, 0)
GO(mutex_prot, 1)
#ifdef DYNAREC
GO(mutex_mmap, 2)
#endif
#undef GO
}
@@ -1200,7 +1119,9 @@ static void init_mutexes(void)
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
pthread_mutex_init(&mutex_blocks, &attr);
pthread_mutex_init(&mutex_prot, &attr);
#ifdef DYNAREC
pthread_mutex_init(&mutex_mmap, &attr);
#endif
pthread_mutexattr_destroy(&attr);
}
@@ -1217,30 +1138,22 @@ void init_custommem_helper(box64context_t* ctx)
if(inited) // already initialized
return;
inited = 1;
memset(memprot_default, 0, sizeof(memprot_default));
for(int i=0; i<(1<<20); ++i)
memprot[i] = memprot_default;
memprot = kh_init(memprot);
init_mutexes();
#ifdef DYNAREC
#ifdef ARM64
if(box64_dynarec)
for(int i=0; i<(1<<JMPTABL_SHIFT); ++i) {
box64_jmptbldefault0[i] = (uintptr_t)native_next;
box64_jmptbldefault0[i] = (uintptr_t)arm64_next;
box64_jmptbldefault1[i] = box64_jmptbldefault0;
box64_jmptbldefault2[i] = box64_jmptbldefault1;
box64_jmptbl3[i] = box64_jmptbldefault2;
}
#else
#error Unsupported architecture!
#endif
#endif
pthread_atfork(NULL, NULL, atfork_child_custommem);
// init mapmem list
mapmem = (mapmem_t*)calloc(1, sizeof(mapmem_t));
mapmem->begin = 0x0;
mapmem->end = (uintptr_t)LOWEST - 1;
loadProtectionFromMap();
// check if PageSize is correctly defined
if(box64_pagesize != (1<<MEMPROT_SHIFT)) {
printf_log(LOG_NONE, "Error: PageSize configuation is wrong: configured with %d, but got %d\n", 1<<MEMPROT_SHIFT, box64_pagesize);
exit(-1); // abort or let it continue?
}
}
void fini_custommem_helper(box64context_t *ctx)
@@ -1288,6 +1201,7 @@ void fini_custommem_helper(box64context_t *ctx)
}
free(mmaplist);
pthread_mutex_destroy(&mutex_mmap);
for (int i3=0; i3<(1<<DYNAMAP_SHIFT); ++i3)
if(box64_jmptbl3[i3]!=box64_jmptbldefault2) {
for (int i2=0; i2<(1<<DYNAMAP_SHIFT); ++i2)
@@ -1303,11 +1217,10 @@ void fini_custommem_helper(box64context_t *ctx)
}
#endif
uint8_t* m;
for(int i=0; i<(1<<20); ++i) {
m = memprot[i];
if(m!=memprot_default)
free(m);
}
kh_foreach_value(memprot, m,
free(m);
);
kh_destroy(memprot, memprot);
for(int i=0; i<n_blocks; ++i)
#ifdef USE_MMAP
@@ -1316,11 +1229,5 @@ void fini_custommem_helper(box64context_t *ctx)
free(p_blocks[i].block);
#endif
free(p_blocks);
pthread_mutex_destroy(&mutex_prot);
pthread_mutex_destroy(&mutex_blocks);
while(mapmem) {
mapmem_t *tmp = mapmem;
mapmem = mapmem->next;
free(tmp);
}
}
-858
View File
@@ -1,858 +0,0 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <math.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "tools/bridge_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "emu/x87emu_private.h"
#include "x64trace.h"
#include "signals.h"
#include "dynarec_native.h"
#include "dynarec_arm64_private.h"
#include "dynarec_arm64_functions.h"
#include "custommem.h"
#include "bridge.h"
void arm_fstp(x64emu_t* emu, void* p)
{
if(ST0.q!=STld(0).uref)
D2LD(&ST0.d, p);
else
memcpy(p, &STld(0).ld, 10);
}
void arm_print_armreg(x64emu_t* emu, uintptr_t reg, uintptr_t n)
{
(void)emu;
dynarec_log(LOG_DEBUG, "R%lu=0x%lx (%lu)\n", n, reg, reg);
}
void arm_f2xm1(x64emu_t* emu)
{
ST0.d = exp2(ST0.d) - 1.0;
}
void arm_fyl2x(x64emu_t* emu)
{
ST(1).d = log2(ST0.d)*ST(1).d;
}
void arm_ftan(x64emu_t* emu)
{
ST0.d = tan(ST0.d);
emu->sw.f.F87_C2 = 0;
}
void arm_fpatan(x64emu_t* emu)
{
ST1.d = atan2(ST1.d, ST0.d);
}
void arm_fxtract(x64emu_t* emu)
{
int32_t tmp32s = (ST1.q&0x7ff0000000000000LL)>>52;
tmp32s -= 1023;
ST1.d /= exp2(tmp32s);
ST0.d = tmp32s;
}
void arm_fprem(x64emu_t* emu)
{
int32_t tmp32s = ST0.d / ST1.d;
ST0.d -= ST1.d * tmp32s;
emu->sw.f.F87_C2 = 0;
emu->sw.f.F87_C0 = (tmp32s&1);
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
emu->sw.f.F87_C1 = ((tmp32s>>2)&1);
}
void arm_fyl2xp1(x64emu_t* emu)
{
ST(1).d = log2(ST0.d + 1.0)*ST(1).d;
}
void arm_fsincos(x64emu_t* emu)
{
sincos(ST1.d, &ST1.d, &ST0.d);
emu->sw.f.F87_C2 = 0;
}
void arm_frndint(x64emu_t* emu)
{
ST0.d = fpu_round(emu, ST0.d);
}
void arm_fscale(x64emu_t* emu)
{
if(ST0.d!=0.0)
ST0.d *= exp2(trunc(ST1.d));
}
void arm_fsin(x64emu_t* emu)
{
ST0.d = sin(ST0.d);
emu->sw.f.F87_C2 = 0;
}
void arm_fcos(x64emu_t* emu)
{
ST0.d = cos(ST0.d);
emu->sw.f.F87_C2 = 0;
}
void arm_fbld(x64emu_t* emu, uint8_t* ed)
{
fpu_fbld(emu, ed);
}
void arm_fild64(x64emu_t* emu, int64_t* ed)
{
int64_t tmp;
memcpy(&tmp, ed, sizeof(tmp));
ST0.d = tmp;
STll(0).sq = tmp;
STll(0).sref = ST0.sq;
}
void arm_fbstp(x64emu_t* emu, uint8_t* ed)
{
fpu_fbst(emu, ed);
}
void arm_fistp64(x64emu_t* emu, int64_t* ed)
{
// used of memcpy to avoid aligments issues
if(STll(0).sref==ST(0).sq) {
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))
tmp = 0x8000000000000000LL;
else
tmp = fpu_round(emu, ST0.d);
memcpy(ed, &tmp, sizeof(tmp));
}
}
void arm_fistt64(x64emu_t* emu, int64_t* ed)
{
// used of memcpy to avoid aligments issues
int64_t tmp = ST0.d;
memcpy(ed, &tmp, sizeof(tmp));
}
void arm_fld(x64emu_t* emu, uint8_t* ed)
{
memcpy(&STld(0).ld, ed, 10);
LD2D(&STld(0), &ST(0).d);
STld(0).uref = ST0.q;
}
void arm_ud(x64emu_t* emu)
{
emit_signal(emu, SIGILL, (void*)R_RIP, 0);
}
void arm_fsave(x64emu_t* emu, uint8_t* ed)
{
fpu_savenv(emu, (char*)ed, 0);
uint8_t* p = ed;
p += 28;
for (int i=0; i<8; ++i) {
LD2D(p, &ST(i).d);
p+=10;
}
}
void arm_frstor(x64emu_t* emu, uint8_t* ed)
{
fpu_loadenv(emu, (char*)ed, 0);
uint8_t* p = ed;
p += 28;
for (int i=0; i<8; ++i) {
D2LD(&ST(i).d, p);
p+=10;
}
}
void arm_fprem1(x64emu_t* emu)
{
// simplified version
int32_t tmp32s = round(ST0.d / ST1.d);
ST0.d -= ST1.d*tmp32s;
emu->sw.f.F87_C2 = 0;
emu->sw.f.F87_C0 = (tmp32s&1);
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
emu->sw.f.F87_C1 = ((tmp32s>>2)&1);
}
static uint8_t ff_mult(uint8_t a, uint8_t b)
{
int retval = 0;
for(int i = 0; i < 8; i++) {
if((b & 1) == 1)
retval ^= a;
if((a & 0x80)) {
a <<= 1;
a ^= 0x1b;
} else {
a <<= 1;
}
b >>= 1;
}
return retval;
}
void arm_aesimc(x64emu_t* emu, int xmm)
{
sse_regs_t eax1 = emu->xmm[xmm];
for(int j=0; j<4; ++j) {
emu->xmm[xmm].ub[0+j*4] = ff_mult(0x0E, eax1.ub[0+j*4]) ^ ff_mult(0x0B, eax1.ub[1+j*4]) ^ ff_mult(0x0D, eax1.ub[2+j*4]) ^ ff_mult(0x09, eax1.ub[3+j*4]);
emu->xmm[xmm].ub[1+j*4] = ff_mult(0x09, eax1.ub[0+j*4]) ^ ff_mult(0x0E, eax1.ub[1+j*4]) ^ ff_mult(0x0B, eax1.ub[2+j*4]) ^ ff_mult(0x0D, eax1.ub[3+j*4]);
emu->xmm[xmm].ub[2+j*4] = ff_mult(0x0D, eax1.ub[0+j*4]) ^ ff_mult(0x09, eax1.ub[1+j*4]) ^ ff_mult(0x0E, eax1.ub[2+j*4]) ^ ff_mult(0x0B, eax1.ub[3+j*4]);
emu->xmm[xmm].ub[3+j*4] = ff_mult(0x0B, eax1.ub[0+j*4]) ^ ff_mult(0x0D, eax1.ub[1+j*4]) ^ ff_mult(0x09, eax1.ub[2+j*4]) ^ ff_mult(0x0E, eax1.ub[3+j*4]);
}
}
void arm_aesmc(x64emu_t* emu, int xmm)
{
sse_regs_t eax1 = emu->xmm[xmm];
for(int j=0; j<4; ++j) {
emu->xmm[xmm].ub[0+j*4] = ff_mult(0x02, eax1.ub[0+j*4]) ^ ff_mult(0x03, eax1.ub[1+j*4]) ^ eax1.ub[2+j*4] ^ eax1.ub[3+j*4] ;
emu->xmm[xmm].ub[1+j*4] = eax1.ub[0+j*4] ^ ff_mult(0x02, eax1.ub[1+j*4]) ^ ff_mult(0x03, eax1.ub[2+j*4]) ^ eax1.ub[3+j*4] ;
emu->xmm[xmm].ub[2+j*4] = eax1.ub[0+j*4] ^ eax1.ub[1+j*4] ^ ff_mult(0x02, eax1.ub[2+j*4]) ^ ff_mult(0x03, eax1.ub[3+j*4]);
emu->xmm[xmm].ub[3+j*4] = ff_mult(0x03, eax1.ub[0+j*4]) ^ eax1.ub[1+j*4] ^ eax1.ub[2+j*4] ^ ff_mult(0x02, eax1.ub[3+j*4]);
}
}
void arm_aesdlast(x64emu_t* emu, int xmm)
{
// A0 B1 C2 D3 E4 F5 G6 H7 I8 J9 Ka Lb Mc Nd Oe Pf
// A N K H E B O L I F C P M J G D
const uint8_t invshiftrows[] = {0,13,10, 7, 4, 1,14,11, 8, 5, 2,15,12, 9, 6, 3};
const uint8_t invsubbytes[256] = {
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
};
sse_regs_t eax1;
for(int i=0; i<16; ++i)
eax1.ub[i] = emu->xmm[xmm].ub[invshiftrows[i]];
//STATE ← InvSubBytes( STATE );
for(int i=0; i<16; ++i)
emu->xmm[xmm].ub[i] = invsubbytes[eax1.ub[i]];
}
void arm_aeselast(x64emu_t* emu, int xmm)
{
// A0 B1 C2 D3 E4 F5 G6 H7 I8 J9 Ka Lb Mc Nd Oe Pf
// A F K P E J O D I N C H M B G L
const uint8_t shiftrows[] = {0, 5,10,15, 4, 9,14, 3, 8,13, 2, 7,12, 1, 6,11};
const uint8_t subbytes[256] = {
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
};
sse_regs_t eax1;
for(int i=0; i<16; ++i)
eax1.ub[i] = emu->xmm[xmm].ub[shiftrows[i]];
//STATE ← SubBytes( STATE );
for(int i=0; i<16; ++i)
emu->xmm[xmm].ub[i] = subbytes[eax1.ub[i]];
}
void arm_aesd(x64emu_t* emu, int xmm)
{
arm_aesdlast(emu, xmm);
arm_aesimc(emu, xmm);
}
void arm_aese(x64emu_t* emu, int xmm)
{
arm_aeselast(emu, xmm);
arm_aesmc(emu, xmm);
}
#define XMM0 0
#define XMM8 16
#define X870 8
#define EMM0 8
#define SCRATCH0 24
// Get a FPU scratch reg
int fpu_get_scratch(dynarec_arm_t* dyn)
{
return SCRATCH0 + dyn->n.fpu_scratch++; // return an Sx
}
// Reset scratch regs counter
void fpu_reset_scratch(dynarec_arm_t* dyn)
{
dyn->n.fpu_scratch = 0;
}
// Get a x87 double reg
int fpu_get_reg_x87(dynarec_arm_t* dyn, int t, int n)
{
int i=X870;
while (dyn->n.fpuused[i]) ++i;
dyn->n.fpuused[i] = 1;
dyn->n.neoncache[i].n = n;
dyn->n.neoncache[i].t = t;
dyn->n.news |= (1<<i);
return i; // return a Dx
}
// Free a FPU double reg
void fpu_free_reg(dynarec_arm_t* dyn, int reg)
{
// TODO: check upper limit?
dyn->n.fpuused[reg] = 0;
if(dyn->n.neoncache[reg].t!=NEON_CACHE_ST_F && dyn->n.neoncache[reg].t!=NEON_CACHE_ST_D)
dyn->n.neoncache[reg].v = 0;
}
// Get an MMX double reg
int fpu_get_reg_emm(dynarec_arm_t* dyn, int emm)
{
dyn->n.fpuused[EMM0 + emm] = 1;
dyn->n.neoncache[EMM0 + emm].t = NEON_CACHE_MM;
dyn->n.neoncache[EMM0 + emm].n = emm;
return EMM0 + emm;
}
// Get an XMM quad reg
int fpu_get_reg_xmm(dynarec_arm_t* dyn, int t, int xmm)
{
int i;
if(xmm>7) {
i = XMM8 + xmm - 8;
} else {
i = XMM0 + xmm;
}
dyn->n.fpuused[i] = 1;
dyn->n.neoncache[i].t = t;
dyn->n.neoncache[i].n = xmm;
return i;
}
// Reset fpu regs counter
void fpu_reset_reg(dynarec_arm_t* dyn)
{
dyn->n.fpu_reg = 0;
for (int i=0; i<24; ++i) {
dyn->n.fpuused[i]=0;
dyn->n.neoncache[i].v = 0;
}
}
int neoncache_get_st(dynarec_arm_t* dyn, int ninst, int a)
{
if (dyn->insts[ninst].n.swapped) {
if(dyn->insts[ninst].n.combined1 == a)
a = dyn->insts[ninst].n.combined2;
else if(dyn->insts[ninst].n.combined2 == a)
a = dyn->insts[ninst].n.combined1;
}
for(int i=0; i<24; ++i)
if((dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F
|| dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_D)
&& dyn->insts[ninst].n.neoncache[i].n==a)
return dyn->insts[ninst].n.neoncache[i].t;
// not in the cache yet, so will be fetched...
return NEON_CACHE_ST_D;
}
int neoncache_get_current_st(dynarec_arm_t* dyn, int ninst, int a)
{
(void)ninst;
if(!dyn->insts)
return NEON_CACHE_ST_D;
for(int i=0; i<24; ++i)
if((dyn->n.neoncache[i].t==NEON_CACHE_ST_F
|| dyn->n.neoncache[i].t==NEON_CACHE_ST_D)
&& dyn->n.neoncache[i].n==a)
return dyn->n.neoncache[i].t;
// not in the cache yet, so will be fetched...
return NEON_CACHE_ST_D;
}
int neoncache_get_st_f(dynarec_arm_t* dyn, int ninst, int a)
{
/*if(a+dyn->insts[ninst].n.stack_next-st<0)
// The STx has been pushed at the end of instructon, so stop going back
return -1;*/
for(int i=0; i<24; ++i)
if(dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F
&& dyn->insts[ninst].n.neoncache[i].n==a)
return i;
return -1;
}
int neoncache_get_st_f_noback(dynarec_arm_t* dyn, int ninst, int a)
{
for(int i=0; i<24; ++i)
if(dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F
&& dyn->insts[ninst].n.neoncache[i].n==a)
return i;
return -1;
}
int neoncache_get_current_st_f(dynarec_arm_t* dyn, int a)
{
for(int i=0; i<24; ++i)
if(dyn->n.neoncache[i].t==NEON_CACHE_ST_F
&& dyn->n.neoncache[i].n==a)
return i;
return -1;
}
static void neoncache_promote_double_forward(dynarec_arm_t* dyn, int ninst, int maxinst, int a);
static void neoncache_promote_double_internal(dynarec_arm_t* dyn, int ninst, int maxinst, int a);
static void neoncache_promote_double_combined(dynarec_arm_t* dyn, int ninst, int maxinst, int a)
{
if(a == dyn->insts[ninst].n.combined1 || a == dyn->insts[ninst].n.combined2) {
if(a == dyn->insts[ninst].n.combined1) {
a = dyn->insts[ninst].n.combined2;
} else
a = dyn->insts[ninst].n.combined1;
int i = neoncache_get_st_f_noback(dyn, ninst, a);
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_combined, ninst=%d combined%c %d i=%d (stack:%d/%d)\n", ninst, (a == dyn->insts[ninst].n.combined2)?'2':'1', a ,i, dyn->insts[ninst].n.stack_push, -dyn->insts[ninst].n.stack_pop);
if(i>=0) {
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
if(!dyn->insts[ninst].n.barrier)
neoncache_promote_double_internal(dyn, ninst-1, maxinst, a-dyn->insts[ninst].n.stack_push);
// go forward is combined is not pop'd
if(a-dyn->insts[ninst].n.stack_pop>=0)
if(!dyn->insts[ninst+1].n.barrier)
neoncache_promote_double_forward(dyn, ninst+1, maxinst, a-dyn->insts[ninst].n.stack_pop);
}
}
}
static void neoncache_promote_double_internal(dynarec_arm_t* dyn, int ninst, int maxinst, int a)
{
if(dyn->insts[ninst+1].n.barrier)
return;
while(ninst>=0) {
a+=dyn->insts[ninst].n.stack_pop; // adjust Stack depth: add pop'd ST (going backward)
int i = neoncache_get_st_f(dyn, ninst, a);
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d, a=%d st=%d:%d, i=%d\n", ninst, a, dyn->insts[ninst].n.stack, dyn->insts[ninst].n.stack_next, i);
if(i<0) return;
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
// check combined propagation too
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) {
if(dyn->insts[ninst].n.swapped) {
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d swapped %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
if (a==dyn->insts[ninst].n.combined1)
a = dyn->insts[ninst].n.combined2;
else if (a==dyn->insts[ninst].n.combined2)
a = dyn->insts[ninst].n.combined1;
} else {
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d combined %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
neoncache_promote_double_combined(dyn, ninst, maxinst, a);
}
}
a-=dyn->insts[ninst].n.stack_push; // // adjust Stack depth: remove push'd ST (going backward)
--ninst;
if(ninst<0 || a<0 || dyn->insts[ninst].n.barrier)
return;
}
}
static void neoncache_promote_double_forward(dynarec_arm_t* dyn, int ninst, int maxinst, int a)
{
while((ninst!=-1) && (ninst<maxinst) && (a>=0)) {
a+=dyn->insts[ninst].n.stack_push; // // adjust Stack depth: add push'd ST (going forward)
if((dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) && dyn->insts[ninst].n.swapped) {
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d swapped %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
if (a==dyn->insts[ninst].n.combined1)
a = dyn->insts[ninst].n.combined2;
else if (a==dyn->insts[ninst].n.combined2)
a = dyn->insts[ninst].n.combined1;
}
int i = neoncache_get_st_f_noback(dyn, ninst, a);
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d, a=%d st=%d:%d(%d/%d), i=%d\n", ninst, a, dyn->insts[ninst].n.stack, dyn->insts[ninst].n.stack_next, dyn->insts[ninst].n.stack_push, -dyn->insts[ninst].n.stack_pop, i);
if(i<0) return;
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
// check combined propagation too
if((dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) && !dyn->insts[ninst].n.swapped) {
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d combined %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
neoncache_promote_double_combined(dyn, ninst, maxinst, a);
}
a-=dyn->insts[ninst].n.stack_pop; // adjust Stack depth: remove pop'd ST (going forward)
if(dyn->insts[ninst].x64.has_next && !dyn->insts[ninst].n.barrier)
++ninst;
else
ninst=-1;
}
if(ninst==maxinst)
neoncache_promote_double(dyn, ninst, a);
}
void neoncache_promote_double(dynarec_arm_t* dyn, int ninst, int a)
{
int i = neoncache_get_current_st_f(dyn, a);
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d a=%d st=%d i=%d\n", ninst, a, dyn->n.stack, i);
if(i<0) return;
dyn->n.neoncache[i].t = NEON_CACHE_ST_D;
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
// check combined propagation too
if(dyn->n.combined1 || dyn->n.combined2) {
if(dyn->n.swapped) {
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d swapped! %d/%d vs %d\n", ninst, dyn->n.combined1 ,dyn->n.combined2, a);
if(dyn->n.combined1 == a)
a = dyn->n.combined2;
else if(dyn->n.combined2 == a)
a = dyn->n.combined1;
} else {
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d combined! %d/%d vs %d\n", ninst, dyn->n.combined1 ,dyn->n.combined2, a);
if(dyn->n.combined1 == a)
neoncache_promote_double(dyn, ninst, dyn->n.combined2);
else if(dyn->n.combined2 == a)
neoncache_promote_double(dyn, ninst, dyn->n.combined1);
}
}
a-=dyn->insts[ninst].n.stack_push; // // adjust Stack depth: remove push'd ST (going backward)
if(!ninst || a<0) return;
neoncache_promote_double_internal(dyn, ninst-1, ninst, a);
}
int neoncache_combine_st(dynarec_arm_t* dyn, int ninst, int a, int b)
{
dyn->n.combined1=a;
dyn->n.combined2=b;
if( neoncache_get_current_st(dyn, ninst, a)==NEON_CACHE_ST_F
&& neoncache_get_current_st(dyn, ninst, b)==NEON_CACHE_ST_F )
return NEON_CACHE_ST_F;
return NEON_CACHE_ST_D;
}
int isPred(dynarec_arm_t* dyn, int ninst, int pred) {
for(int i=0; i<dyn->insts[ninst].pred_sz; ++i)
if(dyn->insts[ninst].pred[i]==pred)
return pred;
return -1;
}
int getNominalPred(dynarec_arm_t* dyn, int ninst) {
if((ninst<=0) || !dyn->insts[ninst].pred_sz)
return -1;
if(isPred(dyn, ninst, ninst-1)!=-1)
return ninst-1;
return dyn->insts[ninst].pred[0];
}
int isCacheEmpty(dynarec_arm_t* dyn, int ninst) {
if(dyn->insts[ninst].n.stack_next) {
return 0;
}
for(int i=0; i<24; ++i)
if(dyn->insts[ninst].n.neoncache[i].v) { // there is something at ninst for i
if(!(
(dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F || dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_D)
&& dyn->insts[ninst].n.neoncache[i].n<dyn->insts[ninst].n.stack_pop))
return 0;
}
return 1;
}
int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
int i2 = dyn->insts[ninst].x64.jmp_insts;
if(i2<0)
return 1;
if((dyn->insts[i2].x64.barrier&BARRIER_FLOAT))
// if the barrier as already been apply, no transform needed
return ((dyn->insts[ninst].x64.barrier&BARRIER_FLOAT))?0:(isCacheEmpty(dyn, ninst)?0:1);
int ret = 0;
if(!i2) { // just purge
if(dyn->insts[ninst].n.stack_next) {
return 1;
}
for(int i=0; i<24 && !ret; ++i)
if(dyn->insts[ninst].n.neoncache[i].v) { // there is something at ninst for i
if(!(
(dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F || dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_D)
&& dyn->insts[ninst].n.neoncache[i].n<dyn->insts[ninst].n.stack_pop))
ret = 1;
}
return ret;
}
// Check if ninst can be compatible to i2
if(dyn->insts[ninst].n.stack_next != dyn->insts[i2].n.stack-dyn->insts[i2].n.stack_push) {
return 1;
}
neoncache_t cache_i2 = dyn->insts[i2].n;
neoncacheUnwind(&cache_i2);
for(int i=0; i<24; ++i) {
if(dyn->insts[ninst].n.neoncache[i].v) { // there is something at ninst for i
if(!cache_i2.neoncache[i].v) { // but there is nothing at i2 for i
ret = 1;
} else if(dyn->insts[ninst].n.neoncache[i].v!=cache_i2.neoncache[i].v) { // there is something different
if(dyn->insts[ninst].n.neoncache[i].n!=cache_i2.neoncache[i].n) { // not the same x64 reg
ret = 1;
}
else if(dyn->insts[ninst].n.neoncache[i].t == NEON_CACHE_XMMR && cache_i2.neoncache[i].t == NEON_CACHE_XMMW)
{/* nothing */ }
else
ret = 1;
}
} else if(cache_i2.neoncache[i].v)
ret = 1;
}
return ret;
}
void neoncacheUnwind(neoncache_t* cache)
{
if(cache->swapped) {
// unswap
int a = -1;
int b = -1;
for(int j=0; j<24 && ((a==-1) || (b==-1)); ++j)
if((cache->neoncache[j].t == NEON_CACHE_ST_D || cache->neoncache[j].t == NEON_CACHE_ST_F)) {
if(cache->neoncache[j].n == cache->combined1)
a = j;
else if(cache->neoncache[j].n == cache->combined2)
b = j;
}
if(a!=-1 && b!=-1) {
int tmp = cache->neoncache[a].n;
cache->neoncache[a].n = cache->neoncache[b].n;
cache->neoncache[b].n = tmp;
}
cache->swapped = 0;
cache->combined1 = cache->combined2 = 0;
}
if(cache->news) {
// reove the newly created neoncache
for(int i=0; i<24; ++i)
if(cache->news&(1<<i))
cache->neoncache[i].v = 0;
cache->news = 0;
}
if(cache->stack_push) {
// unpush
for(int j=0; j<24; ++j) {
if((cache->neoncache[j].t == NEON_CACHE_ST_D || cache->neoncache[j].t == NEON_CACHE_ST_F)) {
if(cache->neoncache[j].n<cache->stack_push)
cache->neoncache[j].v = 0;
else
cache->neoncache[j].n-=cache->stack_push;
}
}
cache->x87stack-=cache->stack_push;
cache->stack-=cache->stack_push;
cache->stack_push = 0;
}
cache->x87stack+=cache->stack_pop;
cache->stack_next = cache->stack;
cache->stack_pop = 0;
cache->barrier = 0;
// And now, rebuild the x87cache info with neoncache
cache->mmxcount = 0;
cache->fpu_scratch = 0;
cache->fpu_extra_qscratch = 0;
cache->fpu_reg = 0;
for(int i=0; i<8; ++i) {
cache->x87cache[i] = -1;
cache->mmxcache[i] = -1;
cache->x87reg[i] = 0;
cache->ssecache[i*2].v = -1;
cache->ssecache[i*2+1].v = -1;
}
int x87reg = 0;
for(int i=0; i<24; ++i) {
if(cache->neoncache[i].v) {
cache->fpuused[i] = 1;
switch (cache->neoncache[i].t) {
case NEON_CACHE_MM:
cache->mmxcache[cache->neoncache[i].n] = i;
++cache->mmxcount;
++cache->fpu_reg;
break;
case NEON_CACHE_XMMR:
case NEON_CACHE_XMMW:
cache->ssecache[cache->neoncache[i].n].reg = i;
cache->ssecache[cache->neoncache[i].n].write = (cache->neoncache[i].t==NEON_CACHE_XMMW)?1:0;
++cache->fpu_reg;
break;
case NEON_CACHE_ST_F:
case NEON_CACHE_ST_D:
cache->x87cache[x87reg] = cache->neoncache[i].n;
cache->x87reg[x87reg] = i;
++x87reg;
++cache->fpu_reg;
break;
case NEON_CACHE_SCR:
cache->fpuused[i] = 0;
cache->neoncache[i].v = 0;
break;
}
} else {
cache->fpuused[i] = 0;
}
}
}
#define F8 *(uint8_t*)(addr++)
#define F32 *(uint32_t*)(addr+=4, addr-4)
#define F32S64 (uint64_t)(int64_t)*(int32_t*)(addr+=4, addr-4)
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity, int delta)
{
(void)dyn; (void)ninst;
uint32_t tested = (1<<parity)-1;
if((nextop&0xC0)==0xC0)
return 0; // direct register, no parity...
if(!(nextop&0xC0)) {
if((nextop&7)==4) {
uint8_t sib = F8;
int sib_reg = (sib>>3)&7;
if((sib&0x7)==5) {
uint64_t tmp = F32S64;
if (sib_reg!=4) {
// if XXXXXX+reg<<N then check parity of XXXXX and N should be enough
return ((tmp&tested)==0 && (sib>>6)>=parity)?1:0;
} else {
// just a constant...
return (tmp&tested)?0:1;
}
} else {
if(sib_reg==4 && parity<3)
return 0; // simple [reg]
// don't try [reg1 + reg2<<N], unless reg1 is ESP
return ((sib&0x7)==4 && (sib>>6)>=parity)?1:0;
}
} else if((nextop&7)==5) {
uint64_t tmp = F32S64;
tmp+=addr+delta;
return (tmp&tested)?0:1;
} else {
return 0;
}
} else {
return 0; //Form [reg1 + reg2<<N + XXXXXX]
}
}
// Do the GETED, but don't emit anything...
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop)
{
(void)dyn; (void)addr; (void)ninst;
if((nextop&0xC0)==0xC0)
return addr;
if(!(nextop&0xC0)) {
if((nextop&7)==4) {
uint8_t sib = F8;
if((sib&0x7)==5) {
addr+=4;
}
} else if((nextop&7)==5) {
addr+=4;
}
} else {
if((nextop&7)==4) {
++addr;
}
if(nextop&0x80) {
addr+=4;
} else {
++addr;
}
}
return addr;
}
#undef F8
#undef F32
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn)
{
(void)dyn;
#define PK(a) *(uint8_t*)(addr+a)
#define PK32(a) *(int32_t*)(addr+a)
if(!addr || !getProtection(addr))
return 0;
if(PK(0)==0xff && PK(1)==0x25) { // "absolute" jump, maybe the GOT (well, RIP relative in fact)
uintptr_t a1 = addr + 6 + (PK32(2)); // need to add a check to see if the address is from the GOT !
addr = (uintptr_t)getAlternate(*(void**)a1);
}
if(!addr || !getProtection(addr))
return 0;
onebridge_t *b = (onebridge_t*)(addr);
if(b->CC==0xCC && b->S=='S' && b->C=='C' && b->w!=(wrapper_t)0 && b->f!=(uintptr_t)PltResolver) {
// found !
if(retn) *retn = (b->C3==0xC2)?b->N:0;
if(calladdress) *calladdress = addr+1;
return 1;
}
return 0;
#undef PK32
#undef PK
}
const char* getCacheName(int t, int n)
{
static char buff[20];
switch(t) {
case NEON_CACHE_ST_D: sprintf(buff, "ST%d", n); break;
case NEON_CACHE_ST_F: sprintf(buff, "st%d", n); break;
case NEON_CACHE_MM: sprintf(buff, "MM%d", n); break;
case NEON_CACHE_XMMW: sprintf(buff, "XMM%d", n); break;
case NEON_CACHE_XMMR: sprintf(buff, "xmm%d", n); break;
case NEON_CACHE_SCR: sprintf(buff, "Scratch"); break;
case NEON_CACHE_NONE: buff[0]='\0'; break;
}
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].x64.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;
}
-54
View File
@@ -1,54 +0,0 @@
#define INIT uintptr_t sav_addr=addr
#define FINI \
dyn->isize = addr-sav_addr; \
dyn->insts[ninst].x64.addr = addr; \
if(ninst) dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr
#define MESSAGE(A, ...)
#define READFLAGS(A) \
dyn->insts[ninst].x64.use_flags = A; dyn->f.dfnone = 1;\
dyn->f.pending=SF_SET
#define SETFLAGS(A,B) \
dyn->insts[ninst].x64.set_flags = A; \
if(B!=SF_MAYSET) { \
dyn->insts[ninst].x64.state_flags = B; \
dyn->f.pending=(B)&SF_SET_PENDING; \
dyn->f.dfnone=((B)&SF_SET)?1:0; \
}
#define EMIT(A)
#define JUMP(A, C) add_next(dyn, (uintptr_t)A); dyn->insts[ninst].x64.jmp = A; dyn->insts[ninst].x64.jmp_cond = C
#define BARRIER(A) if(A!=BARRIER_MAYBE) {fpu_purgecache(dyn, ninst, 0, x1, x2, x3); dyn->insts[ninst].x64.barrier = A;} else dyn->insts[ninst].barrier_maybe = 1
#define BARRIER_NEXT(A) dyn->insts[ninst+1].x64.barrier = A
#define NEW_INST \
++dyn->size; \
if(dyn->size+3>=dyn->cap) { \
dyn->insts = (instruction_native_t*)realloc(dyn->insts, sizeof(instruction_native_t)*dyn->cap*2); \
memset(&dyn->insts[dyn->cap], 0, sizeof(instruction_native_t)*dyn->cap); \
dyn->cap *= 2; \
} \
dyn->insts[ninst].x64.addr = ip; \
dyn->n.combined1 = dyn->n.combined2 = 0;\
dyn->n.swapped = 0; dyn->n.barrier = 0; \
dyn->insts[ninst].f_entry = dyn->f; \
if(ninst) {dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr;}
#define INST_EPILOG \
dyn->insts[ninst].f_exit = dyn->f; \
dyn->insts[ninst].n = dyn->n; \
dyn->insts[ninst].x64.has_next = (ok>0)?1:0;
#define INST_NAME(name)
#define DEFAULT \
--dyn->size; \
*ok = -1; \
if(box64_dynarec_log>=LOG_INFO) {\
dynarec_log(LOG_NONE, "%p: Dynarec stopped because of Opcode %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", \
(void*)ip, PKip(0), \
PKip(1), PKip(2), PKip(3), \
PKip(4), PKip(5), PKip(6), \
PKip(7), PKip(8), PKip(9), \
PKip(10),PKip(11),PKip(12), \
PKip(13),PKip(14)); \
printFunctionAddr(ip, " => "); \
dynarec_log(LOG_NONE, "\n"); \
}
-14
View File
@@ -1,14 +0,0 @@
#define INIT
#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;\
dyn->n.swapped = 0; dyn->n.barrier = 0
#define INST_EPILOG \
dyn->insts[ninst].n = dyn->n; \
dyn->insts[ninst].f_exit = dyn->f
#define INST_NAME(name)
-17
View File
@@ -1,17 +0,0 @@
#define INIT dyn->native_size = 0
#define FINI if(ninst) {dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size);}
#define MESSAGE(A, ...)
#define EMIT(A) dyn->insts[ninst].size+=4; dyn->native_size+=4
#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->last_ip = 0; \
++dyn->sons_size; \
} \
}
#define INST_EPILOG dyn->insts[ninst].epilog = dyn->native_size;
#define INST_NAME(name)
#define TABLE64(A, V) {Table64(dyn, (V)); EMIT(0);}
#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q); EMIT(0);}
-65
View File
@@ -1,65 +0,0 @@
#define INIT
#define FINI
#define EMIT(A) \
if(box64_dynarec_dump) {dynarec_log(LOG_NONE, "\t%08x\t%s\n", (uint32_t)(A), arm64_print(A, (uintptr_t)dyn->block));} \
*(uint32_t*)(dyn->block) = (uint32_t)(A); \
dyn->block += 4; dyn->native_size += 4; \
dyn->insts[ninst].size2 += 4
#define MESSAGE(A, ...) if(box64_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__)
#define NEW_INST \
if(ninst && isInstClean(dyn, ninst)) { \
dyn->last_ip = 0; \
dyn->sons_x64[dyn->sons_size] = (uintptr_t)ip; \
dyn->sons_native[dyn->sons_size] = dyn->block; \
MESSAGE(LOG_DUMP, "----> potential Son here %p/%p\n", (void*)ip, dyn->block); \
++dyn->sons_size; \
}
#define INST_EPILOG
#define INST_NAME(name) \
if(box64_dynarec_dump) {\
printf_x64_instruction(my_context->dec, &dyn->insts[ninst].x64, name); \
dynarec_log(LOG_NONE, "%s%p: %d emited opcodes, inst=%d, barrier=%d state=%d/%d(%d), set=%X, use=%X, need=%X", \
(box64_dynarec_dump>1)?"\e[32m":"", \
(void*)(dyn->native_start+dyn->insts[ninst].address), \
dyn->insts[ninst].size/4, \
ninst, \
dyn->insts[ninst].x64.barrier, \
dyn->insts[ninst].x64.state_flags, \
dyn->f.pending, \
dyn->f.dfnone, \
dyn->insts[ninst].x64.set_flags, \
dyn->insts[ninst].x64.use_flags, \
dyn->insts[ninst].x64.need_flags); \
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].x64.jmp && dyn->insts[ninst].x64.jmp_insts>=0)\
dynarec_log(LOG_NONE, ", jmp=%d", dyn->insts[ninst].x64.jmp_insts);\
if(dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts==-1)\
dynarec_log(LOG_NONE, ", jmp=out"); \
if(dyn->last_ip) \
dynarec_log(LOG_NONE, ", last_ip=%p", (void*)dyn->last_ip);\
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, 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, 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, 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, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break; \
case NEON_CACHE_XMMR: dynarec_log(LOG_NONE, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break; \
case NEON_CACHE_SCR: dynarec_log(LOG_NONE, " D%d:%s", ii, 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", (box64_dynarec_dump>1)?"\e[m":""); \
}
#define TABLE64(A, V) {int val64offset = Table64(dyn, (V)); MESSAGE(LOG_DUMP, " Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset);}
#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q); MESSAGE(LOG_DUMP, " FTable64: %g\n", v.d); VLDR64_literal(A, val64offset);}
-124
View File
@@ -1,124 +0,0 @@
#ifndef __DYNAREC_ARM_PRIVATE_H_
#define __DYNAREC_ARM_PRIVATE_H_
#include "../dynarec_private.h"
typedef struct x64emu_s x64emu_t;
typedef struct dynablock_s dynablock_t;
#define BARRIER_MAYBE 8
#define NEON_CACHE_NONE 0
#define NEON_CACHE_ST_D 1
#define NEON_CACHE_ST_F 2
#define NEON_CACHE_MM 3
#define NEON_CACHE_XMMW 4
#define NEON_CACHE_XMMR 5
#define NEON_CACHE_SCR 6
typedef union neon_cache_s {
int8_t v;
struct {
unsigned int t:4; // reg type
unsigned int n:4; // reg number
};
} neon_cache_t;
typedef union sse_cache_s {
int8_t v;
struct {
unsigned int reg:7;
unsigned int write:1;
};
} sse_cache_t;
typedef struct neoncache_s {
// Neon cache
neon_cache_t neoncache[24];
int8_t stack;
int8_t stack_next;
int8_t stack_pop;
int8_t stack_push;
uint8_t combined1;
uint8_t combined2;
uint8_t swapped; // the combined reg were swapped
uint8_t barrier; // is there a barrier at instruction epilog?
uint32_t news; // bitmask, wich neoncache are new for this opcode
// fpu cache
int8_t x87cache[8]; // cache status for the 8 x87 register behind the fpu stack
int8_t x87reg[8]; // reg used for x87cache entry
int8_t mmxcache[8]; // cache status for the 8 MMX registers
sse_cache_t ssecache[16]; // cache status for the 16 SSE(2) registers
int8_t fpuused[24]; // all 0..24 double reg from fpu, used by x87, sse and mmx
int8_t x87stack; // cache stack counter
int8_t mmxcount; // number of mmx register used (not both mmx and x87 at the same time)
int8_t fpu_scratch; // scratch counter
int8_t fpu_extra_qscratch; // some opcode need an extra quad scratch register
int8_t fpu_reg; // x87/sse/mmx reg counter
} neoncache_t;
typedef struct flagcache_s {
int pending; // is there a pending flags here, or to check?
int dfnone; // if defered flags is already set to df_none
} flagcache_t;
typedef struct instruction_arm64_s {
instruction_x64_t x64;
uintptr_t address; // (start) address of the arm emited instruction
uintptr_t epilog; // epilog of current instruction (can be start of next, or barrier stuff)
int size; // size of the arm emited instruction
int size2; // size of the arm emited instrucion after pass2
int pred_sz; // size of predecessor list
int *pred; // predecessor array
uintptr_t mark, mark2, mark3;
uintptr_t markf;
uintptr_t markseg;
uintptr_t marklock;
int pass2choice;// value for choices that are fixed on pass2 for pass3
uintptr_t natcall;
int retn;
int barrier_maybe;
flagcache_t f_exit; // flags status at end of intruction
neoncache_t n; // neoncache at end of intruction (but before poping)
flagcache_t f_entry; // flags status before the instruction begin
} instruction_arm64_t;
typedef struct dynarec_arm_s {
instruction_arm64_t *insts;
int32_t size;
int32_t cap;
uintptr_t start; // start of the block
uint32_t isize; // size in byte of x64 instructions included
void* block; // memory pointer where next instruction is emited
uintptr_t native_start; // start of the arm code
size_t native_size; // size of emitted arm code
uintptr_t last_ip; // last set IP in RIP (or NULL if unclean state) TODO: move to a cache something
uint64_t *table64; // table of 64bits value
int table64size;// size of table (will be appended at end of executable code)
int table64cap;
uintptr_t tablestart;
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_x64; // the x64 address of potential dynablock sons
void** sons_native; // 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;
} dynarec_arm_t;
void add_next(dynarec_arm_t *dyn, uintptr_t addr);
uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr);
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n);
int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n);
int Table64(dynarec_arm_t *dyn, uint64_t val); // add a value to etable64 (if needed) and gives back the imm19 to use in LDR_literal
#define GO_TRACE() \
GETIP_(ip); \
MOVx_REG(x1, xRIP); \
STORE_XEMU_CALL(xRIP); \
MOV32w(x2, 1); \
CALL(PrintTrace, -1); \
LOAD_XEMU_CALL(xRIP)
#endif //__DYNAREC_ARM_PRIVATE_H_
@@ -194,10 +194,6 @@
#define SBCSw_REG(Rd, Rn, Rm) EMIT(ADDSUBC_gen(0, 1, 1, Rm, Rn, Rd))
#define SBCSxw_REG(Rd, Rn, Rm) EMIT(ADDSUBC_gen(rex.w, 1, 1, Rm, Rn, Rd))
// ADR
#define ADR_gen(immlo, immhi, Rd) ((immlo)<<29 | 0b10000<<24 | (immhi)<<5 | (Rd))
#define ADR_S20(Rd, imm) EMIT(ADR_gen((imm)&3, ((imm)>>2)&0x7ffff, (Rd))
// LDR
#define LDR_gen(size, op1, imm9, op2, Rn, Rt) ((size)<<30 | 0b111<<27 | (op1)<<24 | 0b01<<22 | (imm9)<<12 | (op2)<<10 | (Rn)<<5 | (Rt))
#define LDRx_S9_postindex(Rt, Rn, imm9) EMIT(LDR_gen(0b11, 0b00, (imm9)&0x1ff, 0b01, Rn, Rt))
@@ -355,9 +351,6 @@
#define PST_L1_STREAM_U12(Rn, imm12) EMIT(PRFM_imm(((imm12)>>3)&0xfff, Rn, 0b01001))
// Data Memory Barrier
#define DMB_gen(CRm) (0b1101010100<<22 | 0b011<<16 | 0b0011<<12 | (CRm)<<8 | 1<<7 | 0b01<<5 | 0b11111)
#define DMB_ISH() EMIT(DMB_gen(0b1011))
// BR and Branches
#define BR_gen(Z, op, A, M, Rn, Rm) (0b1101011<<25 | (Z)<<24 | (op)<<21 | 0b11111<<16 | (A)<<11 | (M)<<10 | (Rn)<<5 | (Rm))
@@ -1319,15 +1312,6 @@
#define VUZP1Q_64(Rt, Rn, Rm) EMIT(UZP_gen(1, 0b11, Rm, 0, Rn, Rt))
#define VUZP2Q_64(Rt, Rn, Rm) EMIT(UZP_gen(1, 0b11, Rm, 1, Rn, Rt))
#define DUP_gen(Q, imm5, Rn, Rd) ((Q)<<30 | 0b01110000<<21 | (imm5)<<16 | 1<<10 | (Rn)<<5 | (Rd))
#define VDUP_8(Vd, Vn, idx) EMIT(DUP_gen(0, ((idx)<<1|1), Vn, Vd))
#define VDUPQ_8(Vd, Vn, idx) EMIT(DUP_gen(1, ((idx)<<1|1), Vn, Vd))
#define VDUP_16(Vd, Vn, idx) EMIT(DUP_gen(0, ((idx)<<2|0b10), Vn, Vd))
#define VDUPQ_16(Vd, Vn, idx) EMIT(DUP_gen(1, ((idx)<<2|0b10), Vn, Vd))
#define VDUP_32(Vd, Vn, idx) EMIT(DUP_gen(0, ((idx)<<3|0b100), Vn, Vd))
#define VDUPQ_32(Vd, Vn, idx) EMIT(DUP_gen(1, ((idx)<<3|0b100), Vn, Vd))
#define VDUPQ_64(Vd, Vn, idx) EMIT(DUP_gen(1, ((idx)<<4|0b1000), Vn, Vd))
// TBL
#define TBL_gen(Q, Rm, len, op, Rn, Rd) ((Q)<<30 | 0b001110<<24 | (Rm)<<16 | (len)<<13 | (op)<<12 | (Rn)<<5 | (Rd))
//Use Rm[] to pick from Rn element and store in Rd. Out-of-range element gets 0
@@ -1467,35 +1451,18 @@
// Vector Float CMP
// EQual
#define FCMP_vector(Q, U, E, sz, Rm, ac, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | (E)<<23 | (sz)<<22 | 1<<21 | (Rm)<<16 | 0b1110<<12 | (ac)<<11 | 1<<10 | (Rn)<<5 | (Rd))
#define VFCMEQQD(Rd, Rn, Rm) EMIT(FCMP_vector(1, 0, 0, 1, Rm, 0, Rn, Rd))
#define VFCMEQQS(Rd, Rn, Rm) EMIT(FCMP_vector(1, 0, 0, 0, Rm, 0, Rn, Rd))
#define FCMEQQD(Rd, Rn, Rm) EMIT(FCMP_vector(1, 0, 0, 1, Rm, 0, Rn, Rd))
#define FCMEQQS(Rd, Rn, Rm) EMIT(FCMP_vector(1, 0, 0, 0, Rm, 0, Rn, Rd))
// Greater or Equal
#define VFCMGEQD(Rd, Rn, Rm) EMIT(FCMP_vector(1, 1, 0, 1, Rm, 0, Rn, Rd))
#define VFCMGEQS(Rd, Rn, Rm) EMIT(FCMP_vector(1, 1, 0, 0, Rm, 0, Rn, Rd))
#define VFCMGEQD_ABS(Rd, Rn, Rm) EMIT(FCMP_vector(1, 1, 0, 1, Rm, 1, Rn, Rd))
#define VFCMGEQS_ABS(Rd, Rn, Rm) EMIT(FCMP_vector(1, 1, 0, 0, Rm, 1, Rn, Rd))
#define FCMGEQD(Rd, Rn, Rm) EMIT(FCMP_vector(1, 1, 0, 1, Rm, 0, Rn, Rd))
#define FCMGEQS(Rd, Rn, Rm) EMIT(FCMP_vector(1, 1, 0, 0, Rm, 0, Rn, Rd))
#define FCMGEQD_ABS(Rd, Rn, Rm) EMIT(FCMP_vector(1, 1, 0, 1, Rm, 1, Rn, Rd))
#define FCMGEQS_ABS(Rd, Rn, Rm) EMIT(FCMP_vector(1, 1, 0, 0, Rm, 1, Rn, Rd))
// Greater Than
#define VFCMGTQD(Rd, Rn, Rm) EMIT(FCMP_vector(1, 1, 1, 1, Rm, 0, Rn, Rd))
#define VFCMGTQS(Rd, Rn, Rm) EMIT(FCMP_vector(1, 1, 1, 0, Rm, 0, Rn, Rd))
#define VFCMGTQD_ABS(Rd, Rn, Rm) EMIT(FCMP_vector(1, 1, 1, 1, Rm, 1, Rn, Rd))
#define VFCMGTQS_ABS(Rd, Rn, Rm) EMIT(FCMP_vector(1, 1, 1, 0, Rm, 1, Rn, Rd))
// Scalar Float CMP to 0
#define FCMP_0_scalar(U, sz, op, Rn, Rd) (0b01<<30 | (U)<<29| 0b11110<<24 | 1<<23 | (sz)<<22 | 0b10000<<17 | 0b011<<14 | (op)<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
// Less or equal to 0
#define FCMLES_0(Rd, Rn) EMIT(FCMP_0_scalar(1, 0, 0b01, (Rn), (Rd)))
#define FCMLED_0(Rd, Rn) EMIT(FCMP_0_scalar(1, 1, 0b01, (Rn), (Rd)))
// Greater than 0
#define FCMGTS_0(Rd, Rn) EMIT(FCMP_0_scalar(0, 0, 0b00, (Rn), (Rd)))
#define FCMGTD_0(Rd, Rn) EMIT(FCMP_0_scalar(0, 1, 0b00, (Rn), (Rd)))
// Less than 0
#define FCMLTS_0(Rd, Rn) EMIT(FCMP_0_scalar(0, 0, 0b10, (Rn), (Rd)))
#define FCMLTD_0(Rd, Rn) EMIT(FCMP_0_scalar(0, 1, 0b10, (Rn), (Rd)))
// Scalar Float CMP
#define FCMP_op_scalar(U, E, sz, Rm, ac, Rn, Rd) (0b01<<30 | (U)<<29 | 0b11110<<24 | (E)<<23 | (sz)<<22 | 1<<21 | (Rm)<<16 | 0b1110<<12 | (ac)<<11 | 1<<10 | (Rn)<<5 | (Rd))
#define FCMEQS(Rd, Rn, Rm) EMIT(FCMP_op_scalar(0, 0, 0, (Rm), 0, (Rn), (Rd)))
#define FCMEQD(Rd, Rn, Rm) EMIT(FCMP_op_scalar(0, 0, 1, (Rm), 0, (Rn), (Rd)))
#define FCMGTQD(Rd, Rn, Rm) EMIT(FCMP_vector(1, 1, 1, 1, Rm, 0, Rn, Rd))
#define FCMGTQS(Rd, Rn, Rm) EMIT(FCMP_vector(1, 1, 1, 0, Rm, 0, Rn, Rd))
#define FCMGTQD_ABS(Rd, Rn, Rm) EMIT(FCMP_vector(1, 1, 1, 1, Rm, 1, Rn, Rd))
#define FCMGTQS_ABS(Rd, Rn, Rm) EMIT(FCMP_vector(1, 1, 1, 0, Rm, 1, Rn, Rd))
// UMULL / SMULL
#define MULL_vector(Q, U, size, Rm, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | (size)<<22 | 1<<21 | (Rm)<<16 | 0b1100<<12 |(Rn)<<5 |(Rd))
File renamed without changes.
@@ -21,7 +21,6 @@
arm64_lock_read_b:
dmb ish
// address is x0, return is x0
ldaxrb w0, [x0]
ret
@@ -30,11 +29,9 @@ arm64_lock_write_b:
// address is x0, value is x1, return is x0
mov x2, x0
stlxrb w0, w1, [x2]
dmb ish
ret
arm64_lock_read_h:
dmb ish
// address is x0, return is x0
ldaxrh w0, [x0]
ret
@@ -43,11 +40,9 @@ arm64_lock_write_h:
// address is x0, value is x1, return is x0
mov x2, x0
stlxrh w0, w1, [x2]
dmb ish
ret
arm64_lock_read_d:
dmb ish
// address is x0, return is x0
ldaxr w0, [x0]
ret
@@ -56,11 +51,9 @@ arm64_lock_write_d:
// address is x0, value is w1, return is x0
mov x2, x0
stlxr w0, w1, [x2]
dmb ish
ret
arm64_lock_read_dd:
dmb ish
// address is x0, return is x0
ldaxr x0, [x0]
ret
@@ -69,11 +62,9 @@ arm64_lock_write_dd:
// address is x0, value is x1, return is x0
mov x2, x0
stlxr w0, x1, [x2]
dmb ish
ret
arm64_lock_read_dq:
dmb ish
// address is r2, return is r0, r1
ldaxp x4, x3, [x2]
str x4, [x0]
@@ -85,47 +76,37 @@ arm64_lock_write_dq:
// r0 needs to be aligned
stlxp w3, x0, x1, [x2]
mov w0, w3
dmb ish
ret
arm64_lock_xchg:
dmb ish
arm64_lock_xchg_0:
// address is x0, value is x1, return old value in x0
ldaxr x2, [x0]
stlxr w3, x1, [x0]
cbnz w3, arm64_lock_xchg_0
dmb ish
cbnz w3, arm64_lock_xchg
mov x0, x2
ret
arm64_lock_storeifnull:
dmb ish
arm64_lock_storeifnull_0:
// address is x0, value is x1, x1 store to x0 only if [x0] is 0. return new [x0] value (so x1 or old value)
// address is x0, value is x1, x1 store to x0 only if [x0] is 0, return new [x0] value (so x1 or old value)
ldaxr x2, [x0]
cbnz x2, arm64_lock_storeifnull_exit
mov x2, x1
stlxr w3, x2, [x0]
cbnz w3, arm64_lock_storeifnull_0
cbnz w3, arm64_lock_storeifnull
arm64_lock_storeifnull_exit:
dmb ish
mov x0, x2
ret
arm64_lock_storeifref:
dmb ish
arm64_lock_storeifref_0:
// address is x0, value is x1, x1 store to x0 only if [x0] is x3. return new [x0] value (so x1 or old value)
// address is x0, value is x1, x1 store to x0 only if [x0] is x2, return new [x0] value (so x1 or old value)
ldaxr x3, [x0]
cmp x2, x3
bne arm64_lock_storeifref_exit
stlxr w4, x1, [x0]
cbnz w4, arm64_lock_storeifref_0
cbnz w4, arm64_lock_storeifref
mov x0, x1
ret
arm64_lock_storeifref_exit:
dmb ish
mov x0, x3
ret
@@ -27,13 +27,13 @@ extern void arm64_lock_read_dq(uint64_t * a, uint64_t* b, void* addr);
// STLXRD of ADDR, return 0 if ok, 1 if not
extern int arm64_lock_write_dq(uint64_t a, uint64_t b, void* addr);
// Atomicaly exchange value at [p] with val, return old p
// Atomically exchange value at [p] with val, return old p
extern uintptr_t arm64_lock_xchg(void* p, uintptr_t val);
// Atomicaly store value to [p] only if [p] is NULL. Return new [p] value (so val or old)
extern void* arm64_lock_storeifnull(void*p, void* val);
// Atomically store val to [p] only if [p] is 0. Return new [p] value (so val or old)
extern uint64_t arm64_lock_storeifnull(void* p, uint64_t val);
// Atomicaly store value to [p] only if [p] is ref. Return new [p] value (so val or old)
extern void* arm64_lock_storeifref(void*p, void* val, void* ref);
// Atomically store val to [p] only if [p] is ref. Return new [p] value (so val or old)
extern uint64_t arm64_lock_storeifref(void* p, uint64_t val, uint64_t ref);
#endif //__ARM64_LOCK__H__
#endif //__ARM64_LOCK__H__
File renamed without changes.
@@ -236,15 +236,6 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
snprintf(buff, sizeof(buff), "STR %s, [%s, %s, %s %d]", (size==2)?Wt[Rt]:Xt[Rt], XtSp[Rn], ((option&1)==0)?Wt[Rm]:Xt[Rm], extend[option], amount);
return buff;
}
if(isMask(opcode, "00111000001mmmmmoooS10nnnnnttttt", &a)) {
const char* extend[] = {"?0", "?1", "UXTW", "LSL", "?4", "?5", "SXTW", "SXTX"};
int amount = a.S;
if(option==3 && !amount)
snprintf(buff, sizeof(buff), "STRB %s, [%s, %s]", Wt[Rt], XtSp[Rn], ((option&1)==0)?Wt[Rm]:Xt[Rm]);
else
snprintf(buff, sizeof(buff), "STRB %s, [%s, %s, %s %d]", Wt[Rt], XtSp[Rn], ((option&1)==0)?Wt[Rm]:Xt[Rm], extend[option], amount);
return buff;
}
if(isMask(opcode, "0x111000010iiiiiiiii01nnnnnttttt", &a)) {
int size = a.x;
int offset = signExtend(imm, 9);
@@ -939,12 +930,6 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
return buff;
}
// ADR
if(isMask(opcode, "0ss10000iiiiiiiiiiiiiiiiiiiddddd", &a)) {
snprintf(buff, sizeof(buff), "ADR, %s, %ld", Xt[Rd], signExtend((imm)<<2|(imms), 20));
return buff;
}
// LDR / STR
if(isMask(opcode, "ss111101cciiiiiiiiiiiinnnnnttttt", &a)) {
char s = '?';
@@ -1051,7 +1036,7 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
//FMIN/FMAX
if(isMask(opcode, "00011110ff1mmmmm01oo10nnnnnddddd", &a)) {
char s = (sf==0)?'S':((sf==1)?'D':'?');
snprintf(buff, sizeof(buff), "F%s %c%d, %c%d, %c%d", (option==3)?"MINNM":((option==2)?"MAXNM":((!option)?"MAX":"MIN")), s, Rd, s, Rn, s, Rm);
snprintf(buff, sizeof(buff), "F%s %c%d, %c%d, %c%d", (option==3)?"MINNM":((option==2)?"MINNMP":((!option)?"MAXNM":"MAXNMP")), s, Rd, s, Rn, s, Rm);
return buff;
}
if(isMask(opcode, "0Q001110of1mmmmm110001nnnnnddddd", &a)) {
@@ -1326,21 +1311,6 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
snprintf(buff, sizeof(buff), "%cSHLL%s V%d.%s, V%d.%s, #%d", a.U?'U':'S', a.Q?"2":"", Rd, Va, Rn, Vd, sh);
return buff;
}
// DUP
if(isMask(opcode, "0Q001110000iiiii000001nnnnnddddd", &a)) {
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "2D", "??"};
const char* Z[] = {"B", "H", "S", "D"};
int sz = 3;
if((imm&0b0001)==0b0001) sz=0;
else if((imm&0b0011)==0b0010) sz=1;
else if((imm&0b0111)==0b0100) sz=2;
int sh=imm - (1<<sz);
const char* Vd = Y[(sz<<1)|a.Q];
const char* Vn = Z[sz];
snprintf(buff, sizeof(buff), "DUP V%d.%s, V%d.%s[%d]", Rd, Vd, Rn, Vn, sh);
return buff;
}
// AES
if(isMask(opcode, "0100111000101000010f10nnnnnddddd", &a)) {
@@ -1351,12 +1321,8 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
snprintf(buff, sizeof(buff), "AES%sMC V%d.16B, V%d.16B", sf?"I":"", Rd, Rn);
return buff;
}
// DMB ISH
if(isMask(opcode, "11010101000000110011nnnn10111111", &a)) {
snprintf(buff, sizeof(buff), "DMB %s", (Rn==0b1011)?"ISH":"???");
}
snprintf(buff, sizeof(buff), "%08X ???", __builtin_bswap32(opcode));
return buff;
}
}
File renamed without changes.
File renamed without changes.
+64 -182
View File
@@ -19,10 +19,12 @@
#include "dynablock_private.h"
#include "dynarec_private.h"
#include "elfloader.h"
#include "dynarec_native.h"
#include "native_lock.h"
#ifdef ARM64
#include "dynarec_arm64.h"
#include "arm64_lock.h"
#else
#error Unsupported architecture!
#endif
#include "custommem.h"
#include "khash.h"
@@ -46,8 +48,6 @@ dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct)
dynablocklist_t* ret = (dynablocklist_t*)calloc(1, sizeof(dynablocklist_t));
ret->text = text;
ret->textsz = textsz;
ret->minstart = text;
ret->maxend = text+textsz-1;
if(direct && textsz) {
ret->direct = (dynablock_t**)calloc(textsz, sizeof(dynablock_t*));
if(!ret->direct) {printf_log(LOG_NONE, "Warning, fail to create direct block for dynablock @%p\n", (void*)text);}
@@ -56,14 +56,12 @@ dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct)
return ret;
}
void FreeDynablock(dynablock_t* db, int need_lock)
void FreeDynablock(dynablock_t* db)
{
if(db) {
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x64=%p:%p parent=%p, father=%p, with %d son(s) already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size, db->parent, db->father, db->sons_size, db->gone);
if(db->gone)
return; // already in the process of deletion!
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x64=%p:%p parent=%p, father=%p, with %d son(s) already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->parent, db->father, db->sons_size, db->gone);
if(need_lock)
pthread_mutex_lock(&my_context->mutex_dyndump);
db->done = 0;
db->gone = 1;
// remove from direct if there
@@ -72,25 +70,25 @@ void FreeDynablock(dynablock_t* db, int need_lock)
if(db->parent->direct) {
uintptr_t addr = (uintptr_t)db->x64_addr;
if(addr>=startdb && addr<enddb)
native_lock_xchg(&db->parent->direct[addr-startdb], 0); // secured write
arm64_lock_xchg(&db->parent->direct[addr-startdb], 0); // secured write
}
// remove jumptable
setJumpTableDefault64(db->x64_addr);
// remove and free the sons
for (int i=0; i<db->sons_size; ++i) {
dynablock_t *son = (dynablock_t*)native_lock_xchg(&db->sons[i], 0);
FreeDynablock(son, 0);
dynablock_t *son = (dynablock_t*)arm64_lock_xchg(&db->sons[i], 0);
FreeDynablock(son);
}
// only the father free the DynarecMap
if(!db->father) {
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->block, db->size);
pthread_mutex_lock(&my_context->mutex_dyndump);
FreeDynarecMap(db, (uintptr_t)db->block, db->size);
free(db->sons);
free(db->instsize);
}
free(db);
if(need_lock)
pthread_mutex_unlock(&my_context->mutex_dyndump);
}
free(db->sons);
free(db->instsize);
free(db);
}
}
@@ -104,7 +102,7 @@ void FreeDynablockList(dynablocklist_t** dynablocks)
if((*dynablocks)->direct) {
for (int i=0; i<(*dynablocks)->textsz; ++i) {
if((*dynablocks)->direct[i] && !(*dynablocks)->direct[i]->father)
FreeDynablock((*dynablocks)->direct[i], 1);
FreeDynablock((*dynablocks)->direct[i]);
}
free((*dynablocks)->direct);
}
@@ -121,8 +119,7 @@ void MarkDynablock(dynablock_t* db)
db = db->father; // mark only father
if(db->need_test)
return; // already done
dynarec_log(LOG_DEBUG, "MarkDynablock %p with %d son(s) %p-%p\n", db, db->sons_size, db->x64_addr, db->x64_addr+db->x64_size-1);
db->need_test = 1;
db->need_test = 1; // test only blocks that can be marked (and so deleted)
setJumpTableDefault64(db->x64_addr);
for(int i=0; i<db->sons_size; ++i)
setJumpTableDefault64(db->sons[i]->x64_addr);
@@ -151,19 +148,24 @@ int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2, uintp
void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
{
// Mark will try to find *any* blocks that intersect the range to mark
if(!dynablocks)
return;
if(!dynablocks->direct)
return;
uintptr_t startdb = dynablocks->text;
uintptr_t sizedb = dynablocks->textsz;
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;
dynarec_log(LOG_DEBUG, "MarkDirectDynablock %p-%p .. startdb=%p, sizedb=%p\n", (void*)addr, (void*)addr+size-1, (void*)startdb, (void*)sizedb);
for(uintptr_t i = 0; i<sizedb; ++i)
if((db=dynablocks->direct[i]))
if(IntervalIntersects((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr+db->x64_size-1, addr, addr+size+1))
MarkDynablock(db);
if(end>startdb && start<enddb)
for(uintptr_t i = start; i<end; ++i)
if((db=dynablocks->direct[i-startdb]))
if(IntervalIntersects((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr+db->x64_size-1, addr, addr+size+1))
MarkDynablock(db);
}
int FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
@@ -187,7 +189,7 @@ int FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t si
end = enddb;
if(end>startdb && start<enddb)
for(uintptr_t i = start; i<end; ++i) {
db = (dynablock_t*)native_lock_xchg(&dynablocks->direct[i-startdb], 0);
db = (dynablock_t*)arm64_lock_xchg(&dynablocks->direct[i-startdb], 0);
if(db) {
if(db->father)
db = db->father;
@@ -199,7 +201,7 @@ int FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t si
}
// purge the list
kh_foreach_value(blocks, db,
FreeDynablock(db, 1);
FreeDynablock(db);
);
kh_destroy(dynablocks, blocks);
// check emptyness
@@ -214,14 +216,13 @@ void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t s
{
if(!dynablocks)
return;
dynarec_log(LOG_DEBUG, "MarkRangeDynablock %p-%p\n", (void*)addr, (void*)addr+size-1);
if(dynablocks->direct) {
uintptr_t new_addr = dynablocks->minstart;
uintptr_t new_size = dynablocks->maxend - new_addr + 1;
MarkDirectDynablock(dynablocks, addr, size);
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(unsigned idx=(new_addr)>>DYNAMAP_SHIFT; idx<(addr>>DYNAMAP_SHIFT); ++idx)
MarkDirectDynablock(getDB(idx), addr, size);
MarkDirectDynablock(getDB(idx), new_addr, new_size);
}
}
@@ -269,10 +270,9 @@ dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* c
if (!*created)
return block;
pthread_mutex_lock(&my_context->mutex_dyndump);
if(!dynablocks->direct) {
dynablock_t** p = (dynablock_t**)calloc(dynablocks->textsz, sizeof(dynablock_t*));
if(native_lock_storeifnull(&dynablocks->direct, p)!=p)
if(arm64_lock_storeifnull(&dynablocks->direct, (uint64_t)p) != (uint64_t)p)
free(p); // someone already create the direct array, too late...
}
@@ -281,17 +281,15 @@ dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* c
block = (dynablock_t*)calloc(1, sizeof(dynablock_t));
block->parent = dynablocks;
dynablock_t* tmp = (dynablock_t*)native_lock_storeifnull(&dynablocks->direct[addr-dynablocks->text], block);
dynablock_t* tmp = (dynablock_t*)arm64_lock_storeifnull(&dynablocks->direct[addr-dynablocks->text], (uint64_t)block);
if(tmp != block) {
// a block appeard!
pthread_mutex_unlock(&my_context->mutex_dyndump);
free(block);
*created = 0;
return tmp;
}
*created = 1;
pthread_mutex_lock(&my_context->mutex_dyndump);
return block;
}
@@ -307,7 +305,7 @@ void cancelFillBlock()
return NULL if block is not found / cannot be created.
Don't create if create==0
*/
static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, dynablock_t* current, int need_lock)
static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, dynablock_t* current)
{
// try the quickest way first: get parent of current and check if ok!
dynablocklist_t *dynablocks = NULL;
@@ -338,41 +336,37 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
// fill the block
block->x64_addr = (void*)addr;
if(need_lock)
pthread_mutex_lock(&my_context->mutex_dyndump);
pthread_mutex_lock(&my_context->mutex_dyndump);
if(sigsetjmp(&dynarec_jmpbuf, 1)) {
printf_log(LOG_INFO, "FillBlock at %p triggered a segfault, cancelling\n", (void*)addr);
if(need_lock)
pthread_mutex_unlock(&my_context->mutex_dyndump);
return NULL;
}
void* ret = FillBlock64(block, filladdr);
if(need_lock)
pthread_mutex_unlock(&my_context->mutex_dyndump);
pthread_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*)native_lock_storeifref(&dynablocks->direct[addr-dynablocks->text], 0, block);
if(old!=block && old) {// put it back in place, strange things are happening here!
void* old = (void*)arm64_lock_storeifref(&dynablocks->direct[addr-dynablocks->text], 0, (uint64_t)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 be writen
// doing nothing else, the block has not been written
}
free(block);
block = NULL;
}
// check size
if(block && block->x64_size) {
if(dynablocks->minstart>addr)
dynablocks->minstart = addr;
int blocksz = block->x64_size;
if(dynablocks->maxend<addr+blocksz) {
dynablocks->maxend = addr+blocksz;
for(unsigned idx=(addr>>DYNAMAP_SHIFT)+1; idx<=((addr+blocksz-1)>>DYNAMAP_SHIFT); ++idx) {
if(dynablocks->maxsz<blocksz) {
dynablocks->maxsz = blocksz;
for(unsigned idx=(addr>>DYNAMAP_SHIFT)+1; idx<=((addr+blocksz)>>DYNAMAP_SHIFT); ++idx) {
dynablocklist_t* dblist;
if((dblist = getDB(idx)))
if(dblist->minstart>addr)
dblist->minstart = addr;
if(dblist->maxsz<blocksz)
dblist->maxsz = blocksz;
}
}
protectDB((uintptr_t)block->x64_addr, block->x64_size);
// fill-in jumptable
addJumpTableIfDefault64(block->x64_addr, block->block);
for(int i=0; i<block->sons_size; ++i) {
@@ -382,142 +376,34 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
block->done = 1;
}
dynarec_log(LOG_DEBUG, "%04d| --- DynaRec Block %s @%p:%p (%p, 0x%x bytes, with %d son(s))\n", GetTID(), created?"created":"recycled", (void*)addr, (void*)(addr+((block)?block->x64_size:1)-1), (block)?block->block:0, (block)?block->size:0, (block)?block->sons_size:0);
dynarec_log(LOG_DEBUG, " --- DynaRec Block %s @%p:%p (%p, 0x%x bytes, with %d son(s))\n", created?"created":"recycled", (void*)addr, (void*)(addr+((block)?block->x64_size:0)), (block)?block->block:0, (block)?block->size:0, (block)?block->sons_size:0);
return block;
}
#define MAX_HOTPAGE 64
#define HOTPAGE_STEP 64
static int volatile hotpage_count[MAX_HOTPAGE] = {0};
static uintptr_t volatile hotpage[MAX_HOTPAGE] = {0};
static uintptr_t volatile hotpage_size[MAX_HOTPAGE] = {0};
static volatile int hotpages = 0;
int IsInHotPage(uintptr_t addr) {
if(!hotpages)
return 0;
for(int i=0; i<MAX_HOTPAGE; ++i) {
if((hotpage_count[i]>0) && (addr>=hotpage[i]) && (addr<hotpage[i]+0x1000*(hotpage_size[i]+1))) {
--hotpage_count[i];
if(!hotpage_count[i]) {
--hotpages;
hotpage_size[i] = 0;
dynarec_log(LOG_DEBUG, "End of Hotpage %p\n", (void*)hotpage[i]);
}
__sync_synchronize();
return 1;
}
}
return 0;
}
int AreaInHotPage(uintptr_t start, uintptr_t end) {
if(!hotpages)
return 0;
for(int i=0; i<MAX_HOTPAGE; ++i) {
if(hotpage_count[i]>0)
if(IntervalIntersects(start, end, hotpage[i], hotpage[i]+0x1000*(hotpage_size[i]+1)-1)) {
--hotpage_count[i];
if(!hotpage_count[i]) {
--hotpages;
hotpage_size[i] = 0;
dynarec_log(LOG_DEBUG, "End of Hotpage %p\n", (void*)hotpage[i]);
}
return 1;
}
}
return 0;
}
void AddHotPage(uintptr_t addr) {
addr&=~0xfff;
// look for same address
for(int i=0; i<MAX_HOTPAGE; ++i) {
if(addr>=hotpage[i] && addr<hotpage[i]+0x1000*(hotpage_size[i]+1)) {
if(!hotpage_count[i])
++hotpages;
hotpage_count[i] = HOTPAGE_STEP;
__sync_synchronize();
return;
}
if(addr==hotpage[i]+0x1000*(hotpage_size[i]+1)) {
++hotpage_size[i];
hotpage_count[i] = HOTPAGE_STEP;
__sync_synchronize();
return;
}
if(addr+0x1000==hotpage[i]) {
++hotpage_size[i];
hotpage[i] = addr;
hotpage_count[i] = HOTPAGE_STEP;
__sync_synchronize();
return;
}
}
// look for empty spot / minium
int mincnt = hotpage_count[0];
int minidx = 0;
for(int i=1; i<MAX_HOTPAGE; ++i)
if(hotpage_count[i]<mincnt) {
mincnt = hotpage_count[i];
minidx = i;
}
if(hotpage_count[minidx]) {
static int cnt = 0;
if(cnt<50) {
dynarec_log(LOG_NONE, "Warning, not enough Hotpage, replacing %p(%p/%d) with %p\n", (void*)hotpage[minidx], (void*)(0x1000*(hotpage_size[minidx]+1)), hotpage_count[minidx], (void*)addr);
++cnt;
if(cnt==50) // stop spamming console with message...
dynarec_log(LOG_NONE, " will stop warning about not enough Hotpage now\n");
}
hotpage_size[minidx] = 0;
} else
++hotpages;
hotpage[minidx] = addr;
hotpage_count[minidx] = HOTPAGE_STEP;
__sync_synchronize();
}
dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, dynablock_t** current)
{
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, *current, 1);
dynablock_t *father = (db && db->father)?db->father:db;
if(father && father->done && db->block && father->need_test) {
if(pthread_mutex_trylock(&my_context->mutex_dyndump)) {
dynarec_log(LOG_DEBUG, "mutex_dyndump not available when trying to validate block %p from %p:%p (hash:%X) with %d son(s) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, db->hash, db->sons_size, (void*)addr);
return NULL;
}
if(AreaInHotPage((uintptr_t)father->x64_addr, (uintptr_t)father->x64_addr + father->x64_size - 1)) {
dynarec_log(LOG_DEBUG, "Not running block %p from %p:%p with %d son(s) for %p because it's in a hotpage\n", father, father->x64_addr, father->x64_addr+father->x64_size-1, father->sons_size, (void*)addr);
pthread_mutex_unlock(&my_context->mutex_dyndump);
return NULL;
}
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, *current);
if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
dynablock_t *father = db->father?db->father:db;
uint32_t hash = X31_hash_code(father->x64_addr, father->x64_size);
if(hash!=father->hash) {
father->done = 0; // invalidating the block
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x64_addr, father->x64_addr+father->x64_size-1, hash, father->hash, father->sons_size, (void*)addr);
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x64_addr, father->x64_addr+father->x64_size, hash, father->hash, father->sons_size, (void*)addr);
// no more current if it gets invalidated too
if(*current && IntervalIntersects(
(uintptr_t)father->x64_addr,
(uintptr_t)father->x64_addr+father->x64_size-1,
(uintptr_t)(*current)->x64_addr,
(uintptr_t)(*current)->x64_addr+(*current)->x64_size-1))
if(*current && father->x64_addr>=(*current)->x64_addr && (father->x64_addr+father->x64_size)<(*current)->x64_addr)
*current = NULL;
// Free father, it's now invalid!
FreeDynablock(father, 0);
FreeDynablock(father);
// start again... (will create a new block)
db = internalDBGetBlock(emu, addr, addr, create, *current, 0);
db = internalDBGetBlock(emu, addr, addr, create, *current);
} else {
father->need_test = 0;
dynarec_log(LOG_DEBUG, "Validating block %p from %p:%p (hash:%X) with %d son(s) for %p\n", father, father->x64_addr, father->x64_addr+father->x64_size-1, father->hash, father->sons_size, (void*)addr);
protectDB((uintptr_t)father->x64_addr, father->x64_size);
// fill back jumptable
addJumpTableIfDefault64(father->x64_addr, father->block);
for(int i=0; i<father->sons_size; ++i)
addJumpTableIfDefault64(father->sons[i]->x64_addr, father->sons[i]->block);
}
pthread_mutex_unlock(&my_context->mutex_dyndump);
}
return db;
}
@@ -526,19 +412,16 @@ dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr)
{
dynarec_log(LOG_DEBUG, "Creating AlternateBlock at %p for %p\n", (void*)addr, (void*)filladdr);
int create = 1;
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, NULL, 1);
dynablock_t *father = (db && db->father)?db->father:db;
if(father && father->done && db->block && father->need_test) {
if(pthread_mutex_trylock(&my_context->mutex_dyndump))
return NULL;
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, NULL);
if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
dynablock_t *father = db->father?db->father:db;
uint32_t hash = X31_hash_code(father->x64_addr, father->x64_size);
if(hash!=father->hash) {
father->done = 0; // invalidating the block
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x64_addr, father->x64_addr+father->x64_size, hash, father->hash, father->sons_size, (void*)addr);
// Free father, it's now invalid!
FreeDynablock(father, 0);
FreeDynablock(father);
// start again... (will create a new block)
db = internalDBGetBlock(emu, addr, filladdr, create, NULL, 0);
db = internalDBGetBlock(emu, addr, filladdr, create, NULL);
} else {
father->need_test = 0;
protectDB((uintptr_t)father->x64_addr, father->x64_size);
@@ -547,7 +430,6 @@ dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr)
for(int i=0; i<father->sons_size; ++i)
addJumpTableIfDefault64(father->sons[i]->x64_addr, father->sons[i]->block);
}
pthread_mutex_unlock(&my_context->mutex_dyndump);
}
return db;
}
+1 -2
View File
@@ -29,8 +29,7 @@ typedef struct dynablock_s {
typedef struct dynablocklist_s {
uintptr_t text;
int textsz;
uintptr_t maxend; // max address end for anyblock on this blocklist
uintptr_t minstart; // min start address for block overlapping this blocklist
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;
+21 -28
View File
@@ -26,15 +26,7 @@
#ifdef ARM64
void arm64_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
void arm64_epilog() EXPORTDYN;
#define native_prolog arm64_prolog
#define native_epilog arm64_epilog
#elif defined(LA464)
void la464_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
void la464_epilog() EXPORTDYN;
#define native_prolog la464_prolog
#define native_epilog la464_epilog
#else
#error Unsupported architecture
void arm64_epilog_fast() EXPORTDYN;
#endif
#endif
@@ -55,29 +47,30 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
if(!block) {
// no block, let link table as is...
if(hasAlternate((void*)addr)) {
printf_log(LOG_DEBUG, "Jmp address has alternate: %p", (void*)addr);
printf_log(LOG_INFO, "Jmp address has alternate: %p", (void*)addr);
addr = (uintptr_t)getAlternate((void*)addr); // set new address
R_RIP = addr; // but also new RIP!
*x3 = addr; // and the RIP in x27 register
printf_log(LOG_DEBUG, " -> %p\n", (void*)addr);
printf_log(LOG_INFO, " -> %p\n", (void*)addr);
block = DBGetBlock(emu, addr, 1, &current);
}
if(!block) {
#ifdef HAVE_TRACE
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
dynarec_log(LOG_INFO, "Warning, jumping to a no-block address %p from %p (db=%p, x64addr=%p)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL);
printf_log(LOG_INFO, "Warning, jumping to a no-block address %p from %p (db=%p, x64addr=%p)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL);
#endif
//tableupdate(native_epilog, addr, table);
return native_epilog;
//tableupdate(arm64_epilog, addr, table);
return arm64_epilog;
}
}
if(!block->done) {
// not finished yet... leave linker
return native_epilog;
//tableupdate(arm_linker, addr, table);
return arm64_epilog;
}
if(!(jblock=block->block)) {
// null block, but done: go to epilog, no linker here
return native_epilog;
return arm64_epilog;
}
//dynablock_t *father = block->father?block->father:block;
return jblock;
@@ -121,23 +114,23 @@ void DynaCall(x64emu_t* emu, uintptr_t addr)
PushExit(emu);
R_RIP = addr;
emu->df = d_none;
dynablock_t* block = NULL;
dynablock_t* current = NULL;
dynablock_t* block = DBGetBlock(emu, R_RIP, 1, &current);
current = block;
while(!emu->quit) {
block = DBGetBlock(emu, R_RIP, 1, &current);
current = block;
if(!block || !block->block || !block->done) {
// 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_RIP, emu);
Run(emu, 1);
block = DBGetBlock(emu, R_RIP, 1, &current);
current = block;
} else {
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x64 instructions (father=%p) emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize ,block->father, emu);
CHECK_FLAGS(emu);
// block is here, let's run it!
native_prolog(emu, block->block);
block = NULL;
#ifdef ARM64
arm64_prolog(emu, block->block);
#endif
}
if(emu->fork) {
int forktype = emu->fork;
@@ -201,22 +194,22 @@ int DynaRun(x64emu_t* emu)
return Run(emu, 0);
#ifdef DYNAREC
else {
dynablock_t* block = NULL;
dynablock_t* current = NULL;
dynablock_t* block = DBGetBlock(emu, R_RIP, 1, &current);;
current = block;
while(!emu->quit) {
block = DBGetBlock(emu, R_RIP, 1, &current);
current = block;
if(!block || !block->block || !block->done) {
// 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_RIP, emu);
Run(emu, 1);
block = DBGetBlock(emu, R_RIP, 1, &current);
current = block;
} else {
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x64 insts (father=%p) emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize, block->father, emu);
// block is here, let's run it!
native_prolog(emu, block->block);
block = NULL;
#ifdef ARM64
arm64_prolog(emu, block->block);
#endif
}
if(emu->fork) {
int forktype = emu->fork;
-25
View File
@@ -1,25 +0,0 @@
#ifndef __DYNAREC_ARCH__H_
#define __DYNAREC_ARCH__H_
#ifdef ARM64
#include "arm64/arm64_printer.h"
#include "arm64/dynarec_arm64_private.h"
#include "arm64/dynarec_arm64_functions.h"
#define instruction_native_t instruction_arm64_t
#define dynarec_native_t dynarec_arm_t
#elif defined(LA464)
#include "la464/la464_printer.h"
#include "la464/dynarec_la464_private.h"
#include "la464/dynarec_la464_functions.h"
#define instruction_native_t instruction_la464_t
#define dynarec_native_t dynarec_la464_t
#else
#error Unsupported platform
#endif
#endif //__DYNAREC_ARCH__H_
@@ -3,7 +3,6 @@
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include "debug.h"
#include "box64context.h"
@@ -19,11 +18,11 @@
#include "x64trace.h"
#include "dynablock.h"
#include "dynablock_private.h"
#include "dynarec_arm64.h"
#include "dynarec_arm64_private.h"
#include "dynarec_arm64_functions.h"
#include "elfloader.h"
#include "dynarec_native.h"
#include "dynarec_arch.h"
void printf_x64_instruction(zydis_dec_t* dec, instruction_x64_t* inst, const char* name) {
uint8_t *ip = (uint8_t*)inst->addr;
if(ip[0]==0xcc && ip[1]=='S' && ip[2]=='C') {
@@ -58,19 +57,17 @@ void printf_x64_instruction(zydis_dec_t* dec, instruction_x64_t* inst, const cha
}
}
void add_next(dynarec_native_t *dyn, uintptr_t addr) {
if(!box64_dynarec_bigblock)
return;
for(int i=0; i<dyn->next_sz; ++i)
if(dyn->next[i]==addr)
return;
void add_next(dynarec_arm_t *dyn, uintptr_t addr) {
if(dyn->next_sz == dyn->next_cap) {
dyn->next_cap += 16;
dyn->next = (uintptr_t*)realloc(dyn->next, dyn->next_cap*sizeof(uintptr_t));
}
for(int i=0; i<dyn->next_sz; ++i)
if(dyn->next[i]==addr)
return;
dyn->next[dyn->next_sz++] = addr;
}
uintptr_t get_closest_next(dynarec_native_t *dyn, uintptr_t addr) {
uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr) {
// get closest, but no addresses befores
uintptr_t best = 0;
int i = 0;
@@ -87,7 +84,7 @@ uintptr_t get_closest_next(dynarec_native_t *dyn, uintptr_t addr) {
return best;
}
#define PK(A) (*((uint8_t*)(addr+(A))))
int is_nops(dynarec_native_t *dyn, uintptr_t addr, int n)
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n)
{
if(!n)
return 1;
@@ -118,7 +115,7 @@ int is_nops(dynarec_native_t *dyn, uintptr_t addr, int n)
// return size of next instuciton, -1 is unknown
// not all instrction are setup
int next_instruction(dynarec_native_t *dyn, uintptr_t addr)
int next_instruction(dynarec_arm_t *dyn, uintptr_t addr)
{
uint8_t opcode = PK(0);
uint8_t nextop;
@@ -221,7 +218,7 @@ int next_instruction(dynarec_native_t *dyn, uintptr_t addr)
}
#undef PK
int is_instructions(dynarec_native_t *dyn, uintptr_t addr, int n)
int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n)
{
int i = 0;
while(i<n) {
@@ -232,14 +229,61 @@ int is_instructions(dynarec_native_t *dyn, uintptr_t addr, int n)
return (i==n)?1:0;
}
instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x64_size, int native_size)
uint32_t needed_flags(dynarec_arm_t *dyn, int ninst, uint32_t setf, int recurse)
{
if(recurse == 10)
return X_PEND;
if(ninst == dyn->size)
return X_PEND; // no more instructions, or too many jmp loop, stop
uint32_t needed = dyn->insts[ninst].x64.use_flags;
if(needed) {
setf &= ~needed;
if(!setf) // all flags already used, no need to continue
return needed;
}
if(!needed && !dyn->insts[ninst].x64.set_flags && !dyn->insts[ninst].x64.jmp_insts) {
int start = ninst;
int end = ninst;
while(end<dyn->size && !dyn->insts[end].x64.use_flags && !dyn->insts[end].x64.set_flags && !dyn->insts[end].x64.jmp_insts)
++end;
needed = needed_flags(dyn, end, setf, recurse);
for(int i=start; i<end; ++i)
dyn->insts[i].x64.need_flags = needed;
return needed;
}
if(dyn->insts[ninst].x64.set_flags && (dyn->insts[ninst].x64.state_flags!=SF_MAYSET)) {
if((setf & ~dyn->insts[ninst].x64.set_flags) == 0)
return needed; // all done, gives all the flags needed
setf |= dyn->insts[ninst].x64.set_flags; // add new flags to continue
}
int jinst = dyn->insts[ninst].x64.jmp_insts;
if(dyn->insts[ninst].x64.jmp) {
dyn->insts[ninst].x64.need_flags = (jinst==-1)?X_PEND:needed_flags(dyn, jinst, setf, recurse+1);
if(dyn->insts[ninst].x64.use_flags) // conditionnal jump
dyn->insts[ninst].x64.need_flags |= needed_flags(dyn, ninst+1, setf, recurse);
} else
dyn->insts[ninst].x64.need_flags = needed_flags(dyn, ninst+1, setf, recurse);
if(dyn->insts[ninst].x64.state_flags==SF_MAYSET)
needed |= dyn->insts[ninst].x64.need_flags;
else
needed |= (dyn->insts[ninst].x64.need_flags & ~dyn->insts[ninst].x64.set_flags);
if(needed == (X_PEND|X_ALL))
needed = X_ALL;
return needed;
}
instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x64_size, int arm_size)
{
// x64 instruction is <16 bytes
int toadd;
if(x64_size>native_size)
if(x64_size>arm_size)
toadd = 1 + x64_size/15;
else
toadd = 1 + native_size/15;
toadd = 1 + arm_size/15;
if((*size)+toadd>(*cap)) {
*cap = (*size)+toadd;
insts = (instsize_t*)realloc(insts, (*cap)*sizeof(instsize_t));
@@ -250,11 +294,11 @@ instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x64_size,
else
insts[*size].x64 = x64_size;
x64_size -= insts[*size].x64;
if(native_size>15)
if(arm_size>15)
insts[*size].nat = 15;
else
insts[*size].nat = native_size;
native_size -= insts[*size].nat;
insts[*size].nat = arm_size;
arm_size -= insts[*size].nat;
++(*size);
--toadd;
}
@@ -262,7 +306,7 @@ instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x64_size,
}
// add a value to table64 (if needed) and gives back the imm19 to use in LDR_literal
int Table64(dynarec_native_t *dyn, uint64_t val)
int Table64(dynarec_arm_t *dyn, uint64_t val)
{
// find the value if already present
int idx = -1;
@@ -283,125 +327,13 @@ int Table64(dynarec_native_t *dyn, uint64_t val)
return delta;
}
static void fillPredecessors(dynarec_native_t* dyn)
{
int pred_sz = 0;
// compute total size of predecessor to alocate the array
// first compute the jumps
for(int i=0; i<dyn->size; ++i) {
if(dyn->insts[i].x64.jmp && dyn->insts[i].x64.jmp_insts!=-1) {
++pred_sz;
++dyn->insts[dyn->insts[i].x64.jmp_insts].pred_sz;
}
}
// second the "has_next"
for(int i=0; i<dyn->size; ++i) {
if(i!=dyn->size-1 && dyn->insts[i].x64.has_next && (!i || dyn->insts[i].pred_sz)) {
++pred_sz;
++dyn->insts[i+1].pred_sz;
}
}
dyn->predecessor = (int*)malloc(pred_sz*sizeof(int));
// fill pred pointer
int* p = dyn->predecessor;
for(int i=0; i<dyn->size; ++i) {
dyn->insts[i].pred = p;
p += dyn->insts[i].pred_sz;
dyn->insts[i].pred_sz=0; // reset size, it's reused to actually fill pred[]
}
assert(p==dyn->predecessor+pred_sz);
// fill pred
for(int i=0; i<dyn->size; ++i) {
if(i!=dyn->size-1 && dyn->insts[i].x64.has_next && (!i || dyn->insts[i].pred_sz))
dyn->insts[i+1].pred[dyn->insts[i+1].pred_sz++] = i;
if(dyn->insts[i].x64.jmp && dyn->insts[i].x64.jmp_insts!=-1)
dyn->insts[dyn->insts[i].x64.jmp_insts].pred[dyn->insts[dyn->insts[i].x64.jmp_insts].pred_sz++] = i;
}
}
static void updateNeed(dynarec_native_t* dyn, int ninst, uint32_t need) {
uint32_t old_need = dyn->insts[ninst].x64.need_flags;
uint32_t new_need = old_need | need;
uint32_t new_use = dyn->insts[ninst].x64.use_flags;
uint32_t old_use = dyn->insts[ninst].x64.old_use;
if((new_need&X_PEND) && dyn->insts[ninst].x64.state_flags==SF_SUBSET) {
new_need &=~X_PEND;
new_need |= X_ALL;
}
uint32_t new_set = 0;
if(dyn->insts[ninst].x64.state_flags & SF_SET)
new_set = dyn->insts[ninst].x64.set_flags;
if(dyn->insts[ninst].x64.state_flags & SF_PENDING)
new_set |= X_PEND;
if((new_need&X_PEND) && (
dyn->insts[ninst].x64.state_flags==SF_SET || dyn->insts[ninst].x64.state_flags==SF_SUBSET)) {
new_need &=~X_PEND;
new_need |=X_ALL;
}
dyn->insts[ninst].x64.need_flags = new_need;
dyn->insts[ninst].x64.old_use = new_use;
if(dyn->insts[ninst].x64.jmp_insts==-1)
new_need |= X_PEND;
// a Flag Barrier will change all need to "Pending", as it clear all flags optimisation
if(new_need && dyn->insts[ninst].x64.barrier&BARRIER_FLAGS)
new_need = X_PEND;
if((new_need == old_need) && (new_use == old_use)) // no changes, bye
return;
if(!(new_need && dyn->insts[ninst].x64.barrier&BARRIER_FLAGS)) {
new_need &=~new_set; // clean needed flag that were suplied
new_need |= new_use; // new need
}
if((new_need == (X_ALL|X_PEND)) && (dyn->insts[ninst].x64.state_flags & SF_SET))
new_need = X_ALL;
//update need to new need on predecessor
for(int i=0; i<dyn->insts[ninst].pred_sz; ++i)
updateNeed(dyn, dyn->insts[ninst].pred[i], new_need);
}
static void resetNeed(dynarec_native_t* dyn) {
for(int i = dyn->size; i-- > 0;) {
dyn->insts[i].x64.old_use = 0;
dyn->insts[i].x64.need_flags = dyn->insts[i].x64.default_need;
}
}
__thread void* current_helper = NULL;
void CancelBlock64()
{
dynarec_native_t* helper = (dynarec_native_t*)current_helper;
current_helper = NULL;
if(!helper)
return;
free(helper->next);
free(helper->insts);
free(helper->table64);
free(helper->sons_x64);
free(helper->sons_native);
if(helper->dynablock && helper->dynablock->block)
FreeDynarecMap(helper->dynablock, (uintptr_t)helper->dynablock->block, helper->dynablock->size);
}
uintptr_t native_pass0(dynarec_native_t* dyn, uintptr_t addr);
uintptr_t native_pass1(dynarec_native_t* dyn, uintptr_t addr);
uintptr_t native_pass2(dynarec_native_t* dyn, uintptr_t addr);
uintptr_t native_pass3(dynarec_native_t* dyn, uintptr_t addr);
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* FillBlock64(dynablock_t* block, uintptr_t addr) {
if(IsInHotPage(addr)) {
dynarec_log(LOG_DEBUG, "Cancelling dynarec FillBlock on hotpage for %p\n", (void*)addr);
return NULL;
}
if(addr>=box64_nodynarec_start && addr<box64_nodynarec_end) {
block->done = 1;
return (void*)block;
@@ -409,153 +341,80 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
// protect the 1st page
protectDB(addr, 1);
// init the helper
dynarec_native_t helper = {0};
current_helper = &helper;
helper.dynablock = block;
dynarec_arm_t helper = {0};
helper.start = addr;
uintptr_t start = addr;
helper.cap = 64; // needs epilog handling
helper.insts = (instruction_native_t*)calloc(helper.cap, sizeof(instruction_native_t));
// pass 0, addresses, x64 jump addresses, overall size of the block
uintptr_t end = native_pass0(&helper, addr);
// no need for next anymore
free(helper.next);
helper.next_sz = helper.next_cap = 0;
helper.next = NULL;
// basic checks
if(!helper.size) {
dynarec_log(LOG_INFO, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
CancelBlock64();
uintptr_t end = arm_pass0(&helper, addr);
if(!helper.size || !isprotectedDB(addr, 1)) {
dynarec_log(LOG_DEBUG, "Warning, null-sized dynarec block (%p) or write on purge on pass0\n", (void*)addr);
block->done = 1;
return (void*)block;
}
if(!isprotectedDB(addr, 1)) {
dynarec_log(LOG_INFO, "Warning, write on current page on pass0, aborting dynablock creation (%p)\n", (void*)addr);
CancelBlock64();
return NULL;
}
// protect the block of it goes over the 1st page
helper.cap = helper.size+3; // needs epilog handling
helper.insts = (instruction_arm64_t*)calloc(helper.cap, sizeof(instruction_arm64_t));
// already protect the block and compute hash signature
if((addr&~0xfff)!=(end&~0xfff)) // need to protect some other pages too
protectDB(addr, end-addr); //end is 1byte after actual end
// compute hash signature
uint32_t hash = X31_hash_code((void*)addr, end-addr);
// Compute flag_need, without with current barriers
resetNeed(&helper);
for(int i = helper.size; i-- > 0;)
updateNeed(&helper, i, 0);
// pass 1, addresses, x64 jump addresses, flags
arm_pass1(&helper, addr);
// calculate barriers
for(int i=0; i<helper.size; ++i)
if(helper.insts[i].x64.jmp) {
uintptr_t j = helper.insts[i].x64.jmp;
if(j<start || j>=end) {
if(j<start || j>=end)
helper.insts[i].x64.jmp_insts = -1;
helper.insts[i].x64.use_flags |= X_PEND;
} else {
else {
// find jump address instruction
int k=-1;
for(int i2=0; i2<helper.size && k==-1; ++i2) {
if(helper.insts[i2].x64.addr==j)
k=i2;
}
if(k!=-1 && !helper.insts[i].barrier_maybe)
helper.insts[k].x64.barrier |= BARRIER_FULL;
if(k!=-1) // -1 if not found, mmm, probably wrong, exit anyway
helper.insts[k].x64.barrier = 1;
helper.insts[i].x64.jmp_insts = k;
}
}
// fill predecessors with the jump address
fillPredecessors(&helper);
// check for the optionnal barriers now
for(int i=helper.size-1; i>=0; --i) {
if(helper.insts[i].barrier_maybe) {
// out-of-block jump
if(helper.insts[i].x64.jmp_insts == -1) {
// nothing for now
} else {
// inside block jump
int k = helper.insts[i].x64.jmp_insts;
if(k>i) {
// jump in the future
if(helper.insts[k].pred_sz>1) {
// with multiple flow, put a barrier
helper.insts[k].x64.barrier|=BARRIER_FLAGS;
}
} else {
// jump back
helper.insts[k].x64.barrier|=BARRIER_FLAGS;
}
}
}
}
// check to remove useless barrier, in case of jump when destination doesn't needs flags
/*for(int i=helper.size-1; i>=0; --i) {
int k;
if(helper.insts[i].x64.jmp
&& ((k=helper.insts[i].x64.jmp_insts)>=0)
&& helper.insts[k].x64.barrier&BARRIER_FLAGS) {
//TODO: optimize FPU barrier too
if((!helper.insts[k].x64.need_flags)
||(helper.insts[k].x64.set_flags==X_ALL
&& helper.insts[k].x64.state_flags==SF_SET)
||(helper.insts[k].x64.state_flags==SF_SET_PENDING)) {
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Removed barrier for inst %d\n", k);
helper.insts[k].x64.barrier &= ~BARRIER_FLAGS; // remove flag barrier
}
for(int i=0; i<helper.size; ++i)
if(helper.insts[i].x64.set_flags && !helper.insts[i].x64.need_flags) {
helper.insts[i].x64.need_flags = needed_flags(&helper, i+1, helper.insts[i].x64.set_flags, 0);
if((helper.insts[i].x64.need_flags&X_PEND) && (helper.insts[i].x64.state_flags==SF_MAYSET))
helper.insts[i].x64.need_flags = X_ALL;
}
}*/
// reset need_flags and compute again, now taking barrier into account (because barrier change use_flags)
for(int i = helper.size; i-- > 0;) {
int k;
if(helper.insts[i].x64.jmp
&& ((k=helper.insts[i].x64.jmp_insts)>=0)
) {
if(helper.insts[k].x64.barrier&BARRIER_FLAGS)
// jumpto barrier
helper.insts[i].x64.use_flags |= X_PEND;
if(helper.insts[i].x64.barrier&BARRIER_FLAGS && (helper.insts[k].x64.need_flags | helper.insts[k].x64.use_flags))
helper.insts[k].x64.barrier|=BARRIER_FLAGS;
else
helper.insts[i].x64.use_flags |= (helper.insts[k].x64.need_flags | helper.insts[k].x64.use_flags);
}
if(helper.insts[i].x64.barrier&BARRIER_FLAGS)
// immediate barrier
helper.insts[i].x64.use_flags |= X_PEND;
}
resetNeed(&helper);
for(int i = helper.size; i-- > 0;)
updateNeed(&helper, i, 0);
// pass 1, float optimisations, first pass for flags
native_pass1(&helper, addr);
// pass 2, instruction size
native_pass2(&helper, addr);
arm_pass2(&helper, addr);
// ok, now allocate mapped memory, with executable flag on
size_t sz = helper.native_size + helper.table64size*sizeof(uint64_t);
size_t sz = helper.arm_size + helper.table64size*sizeof(uint64_t);
void* p = (void*)AllocDynarecMap(block, sz);
if(p==NULL) {
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, cancelling block\n", block, sz);
CancelBlock64();
dynarec_log(LOG_DEBUG, "AllocDynarecMap(%p, %zu) failed, cancelling block\n", block, sz);
free(helper.insts);
free(helper.next);
free(helper.table64);
return NULL;
}
helper.block = p;
helper.native_start = (uintptr_t)p;
helper.tablestart = helper.native_start + helper.native_size;
helper.arm_start = (uintptr_t)p;
helper.tablestart = helper.arm_start + helper.arm_size;
if(helper.sons_size) {
helper.sons_x64 = (uintptr_t*)calloc(helper.sons_size, sizeof(uintptr_t));
helper.sons_native = (void**)calloc(helper.sons_size, sizeof(void*));
helper.sons_arm = (void**)calloc(helper.sons_size, sizeof(void*));
}
// pass 3, emit (log emit native opcode)
// pass 3, emit (log emit arm opcode)
if(box64_dynarec_dump) {
dynarec_log(LOG_NONE, "%s%04d|Emitting %zu bytes for %u x64 bytes", (box64_dynarec_dump>1)?"\e[01;36m":"", GetTID(), helper.native_size, helper.isize);
dynarec_log(LOG_NONE, "%s%04d|Emitting %zu bytes for %u x64 bytes", (box64_dynarec_dump>1)?"\e[01;36m":"", GetTID(), helper.arm_size, helper.isize);
printFunctionAddr(helper.start, " => ");
dynarec_log(LOG_NONE, "%s\n", (box64_dynarec_dump>1)?"\e[m":"");
}
int oldtable64size = helper.table64size;
size_t oldnativesize = helper.native_size;
helper.native_size = 0;
size_t oldarmsize = helper.arm_size;
helper.arm_size = 0;
helper.table64size = 0; // reset table64 (but not the cap)
native_pass3(&helper, addr);
if((oldnativesize!=helper.native_size) || (oldtable64size<helper.table64size)) {
printf_log(LOG_NONE, "BOX64: Warning, size difference in block between pass2 (%zu) & pass3 (%zu)!\n", sz, helper.native_size+helper.table64size*8);
arm_pass3(&helper, addr);
if((oldarmsize!=helper.arm_size) || (oldtable64size<helper.table64size)) {
printf_log(LOG_NONE, "BOX64: Warning, size difference in block between pass2 (%zu) & pass3 (%zu)!\n", sz, helper.arm_size+helper.table64size*8);
uint8_t *dump = (uint8_t*)helper.start;
printf_log(LOG_NONE, "Dump of %d x64 opcodes:\n", helper.size);
for(int i=0; i<helper.size; ++i) {
@@ -566,7 +425,15 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
}
printf_log(LOG_NONE, "Table64 \t%d -> %d\n", oldtable64size*8, helper.table64size*8);
printf_log(LOG_NONE, " ------------\n");
//TODO: Cancel block and return empty one
free(helper.insts);
free(helper.next);
free(helper.table64);
free(helper.sons_x64);
free(helper.sons_arm);
FreeDynarecMap(block, (uintptr_t)p, sz);
return NULL;
}
// add table64 if needed
if(helper.table64size) {
@@ -587,9 +454,8 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
}
// ok, free the helper now
free(helper.insts);
helper.insts = NULL;
free(helper.next);
free(helper.table64);
helper.table64 = NULL;
block->size = sz;
block->isize = helper.size;
block->block = p;
@@ -598,18 +464,13 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
block->x64_size = end-start;
block->hash = X31_hash_code(block->x64_addr, block->x64_size);
// Check if something changed, to abbort if it as
if((block->hash != hash)) {
if(block->hash != hash || !isprotectedDB(addr, end-addr)) {
dynarec_log(LOG_INFO, "Warning, a block changed while beeing processed hash(%p:%ld)=%x/%x\n", block->x64_addr, block->x64_size, block->hash, hash);
CancelBlock64();
free(helper.sons_x64);
free(helper.sons_arm);
FreeDynarecMap(block, (uintptr_t)p, sz);
return NULL;
}
if(!isprotectedDB(addr, end-addr)) {
dynarec_log(LOG_INFO, "Warning, block unprotected while beeing processed %p:%ld, cancelling\n", block->x64_addr, block->x64_size);
CancelBlock64();
return NULL;
//protectDB(addr, end-addr);
}
// fill sons if any
} // fill sons if any
dynablock_t** sons = NULL;
int sons_size = 0;
if(helper.sons_size) {
@@ -618,10 +479,10 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
int created = 1;
dynablock_t *son = AddNewDynablock(block->parent, helper.sons_x64[i], &created);
if(created) { // avoid breaking a working block!
son->block = helper.sons_native[i];
son->block = helper.sons_arm[i];
son->x64_addr = (void*)helper.sons_x64[i];
son->x64_size = end-helper.sons_x64[i];
if(!son->x64_size) {printf_log(LOG_NONE, "Warning, son with null x64 size! (@%p / Native=%p)", son->x64_addr, son->block);}
if(!son->x64_size) {printf_log(LOG_NONE, "Warning, son with null x64 size! (@%p / ARM=%p)", son->x64_addr, son->block);}
son->father = block;
son->size = sz + son->block - block->block; // update size count, for debugging
//son->done = 1;
@@ -638,10 +499,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
free(sons);
}
free(helper.sons_x64);
helper.sons_x64 = NULL;
free(helper.sons_native);
helper.sons_native = NULL;
current_helper = NULL;
free(helper.sons_arm);
//block->done = 1;
return (void*)block;
}
@@ -17,10 +17,10 @@
#include "bridge.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64.h"
#include "dynarec_arm64_private.h"
#include "arm64_printer.h"
#include "dynarec_arm64_functions.h"
#include "dynarec_arm64_helper.h"
@@ -372,9 +372,6 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
i64 = F32S;
emit_sub32c(dyn, ninst, rex, xRAX, i64, x3, x4, x5);
break;
case 0x2E:
INST_NAME("CS:");
break;
case 0x30:
INST_NAME("XOR Eb, Gb");
@@ -636,30 +633,23 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
break;
#define GO(GETFLAGS, NO, YES, F) \
READFLAGS(F); \
i8 = F8S; \
BARRIER(BARRIER_MAYBE); \
JUMP(addr+i8, 1); \
GETFLAGS; \
if(dyn->insts[ninst].x64.jmp_insts==-1 || \
CHECK_CACHE()) { \
/* out of the block */ \
i32 = dyn->insts[ninst].epilog-(dyn->native_size); \
Bcond(NO, i32); \
if(dyn->insts[ninst].x64.jmp_insts==-1) { \
if(!dyn->insts[ninst].x64.barrier) \
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
jump_to_next(dyn, addr+i8, 0, ninst); \
} else { \
fpuCacheTransform(dyn, ninst, x1, x2, x3); \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);\
B(i32); \
} \
} else { \
/* inside the block */ \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
Bcond(YES, i32); \
#define GO(GETFLAGS, NO, YES, F) \
READFLAGS(F); \
i8 = F8S; \
BARRIER(2); \
JUMP(addr+i8);\
GETFLAGS; \
if(dyn->insts) { \
if(dyn->insts[ninst].x64.jmp_insts==-1) { \
/* out of the block */ \
i32 = dyn->insts[ninst+1].address-(dyn->arm_size); \
Bcond(NO, i32); \
jump_to_next(dyn, addr+i8, 0, ninst); \
} else { \
/* inside the block */ \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->arm_size); \
Bcond(YES, i32); \
} \
}
GOCOND(0x70, "J", "ib");
@@ -856,7 +846,6 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
BFIx(gb1, x1, gb2*8, 8);
BFIx(eb1, x4, eb2*8, 8);
} else {
DMB_ISH();
GETGB(x4);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
MARKLOCK;
@@ -865,7 +854,6 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
// do the swap 14 -> strb(ed), 1 -> gd
STLXRB(x3, x4, ed);
CBNZx_MARKLOCK(x3);
DMB_ISH();
BFIx(gb1, x1, gb2*8, 8);
}
break;
@@ -881,7 +869,6 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
} else {
GETGD;
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
DMB_ISH();
TSTx_mask(ed, 1, 0, 1+rex.w); // mask=3 or 7
B_MARK(cNE);
MARKLOCK;
@@ -893,7 +880,6 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
LDRxw_U12(x1, ed, 0);
STRxw_U12(gd, ed, 0);
MARK2;
DMB_ISH();
MOVxw_REG(gd, x1);
}
break;
@@ -938,10 +924,6 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
} else { // mem <= reg
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, 0);
STRxw_U12(gd, ed, fixedaddress);
if(box64_dynarec_strongmem &&
(dyn->insts[ninst].x64.barrier || box64_dynarec_strongmem>1 || (dyn->insts[ninst+1].x64.barrier || dyn->insts[ninst+1].x64.jmp))) {
DMB_ISH();
}
}
break;
case 0x8A:
@@ -971,10 +953,6 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
ed = wback;
}
} else {
if(box64_dynarec_strongmem &&
(dyn->insts[ninst].x64.barrier || !ninst || box64_dynarec_strongmem>1 || (ninst && dyn->insts[ninst-1].x64.barrier))) {
DMB_ISH();
}
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff, 0, rex, 0, 0);
LDRB_U12(x4, wback, fixedaddress);
ed = x4;
@@ -985,13 +963,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("MOV Gd, Ed");
nextop=F8;
GETGD;
if(MODREG) {
if(MODREG) { // reg <= reg
MOVxw_REG(gd, xRAX+(nextop&7)+(rex.b<<3));
} else {
if(box64_dynarec_strongmem &&
(dyn->insts[ninst].x64.barrier || !ninst || box64_dynarec_strongmem>1 || (ninst && dyn->insts[ninst-1].x64.barrier))) {
DMB_ISH();
}
} else { // mem <= reg
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, 0);
LDRxw_U12(gd, ed, fixedaddress);
}
@@ -1023,19 +997,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
}
break;
case 0x8E:
INST_NAME("MOV Seg,Ew");
nextop = F8;
if((nextop&0xC0)==0xC0) {
ed = xRAX+(nextop&7)+(rex.b<<3);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 0, rex, 0, 0);
LDRH_U12(x1, ed, fixedaddress);
ed = x1;
}
STRw_U12(ed, xEmu, offsetof(x64emu_t, segs[(nextop&0x38)>>3]));
STRw_U12(wZR, xEmu, offsetof(x64emu_t, segs_serial[(nextop&0x38)>>3]));
break;
case 0x8F:
INST_NAME("POP Ed");
nextop = F8;
@@ -1489,7 +1451,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
switch((nextop>>3)&7) {
case 0:
INST_NAME("ROL Ed, Ib");
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
SETFLAGS(X_OF|X_CF, SF_SUBSET);
GETED(1);
u8 = (F8)&(rex.w?0x3f:0x1f);
emit_rol32c(dyn, ninst, rex, ed, u8, x3, x4);
@@ -1497,7 +1459,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 1:
INST_NAME("ROR Ed, Ib");
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
SETFLAGS(X_OF|X_CF, SF_SUBSET);
GETED(1);
u8 = (F8)&(rex.w?0x3f:0x1f);
emit_ror32c(dyn, ninst, rex, ed, u8, x3, x4);
@@ -1560,7 +1522,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("RETN");
//SETFLAGS(X_ALL, SF_SET); // Hack, set all flags (to an unknown state...)
READFLAGS(X_PEND); // lets play safe here too
BARRIER(BARRIER_FLOAT);
BARRIER(2);
i32 = F16;
retn_to_epilog(dyn, ninst, i32);
*need_epilog = 0;
@@ -1570,7 +1532,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("RET");
// SETFLAGS(X_ALL, SF_SET); // Hack, set all flags (to an unknown state...)
READFLAGS(X_PEND); // so instead, force the defered flags, so it's not too slow, and flags are not lost
BARRIER(BARRIER_FLOAT);
BARRIER(2);
ret_to_epilog(dyn, ninst);
*need_epilog = 0;
*ok = 0;
@@ -1623,7 +1585,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET); // Hack, set all flags (to an unknown state...)
if(PK(0)=='S' && PK(1)=='C') {
addr+=2;
BARRIER(BARRIER_FLOAT);
BARRIER(2);
INST_NAME("Special Box64 instruction");
if((PK64(0)==0))
{
@@ -1681,7 +1643,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xCF:
INST_NAME("IRET");
SETFLAGS(X_ALL, SF_SET); // Not a hack, EFLAGS are restored
BARRIER(BARRIER_FLOAT);
BARRIER(2);
iret_to_epilog(dyn, ninst, rex.w);
*need_epilog = 0;
*ok = 0;
@@ -1794,14 +1756,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
switch((nextop>>3)&7) {
case 0:
INST_NAME("ROL Ed, 1");
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
SETFLAGS(X_OF|X_CF, SF_SUBSET);
GETED(0);
emit_rol32c(dyn, ninst, rex, ed, 1, x3, x4);
WBACK;
break;
case 1:
INST_NAME("ROR Ed, 1");
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
SETFLAGS(X_OF|X_CF, SF_SUBSET);
GETED(0);
emit_ror32c(dyn, ninst, rex, ed, 1, x3, x4);
WBACK;
@@ -2006,26 +1968,19 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
addr = dynarec64_DF(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
break;
#define GO(Z) \
BARRIER(BARRIER_MAYBE); \
JUMP(addr+i8, 1); \
if(dyn->insts[ninst].x64.jmp_insts==-1 || \
CHECK_CACHE()) { \
/* out of the block */ \
i32 = dyn->insts[ninst].epilog-(dyn->native_size); \
if(Z) {CBNZx(xRCX, i32);} else {CBZx(xRCX, i32);}; \
BARRIER(2); \
JUMP(addr+i8); \
if(dyn->insts) { \
if(dyn->insts[ninst].x64.jmp_insts==-1) { \
if(!dyn->insts[ninst].x64.barrier) \
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
/* out of the block */ \
i32 = dyn->insts[ninst+1].address-(dyn->arm_size); \
if(Z) {CBNZx(xRCX, i32);} else {CBZx(xRCX, i32);}; \
jump_to_next(dyn, addr+i8, 0, ninst); \
} else { \
fpuCacheTransform(dyn, ninst, x1, x2, x3); \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
Bcond(c__, i32); \
} \
} else { \
/* inside the block */ \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
if(Z) {CBZx(xRCX, i32);} else {CBNZx(xRCX, i32);}; \
/* inside the block */ \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->arm_size); \
if(Z) {CBZx(xRCX, i32);} else {CBNZx(xRCX, i32);}; \
} \
}
case 0xE0:
INST_NAME("LOOPNZ");
@@ -2064,7 +2019,12 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
printf_log(LOG_INFO, "Warning, CALL to 0x0 at %p (%p)\n", (void*)addr, (void*)(addr-1));
#endif
}
#if STEP < 2
#if STEP == 0
if(isNativeCall(dyn, addr+i32, NULL, NULL))
tmp = 3;
else
tmp = 0;
#elif STEP < 2
if(isNativeCall(dyn, addr+i32, &dyn->insts[ninst].natcall, &dyn->insts[ninst].retn))
tmp = dyn->insts[ninst].pass2choice = 3;
else
@@ -2075,14 +2035,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
switch(tmp) {
case 3:
SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
BARRIER(BARRIER_FULL);
//BARRIER_NEXT(BARRIER_FULL);
BARRIER(1);
BARRIER_NEXT(1);
TABLE64(x2, addr);
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
sse_purge07cache(dyn, ninst, x3);
if(box64_log<2 && dyn->insts[ninst].natcall && (tmp=isSimpleWrapper(*(wrapper_t*)(dyn->insts[ninst].natcall+2)))) {
if(box64_log<2 && dyn->insts && (tmp=isSimpleWrapper(*(wrapper_t*)(dyn->insts[ninst].natcall+2)))) {
//GETIP(ip+3+8+8); // read the 0xCC
call_n(dyn, ninst, *(void**)(dyn->insts[ninst].natcall+2+8), tmp);
POP1(xRIP); // pop the return address
@@ -2110,16 +2070,18 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
break;
default:
if(ninst && dyn->insts[ninst-1].x64.set_flags) {
if(ninst && dyn->insts && dyn->insts[ninst-1].x64.set_flags) {
READFLAGS(X_PEND); // that's suspicious
} else {
SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
}
// regular call
BARRIER(BARRIER_FULL);
//BARRIER_NEXT(1);
*need_epilog = 0;
*ok = 0;
BARRIER(1);
BARRIER_NEXT(1);
if(!dyn->insts || ninst==dyn->size-1) {
*need_epilog = 0;
*ok = 0;
}
TABLE64(x2, addr);
PUSH1(x2);
if(addr+i32==0) { // self modifying code maybe? so use indirect address fetching
@@ -2133,7 +2095,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 0xE9:
case 0xEB:
BARRIER(BARRIER_MAYBE);
BARRIER(1);
if(opcode==0xE9) {
INST_NAME("JMP Id");
i32 = F32S;
@@ -2141,19 +2103,19 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("JMP Ib");
i32 = F8S;
}
JUMP(addr+i32, 0);
if(dyn->insts[ninst].x64.jmp_insts==-1) {
// out of the block
fpu_purgecache(dyn, ninst, 1, x1, x2, x3);
jump_to_next(dyn, addr+i32, 0, ninst);
} else {
// inside the block
fpuCacheTransform(dyn, ninst, x1, x2, x3);
tmp = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);
if(tmp==4) {
NOP;
JUMP(addr+i32);
if(dyn->insts) {
PASS2IF(dyn->insts[ninst].x64.jmp_insts==-1, 1) {
// out of the block
jump_to_next(dyn, addr+i32, 0, ninst);
} else {
B(tmp);
// inside the block
tmp = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->arm_size);
if(tmp==4) {
NOP;
} else {
B(tmp);
}
}
}
*need_epilog = 0;
@@ -2309,7 +2271,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MOVw_REG(xRAX, x2);
MOVw_REG(xRDX, x4);
} else {
if(ninst
if(ninst && dyn->insts
&& dyn->insts[ninst-1].x64.addr
&& *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0x31
&& *(uint8_t*)(dyn->insts[ninst-1].x64.addr+1)==0xD2) {
@@ -2356,15 +2318,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MOVx_REG(xRAX, x2);
} else {
GETEDH(x1, 0); // get edd changed addr, so cannot be called 2 times for same op...
//Need to see if RDX==0 and RAX not signed
// or RDX==-1 and RAX signed
CBNZx_MARK2(xRDX);
TBZ_MARK(xRAX, 31);
MARK2;
CBZxw_MARK(xRDX);
MVNx_REG(x2, xRDX);
CBNZx_MARK3(x2);
TBNZ_MARK(xRAX, 31);
MARK3;
CBZxw_MARK(x2);
if(ed!=x1) {MOVx_REG(x1, ed);}
CALL((void*)idiv64, -1);
B_NEXT_nocond;
@@ -2393,14 +2349,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
switch((nextop>>3)&7) {
case 0:
INST_NAME("INC Eb");
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
GETEB(x1, 0);
emit_inc8(dyn, ninst, x1, x2, x4);
EBBACK;
break;
case 1:
INST_NAME("DEC Eb");
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
GETEB(x1, 0);
emit_dec8(dyn, ninst, x1, x2, x4);
EBBACK;
@@ -2414,21 +2370,22 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
switch((nextop>>3)&7) {
case 0: // INC Ed
INST_NAME("INC Ed");
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
GETED(0);
emit_inc32(dyn, ninst, rex, ed, x3, x4);
WBACK;
break;
case 1: //DEC Ed
INST_NAME("DEC Ed");
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
GETED(0);
emit_dec32(dyn, ninst, rex, ed, x3, x4);
WBACK;
break;
case 2: // CALL Ed
INST_NAME("CALL Ed");
PASS2IF(((ninst && dyn->insts[ninst-1].x64.set_flags)
PASS2IF(dyn->insts &&
((ninst && dyn->insts[ninst-1].x64.set_flags)
|| ((ninst>1) && dyn->insts[ninst-2].x64.set_flags)), 1)
{
READFLAGS(X_PEND); // that's suspicious
@@ -2436,19 +2393,19 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET); //Hack to put flag in "don't care" state
}
GETEDx(0);
BARRIER(BARRIER_FLOAT);
//BARRIER_NEXT(BARRIER_FULL);
BARRIER(1);
BARRIER_NEXT(1);
if(!dyn->insts || ninst==dyn->size-1) {
*need_epilog = 0;
*ok = 0;
}
GETIP_(addr);
GETIP(addr);
PUSH1(xRIP);
jump_to_next(dyn, 0, ed, ninst);
break;
case 4: // JMP Ed
INST_NAME("JMP Ed");
BARRIER(BARRIER_FULL);
BARRIER(1);
GETEDx(0);
jump_to_next(dyn, 0, ed, ninst);
*need_epilog = 0;
@@ -15,46 +15,46 @@
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "dynarec_arm64.h"
#include "dynarec_arm64_private.h"
#include "arm64_printer.h"
#include "my_cpuid.h"
#include "emu/x87emu_private.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "dynarec_arm64_functions.h"
#include "dynarec_arm64_helper.h"
#define GETG \
gd = ((nextop&0x38)>>3)+(rex.r<<3) \
#define GETGX(a, w) \
#define GETGX(a) \
gd = ((nextop&0x38)>>3)+(rex.r<<3); \
a = sse_get_reg(dyn, ninst, x1, gd, w)
a = sse_get_reg(dyn, ninst, x1, gd)
#define GETGX_empty(a) \
gd = ((nextop&0x38)>>3)+(rex.r<<3); \
a = sse_get_reg_empty(dyn, ninst, x1, gd)
#define GETEX(a, w, D) \
if(MODREG) { \
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), w); \
} else { \
#define GETEX(a, D) \
if(MODREG) { \
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3)); \
} else { \
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, D); \
a = fpu_get_scratch(dyn); \
VLDR128_U12(a, ed, fixedaddress); \
a = fpu_get_scratch(dyn); \
VLDR128_U12(a, ed, fixedaddress); \
}
#define GETGM(a) \
gd = ((nextop&0x38)>>3); \
a = mmx_get_reg(dyn, ninst, x1, x2, x3, gd)
a = mmx_get_reg(dyn, ninst, x1, gd)
#define GETEM(a, D) \
if(MODREG) { \
a = mmx_get_reg(dyn, ninst, x1, x2, x3, (nextop&7)); \
} else { \
#define GETEM(a, D) \
if(MODREG) { \
a = mmx_get_reg(dyn, ninst, x1, (nextop&7));\
} else { \
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, D); \
a = fpu_get_scratch(dyn); \
VLDR64_U12(a, ed, fixedaddress); \
a = fpu_get_scratch(dyn); \
VLDR64_U12(a, ed, fixedaddress); \
}
#define PUTEM(a) \
@@ -151,7 +151,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GETG;
if(MODREG) {
ed = (nextop&7)+(rex.b<<3);
v1 = sse_get_reg(dyn, ninst, x1, ed, 0);
v1 = sse_get_reg(dyn, ninst, x1, ed);
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
VMOVQ(v0, v1);
} else {
@@ -164,7 +164,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("MOVUPS Ex,Gx");
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
v0 = sse_get_reg(dyn, ninst, x1, gd);
if(MODREG) {
ed = (nextop&7)+(rex.b<<3);
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
@@ -178,12 +178,12 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
nextop = F8;
if(MODREG) {
INST_NAME("MOVHLPS Gx,Ex");
GETGX(v0, 1);
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
GETGX(v0);
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
VMOVeD(v0, 0, v1, 1);
} else {
INST_NAME("MOVLPS Gx,Ex");
GETGX(v0, 1);
GETGX(v0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
VLD1_64(v0, 0, ed);
}
@@ -191,9 +191,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0x13:
nextop = F8;
INST_NAME("MOVLPS Ex,Gx");
GETGX(v0, 0);
GETGX(v0);
if(MODREG) {
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
VMOVeD(v1, 0, v0, 0);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
@@ -203,27 +203,27 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0x14:
INST_NAME("UNPCKLPS Gx, Ex");
nextop = F8;
GETEX(q0, 0, 0);
GETGX(v0, 1);
GETEX(q0, 0);
GETGX(v0);
VZIP1Q_32(v0, v0, q0);
break;
case 0x15:
INST_NAME("UNPCKHPS Gx, Ex");
nextop = F8;
GETEX(q0, 0, 0);
GETGX(v0, 1);
GETEX(q0, 0);
GETGX(v0);
VZIP2Q_32(v0, v0, q0);
break;
case 0x16:
nextop = F8;
if(MODREG) {
INST_NAME("MOVLHPS Gx,Ex");
GETGX(v0, 1);
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
GETGX(v0);
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
VMOVeD(v0, 1, v1, 0);
} else {
INST_NAME("MOVHPS Gx,Ex");
GETGX(v0, 1);
GETGX(v0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
VLD1_64(v0, 1, ed);
}
@@ -231,9 +231,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0x17:
nextop = F8;
INST_NAME("MOVHPS Ex,Gx");
GETGX(v0, 0);
GETGX(v0);
if(MODREG) {
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
VMOVeD(v1, 0, v0, 1);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
@@ -284,7 +284,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GETG;
if(MODREG) {
ed = (nextop&7)+(rex.b<<3);
v1 = sse_get_reg(dyn, ninst, x1, ed, 0);
v1 = sse_get_reg(dyn, ninst, x1, ed);
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
VMOVQ(v0, v1);
} else {
@@ -297,7 +297,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("MOVAPS Ex,Gx");
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
v0 = sse_get_reg(dyn, ninst, x1, gd);
if(MODREG) {
ed = (nextop&7)+(rex.b<<3);
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
@@ -312,7 +312,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("MOVNTPS Ex,Gx");
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
v0 = sse_get_reg(dyn, ninst, x1, gd);
if(MODREG) {
ed = (nextop&7)+(rex.b<<3);
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
@@ -329,9 +329,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(opcode==0x2F) {INST_NAME("COMISS Gx, Ex");} else {INST_NAME("UCOMISS Gx, Ex");}
SETFLAGS(X_ALL, SF_SET);
nextop = F8;
GETGX(v0, 0);
GETGX(v0);
if(MODREG) {
s0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
s0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
} else {
s0 = fpu_get_scratch(dyn);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
@@ -391,30 +391,6 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
break;
case 0x3A: // these are some more SSSE3 opcodes
opcode = F8;
switch(opcode) {
case 0x0F:
INST_NAME("PALIGNR Gm, Em, Ib");
nextop = F8;
GETGM(q0);
GETEM(q1, 1);
u8 = F8;
if(u8>15) {
VEOR(q0, q0, q0);
} else if(u8>7) {
d0 = fpu_get_scratch(dyn);
VEOR(d0, d0, d0);
VEXT_8(q0, q0, d0, u8-8);
} else {
VEXT_8(q0, q1, q0, u8);
}
break;
default:
DEFAULT;
}
break;
#define GO(GETFLAGS, NO, YES, F) \
READFLAGS(F); \
GETFLAGS; \
@@ -439,7 +415,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MOV32w(gd, 0);
if((nextop&0xC0)==0xC0) {
// EX is an xmm reg
GETEX(q0, 0, 0);
GETEX(q0, 0);
VMOVQDto(x1, q0, 0);
LSRx(x1, x1, 31);
BFIx(gd, x1, 0, 1);
@@ -468,14 +444,14 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0x51:
INST_NAME("SQRTPS Gx, Ex");
nextop = F8;
GETEX(q0, 0, 0);
GETEX(q0, 0);
GETGX_empty(v0);
VFSQRTQS(v0, q0);
break;
case 0x52:
INST_NAME("RSQRTPS Gx, Ex");
nextop = F8;
GETEX(q0, 0, 0);
GETEX(q0, 0);
GETGX_empty(q1);
v0 = fpu_get_scratch(dyn);
// more precise
@@ -491,7 +467,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0x53:
INST_NAME("RCPPS Gx, Ex");
nextop = F8;
GETEX(q0, 0, 0);
GETEX(q0, 0);
GETGX_empty(q1);
if(q0 == q1)
v1 = fpu_get_scratch(dyn);
@@ -505,22 +481,22 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0x54:
INST_NAME("ANDPS Gx, Ex");
nextop = F8;
GETEX(q0, 0, 0);
GETGX(v0, 1);
GETEX(q0, 0);
GETGX(v0);
VANDQ(v0, v0, q0);
break;
case 0x55:
INST_NAME("ANDNPS Gx, Ex");
nextop = F8;
GETEX(q0, 0, 0);
GETGX(v0, 1);
GETEX(q0, 0);
GETGX(v0);
VBICQ(v0, q0, v0);
break;
case 0x56:
INST_NAME("ORPS Gx, Ex");
nextop = F8;
GETEX(q0, 0, 0);
GETGX(v0, 1);
GETEX(q0, 0);
GETGX(v0);
VORRQ(v0, v0, q0);
break;
case 0x57:
@@ -532,65 +508,65 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
q0 = sse_get_reg_empty(dyn, ninst, x1, gd);
VEORQ(q0, q0, q0);
} else {
q0 = sse_get_reg(dyn, ninst, x1, gd, 1);
GETEX(q1, 0, 0);
q0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(q1, 0);
VEORQ(q0, q0, q1);
}
break;
case 0x58:
INST_NAME("ADDPS Gx, Ex");
nextop = F8;
GETEX(q0, 0, 0);
GETGX(v0, 1);
GETEX(q0, 0);
GETGX(v0);
VFADDQS(v0, v0, q0);
break;
case 0x59:
INST_NAME("MULPS Gx, Ex");
nextop = F8;
GETEX(q0, 0, 0);
GETGX(v0, 1);
GETEX(q0, 0);
GETGX(v0);
VFMULQS(v0, v0, q0);
break;
case 0x5A:
INST_NAME("CVTPS2PD Gx, Ex");
nextop = F8;
GETEX(q0, 0, 0);
GETGX(q1, 1);
GETEX(q0, 0);
GETGX(q1);
FCVTL(q1, q0);
break;
case 0x5B:
INST_NAME("CVTDQ2PS Gx, Ex");
nextop = F8;
GETEX(q0, 0, 0);
GETEX(q0, 0);
GETGX_empty(q1);
SCVTQFS(q1, q0);
break;
case 0x5C:
INST_NAME("SUBPS Gx, Ex");
nextop = F8;
GETEX(q0, 0, 0);
GETGX(v0, 1);
GETEX(q0, 0);
GETGX(v0);
VFSUBQS(v0, v0, q0);
break;
case 0x5D:
INST_NAME("MINPS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 0);
GETGX(v0);
GETEX(v1, 0);
VFMINQS(v0, v0, v1);
break;
case 0x5E:
INST_NAME("DIVPS Gx, Ex");
nextop = F8;
GETEX(q0, 0, 0);
GETGX(v0, 1);
GETEX(q0, 0);
GETGX(v0);
VFDIVQS(v0, v0, q0);
break;
case 0x5F:
INST_NAME("MAXPS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 0);
GETGX(v0);
GETEX(v1, 0);
VFMAXQS(v0, v0, v1);
break;
case 0x60:
@@ -625,21 +601,21 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SQXTN_8(d0, q0);
break;
case 0x64:
INST_NAME("PCMPGTB Gm,Em");
INST_NAME("PCMPGTB Gx,Ex");
nextop = F8;
GETGM(v0);
GETEM(v1, 0);
VCMGT_8(v0, v0, v1);
break;
case 0x65:
INST_NAME("PCMPGTW Gm,Em");
INST_NAME("PCMPGTW Gx,Ex");
nextop = F8;
GETGM(v0);
GETEM(v1, 0);
VCMGT_16(v0, v0, v1);
break;
case 0x66:
INST_NAME("PCMPGTD Gm,Em");
INST_NAME("PCMPGTD Gx,Ex");
nextop = F8;
GETGM(v0);
GETEM(v1, 0);
@@ -652,7 +628,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
q0 = fpu_get_scratch(dyn);
VMOVeD(q0, 0, v0, 0);
if(MODREG) {
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, (nextop&7));
v1 = mmx_get_reg(dyn, ninst, x1, (nextop&7));
VMOVeD(q0, 1, v1, 0);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
@@ -702,7 +678,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("MOVD Gm, Ed");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
v0 = mmx_get_reg_empty(dyn, ninst, x3, gd);
if(MODREG) {
ed = xRAX + (nextop&7) + (rex.b<<3);
if(rex.w) {
@@ -711,7 +687,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
FMOVSw(v0, ed);
}
} else {
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
v0 = mmx_get_reg_empty(dyn, ninst, x1, gd);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, 0, 0);
if(rex.w) {
VLDR64_U12(v0, ed, fixedaddress);
@@ -725,11 +701,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
nextop = F8;
GETG;
if(MODREG) {
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7); // no rex.b on MMX
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
v1 = mmx_get_reg(dyn, ninst, x1, nextop&7); // no rex.b on MMX
v0 = mmx_get_reg_empty(dyn, ninst, x1, gd);
VMOVeD(v0, 0, v1, 0);
} else {
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
v0 = mmx_get_reg_empty(dyn, ninst, x1, gd);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
VLDR64_U12(v0, ed, fixedaddress);
}
@@ -740,8 +716,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
gd = (nextop&0x38)>>3;
if(MODREG) {
u8 = F8;
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, (nextop&7));
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
v1 = mmx_get_reg(dyn, ninst, x1, (nextop&7));
v0 = mmx_get_reg_empty(dyn, ninst, x1, gd);
if(u8==0x4E) {
if(v0==v1) {
VEXT_8(v0, v0, v0, 4); // Swap Up/Lower 32bits parts
@@ -797,7 +773,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
VTBL1_8(v0, v1, d0);
}
} else {
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
v0 = mmx_get_reg_empty(dyn, ninst, x1, gd);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 1);
u8 = F8;
if (u8) {
@@ -971,7 +947,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0x77:
INST_NAME("EMMS");
// empty MMX, FPU now usable
mmx_purgecache(dyn, ninst, 0, x1);
mmx_purgecache(dyn, ninst, x1);
/*emu->top = 0;
emu->fpu_stack = 0;*/ //TODO: Check if something is needed here?
break;
@@ -1002,7 +978,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
nextop = F8;
GETGM(v0);
if(MODREG) {
v1 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, nextop&7);
v1 = mmx_get_reg_empty(dyn, ninst, x1, nextop&7);
VMOV(v1, v0);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
@@ -1011,29 +987,22 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
#define GO(GETFLAGS, NO, YES, F) \
READFLAGS(F); \
i32_ = F32S; \
BARRIER(BARRIER_MAYBE); \
JUMP(addr+i32_, 1); \
GETFLAGS; \
if(dyn->insts[ninst].x64.jmp_insts==-1 || \
CHECK_CACHE()) { \
/* out of the block */ \
i32 = dyn->insts[ninst].epilog-(dyn->native_size); \
Bcond(NO, i32); \
if(dyn->insts[ninst].x64.jmp_insts==-1) { \
if(!dyn->insts[ninst].x64.barrier) \
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
jump_to_next(dyn, addr+i32_, 0, ninst); \
} else { \
fpuCacheTransform(dyn, ninst, x1, x2, x3); \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
B(i32); \
} \
} else { \
/* inside the block */ \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
Bcond(YES, i32); \
READFLAGS(F); \
i32_ = F32S; \
BARRIER(2); \
JUMP(addr+i32_);\
GETFLAGS; \
if(dyn->insts) { \
if(dyn->insts[ninst].x64.jmp_insts==-1) { \
/* out of the block */ \
i32 = dyn->insts[ninst+1].address-(dyn->arm_size); \
Bcond(NO, i32); \
jump_to_next(dyn, addr+i32_, 0, ninst); \
} else { \
/* inside the block */ \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->arm_size); \
Bcond(YES, i32); \
} \
}
GOCOND(0x80, "J", "Id");
@@ -1188,7 +1157,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0:
INST_NAME("FXSAVE Ed");
MESSAGE(LOG_DUMP, "Need Optimization\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
fpu_purgecache(dyn, ninst, x1, x2, x3);
if(MODREG) {
DEFAULT;
} else {
@@ -1200,7 +1169,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 1:
INST_NAME("FXRSTOR Ed");
MESSAGE(LOG_DUMP, "Need Optimization\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
fpu_purgecache(dyn, ninst, x1, x2, x3);
if(MODREG) {
DEFAULT;
} else {
@@ -1544,29 +1513,29 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xC2:
INST_NAME("CMPPS Gx, Ex, Ib");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 1);
GETGX(v0);
GETEX(v1, 1);
u8 = F8;
switch(u8&7) {
// the inversion of the params in the comparison is there to handle NaN the same way SSE does
case 0: VFCMEQQS(v0, v0, v1); break; // Equal
case 1: VFCMGTQS(v0, v1, v0); break; // Less than
case 2: VFCMGEQS(v0, v1, v0); break; // Less or equal
case 3: VFCMEQQS(v0, v0, v0);
case 0: FCMEQQS(v0, v0, v1); break; // Equal
case 1: FCMGTQS(v0, v1, v0); break; // Less than
case 2: FCMGEQS(v0, v1, v0); break; // Less or equal
case 3: FCMEQQS(v0, v0, v0);
if(v0!=v1) {
q0 = fpu_get_scratch(dyn);
VFCMEQQS(q0, v1, v1);
FCMEQQS(q0, v1, v1);
VANDQ(v0, v0, q0);
}
VMVNQ(v0, v0);
break; // NaN (NaN is not equal to himself)
case 4: VFCMEQQS(v0, v0, v1); VMVNQ(v0, v0); break; // Not Equal (or unordered on ARM, not on X86...)
case 5: VFCMGTQS(v0, v1, v0); VMVNQ(v0, v0); break; // Greater or equal or unordered
case 6: VFCMGEQS(v0, v1, v0); VMVNQ(v0, v0); break; // Greater or unordered
case 7: VFCMEQQS(v0, v0, v0);
case 4: FCMEQQS(v0, v0, v1); VMVNQ(v0, v0); break; // Not Equal (or unordered on ARM, not on X86...)
case 5: FCMGTQS(v0, v1, v0); VMVNQ(v0, v0); break; // Greater or equal or unordered
case 6: FCMGEQS(v0, v1, v0); VMVNQ(v0, v0); break; // Greater or unordered
case 7: FCMEQQS(v0, v0, v0);
if(v0!=v1) {
q0 = fpu_get_scratch(dyn);
VFCMEQQS(q0, v1, v1);
FCMEQQS(q0, v1, v1);
VANDQ(v0, v0, q0);
}
break; // not NaN
@@ -1614,7 +1583,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xC6:
INST_NAME("SHUFPS Gx, Ex, Ib");
nextop = F8;
GETGX(v0, 1);
GETGX(v0);
if(!MODREG)
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 1);
u8 = F8;
@@ -1625,7 +1594,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
// second two from Ex
if(MODREG) {
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
for(int i=2; i<4; ++i) {
VMOVeS(d0, i, v1, (u8>>(i*2)&3));
}
@@ -1777,7 +1746,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if((nextop&0xC0)==0xC0) {
DEFAULT;
} else {
v0 = mmx_get_reg(dyn, ninst, x1, x2, x3, gd);
v0 = mmx_get_reg(dyn, ninst, x1, gd);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
VSTR64_U12(v0, ed, fixedaddress);
}
@@ -1825,10 +1794,10 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
gd = ((nextop&0x38)>>3);
if(MODREG && ((nextop&7))==gd) {
// special case for PXOR Gx, Gx
q0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
q0 = mmx_get_reg_empty(dyn, ninst, x1, gd);
VEOR(q0, q0, q0);
} else {
q0 = mmx_get_reg(dyn, ninst, x1, x2, x3, gd);
q0 = mmx_get_reg(dyn, ninst, x1, gd);
GETEM(q1, 0);
VEOR(q0, q0, q1);
}
@@ -15,10 +15,10 @@
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64.h"
#include "dynarec_arm64_private.h"
#include "arm64_printer.h"
#include "dynarec_arm64_helper.h"
#include "dynarec_arm64_functions.h"
@@ -31,10 +31,10 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
uint8_t opcode = F8;
uint8_t nextop;
uint8_t u8;
uint8_t gd, ed, eb1, eb2, gb1, gb2;
uint8_t gd, ed, eb1, eb2;
uint8_t wback, wb1, wb2, wb;
int64_t i64, j64;
int v0, v1;
int v0;
int q0;
int d0;
int64_t fixedaddress;
@@ -42,13 +42,10 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MAYUSE(eb2);
MAYUSE(wb1);
MAYUSE(wb2);
MAYUSE(gb1);
MAYUSE(gb2);
MAYUSE(j64);
MAYUSE(d0);
MAYUSE(q0);
MAYUSE(v0);
MAYUSE(v1);
while((opcode==0xF2) || (opcode==0xF3)) {
rep = opcode-0xF1;
@@ -85,8 +82,8 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GETG;
if(MODREG) {
ed = (nextop&7)+ (rex.b<<3);
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
d0 = sse_get_reg(dyn, ninst, x1, ed, 0);
v0 = sse_get_reg(dyn, ninst, x1, gd);
d0 = sse_get_reg(dyn, ninst, x1, ed);
VMOVeD(v0, 0, d0, 0);
} else {
grab_segdata(dyn, addr, ninst, x4, seg);
@@ -101,8 +98,8 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
nextop = F8;
GETG;
if(MODREG) {
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
v0 = sse_get_reg(dyn, ninst, x1, gd);
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
VMOVeS(v0, 0, q0, 0);
} else {
grab_segdata(dyn, addr, ninst, x4, seg);
@@ -118,30 +115,14 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 0x11:
switch(rep) {
case 0:
INST_NAME("MOVUPS Ex,Gx");
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
if(MODREG) {
ed = (nextop&7)+(rex.b<<3);
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
VMOVQ(v1, v0);
} else {
grab_segdata(dyn, addr, ninst, x4, seg);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
ADDx_REG(x4, x4, ed);
VSTR128_U12(v0, x4, fixedaddress);
}
break;
case 1:
INST_NAME("MOVSD Ex, Gx");
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
v0 = sse_get_reg(dyn, ninst, x1, gd);
if(MODREG) {
ed = (nextop&7)+ (rex.b<<3);
d0 = sse_get_reg(dyn, ninst, x1, ed, 1);
d0 = sse_get_reg(dyn, ninst, x1, ed);
VMOVeD(d0, 0, v0, 0);
} else {
grab_segdata(dyn, addr, ninst, x4, seg);
@@ -154,9 +135,9 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("MOVSS Ex, Gx");
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
v0 = sse_get_reg(dyn, ninst, x1, gd);
if(MODREG) {
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 1);
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
VMOVeS(q0, 0, v0, 0);
} else {
grab_segdata(dyn, addr, ninst, x4, seg);
@@ -170,29 +151,6 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
break;
case 0x6F:
switch(rep) {
case 2:
INST_NAME("MOVDQU Gx,Ex");// no alignment constraint on NEON here, so same as MOVDQA
nextop = F8;
GETG;
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
if(MODREG) {
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
VMOVQ(v0, v1);
} else {
grab_segdata(dyn, addr, ninst, x4, seg);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
ADDx_REG(x4, x4, ed);
VLDR128_U12(v0, ed, fixedaddress);
}
break;
default:
DEFAULT;
}
break;
case 0xAF:
INST_NAME("IMUL Gd, Ed");
SETFLAGS(X_ALL, SF_PENDING);
@@ -226,27 +184,6 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
break;
case 0xB6:
INST_NAME("MOVZX Gd, Eb");
nextop = F8;
grab_segdata(dyn, addr, ninst, x4, seg);
GETGD;
if(MODREG) {
if(rex.rex) {
eb1 = xRAX+(nextop&7)+(rex.b<<3);
eb2 = 0; \
} else {
ed = (nextop&7);
eb1 = xRAX+(ed&3); // Ax, Cx, Dx or Bx
eb2 = (ed&4)>>2; // L or H
}
UBFXxw(gd, eb1, eb2*8, 8);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
LDRB_REG(gd, ed, x4);
}
break;
default:
DEFAULT;
}
@@ -272,49 +209,16 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
emit_cmp32(dyn, ninst, rex, ed, gd, x3, x4, x5);
break;
case 0x3B:
INST_NAME("CMP Gd, Seg:Ed");
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_segdata(dyn, addr, ninst, x4, seg);
nextop = F8;
GETGD;
GETEDO(x4, 0);
emit_cmp32(dyn, ninst, rex, gd, ed, x3, x4, x5);
break;
case 0x63:
INST_NAME("MOVSXD Gd, Ed");
nextop = F8;
GETGD;
if(rex.w) {
if(MODREG) { // reg <= reg
SXTWx(gd, xRAX+(nextop&7)+(rex.b<<3));
} else { // mem <= reg
grab_segdata(dyn, addr, ninst, x4, seg);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
LDRSW_REG(gd, ed, x4);
}
} else {
if(MODREG) { // reg <= reg
MOVw_REG(gd, xRAX+(nextop&7)+(rex.b<<3));
} else { // mem <= reg
grab_segdata(dyn, addr, ninst, x4, seg);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
LDRw_REG(gd, ed, x4);
}
}
break;
case 0x66:
addr = dynarec64_6664(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
break;
case 0x80:
nextop = F8;
grab_segdata(dyn, addr, ninst, x1, seg);
switch((nextop>>3)&7) {
case 0: //ADD
INST_NAME("ADD Eb, Ib");
grab_segdata(dyn, addr, ninst, x1, seg);
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEBO(x1, 1);
u8 = F8;
@@ -323,7 +227,6 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 1: //OR
INST_NAME("OR Eb, Ib");
grab_segdata(dyn, addr, ninst, x1, seg);
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEBO(x1, 1);
u8 = F8;
@@ -332,7 +235,6 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 2: //ADC
INST_NAME("ADC Eb, Ib");
grab_segdata(dyn, addr, ninst, x1, seg);
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEBO(x1, 1);
@@ -342,7 +244,6 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 3: //SBB
INST_NAME("SBB Eb, Ib");
grab_segdata(dyn, addr, ninst, x1, seg);
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEBO(x1, 1);
@@ -352,7 +253,6 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 4: //AND
INST_NAME("AND Eb, Ib");
grab_segdata(dyn, addr, ninst, x1, seg);
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEBO(x1, 1);
u8 = F8;
@@ -361,7 +261,6 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 5: //SUB
INST_NAME("SUB Eb, Ib");
grab_segdata(dyn, addr, ninst, x1, seg);
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEBO(x1, 1);
u8 = F8;
@@ -370,7 +269,6 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 6: //XOR
INST_NAME("XOR Eb, Ib");
grab_segdata(dyn, addr, ninst, x1, seg);
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEBO(x1, 1);
u8 = F8;
@@ -379,7 +277,6 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 7: //CMP
INST_NAME("CMP Eb, Ib");
grab_segdata(dyn, addr, ninst, x1, seg);
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEBO(x1, 1);
u8 = F8;
@@ -472,40 +369,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
}
break;
case 0x8A:
INST_NAME("MOV Gb, Eb");
nextop = F8;
if(rex.rex) {
gb1 = gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3);
gb2=0;
} else {
gd = (nextop&0x38)>>3;
gb1 = xRAX+(gd&3);
gb2 = ((gd&4)>>2);
}
if(MODREG) {
if(rex.rex) {
wback = xRAX+(nextop&7)+(rex.b<<3);
wb2 = 0;
} else {
wback = (nextop&7);
wb2 = (wback>>2);
wback = xRAX+(wback&3);
}
if(wb2) {
UBFXw(x4, wback, wb2*8, 8);
ed = x4;
} else {
ed = wback;
}
} else {
grab_segdata(dyn, addr, ninst, x4, seg);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, 0, 0);
LDRB_REG(x4, wback, x4);
ed = x4;
}
BFIx(gb1, ed, gb2*8, 8);
break;
case 0x89:
INST_NAME("MOV Seg:Ed, Gd");
grab_segdata(dyn, addr, ninst, x4, seg);
@@ -577,14 +441,14 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
switch((nextop>>3)&7) {
case 0:
INST_NAME("ROL Ed, 1");
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
SETFLAGS(X_OF|X_CF, SF_SUBSET);
GETEDO(x6, 0);
emit_rol32c(dyn, ninst, rex, ed, 1, x3, x4);
WBACKO(x6);
break;
case 1:
INST_NAME("ROR Ed, 1");
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
SETFLAGS(X_OF|X_CF, SF_SUBSET);
GETEDO(x6, 0);
emit_ror32c(dyn, ninst, rex, ed, 1, x3, x4);
WBACKO(x6);
@@ -853,7 +717,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MOVw_REG(xRAX, x2);
MOVw_REG(xRDX, x4);
} else {
if(ninst
if(ninst && dyn->insts
&& dyn->insts[ninst-1].x64.addr
&& *(uint8_t*)(dyn->insts[ninst-1].x64.addr)==0x31
&& *(uint8_t*)(dyn->insts[ninst-1].x64.addr+1)==0xD2) {
@@ -923,21 +787,22 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
switch((nextop>>3)&7) {
case 0: // INC Ed
INST_NAME("INC Ed");
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
GETEDO(x6, 0);
emit_inc32(dyn, ninst, rex, ed, x3, x4);
WBACKO(x6);
break;
case 1: //DEC Ed
INST_NAME("DEC Ed");
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
GETEDO(x6, 0);
emit_dec32(dyn, ninst, rex, ed, x3, x4);
WBACKO(x6);
break;
case 2: // CALL Ed
INST_NAME("CALL Ed");
PASS2IF(((ninst && dyn->insts[ninst-1].x64.set_flags)
PASS2IF(dyn->insts &&
((ninst && dyn->insts[ninst-1].x64.set_flags)
|| ((ninst>1) && dyn->insts[ninst-2].x64.set_flags)), 1)
{
READFLAGS(X_PEND); // that's suspicious
@@ -945,12 +810,13 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET); //Hack to put flag in "don't care" state
}
GETEDOx(x6, 0);
BARRIER(BARRIER_FLOAT);
BARRIER(1);
BARRIER_NEXT(1);
if(!dyn->insts || ninst==dyn->size-1) {
*need_epilog = 0;
*ok = 0;
}
GETIP_(addr);
GETIP(addr);
PUSH1(xRIP);
jump_to_next(dyn, 0, ed, ninst);
break;
@@ -15,10 +15,10 @@
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64.h"
#include "dynarec_arm64_private.h"
#include "arm64_printer.h"
#include "dynarec_arm64_helper.h"
#include "dynarec_arm64_functions.h"
@@ -328,25 +328,6 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GWBACK;
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 use regular conditional jump
return dynarec64_00(dyn, addr-1, ip, ninst, rex, rep, ok, need_epilog);
case 0x81:
case 0x83:
nextop = F8;
@@ -867,14 +848,14 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
switch((nextop>>3)&7) {
case 0:
INST_NAME("INC Ew");
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
GETEW(x1, 0);
emit_inc16(dyn, ninst, x1, x2, x4);
EWBACK;
break;
case 1:
INST_NAME("DEC Ew");
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
GETEW(x1, 0);
emit_dec16(dyn, ninst, x1, x2, x4);
EWBACK;
File diff suppressed because it is too large. Load diff
@@ -15,10 +15,10 @@
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64.h"
#include "dynarec_arm64_private.h"
#include "arm64_printer.h"
#include "dynarec_arm64_helper.h"
#include "dynarec_arm64_functions.h"
@@ -56,7 +56,7 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
INST_NAME("MOVQ Ex, Gx");
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
v0 = sse_get_reg(dyn, ninst, x1, gd);
if(MODREG) {
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
FMOVD(v1, v0);
@@ -15,20 +15,20 @@
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64.h"
#include "dynarec_arm64_private.h"
#include "arm64_printer.h"
#include "dynarec_arm64_helper.h"
#include "dynarec_arm64_functions.h"
#define GETGX(a, w) \
#define GETGX(a) \
gd = ((nextop&0x38)>>3)+(rex.r<<3); \
a = sse_get_reg(dyn, ninst, x1, gd, w)
a = sse_get_reg(dyn, ninst, x1, gd)
#define GETGM(a) \
gd = ((nextop&0x38)>>3); \
a = mmx_get_reg(dyn, ninst, x1, x2, x3, gd)
a = mmx_get_reg(dyn, ninst, x1, gd)
#define GETGm gd = ((nextop&0x38)>>3)
@@ -78,9 +78,9 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(opcode==0x2F) {INST_NAME("COMISS Gx, Ex");} else {INST_NAME("UCOMISS Gx, Ex");}
SETFLAGS(X_ALL, SF_SET);
nextop = F8;
GETGX(v0, 0);
GETGX(v0);
if(MODREG) {
s0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
s0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
} else {
s0 = fpu_get_scratch(dyn);
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
@@ -96,11 +96,11 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
nextop = F8;
GETGm;
if(MODREG) {
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7); // no rex.b on MMX
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
v1 = mmx_get_reg(dyn, ninst, x1, nextop&7); // no rex.b on MMX
v0 = mmx_get_reg_empty(dyn, ninst, x1, gd);
VMOVeD(v0, 0, v1, 0);
} else {
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
v0 = mmx_get_reg_empty(dyn, ninst, x1, gd);
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
VLDR64_U12(v0, ed, fixedaddress);
}
@@ -111,7 +111,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
nextop = F8;
GETGM(v0);
if(MODREG) {
v1 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, nextop&7);
v1 = mmx_get_reg_empty(dyn, ninst, x1, nextop&7);
VMOV(v1, v0);
} else {
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
@@ -156,7 +156,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
switch((nextop>>3)&7) {
case 0:
INST_NAME("ROL Ed, Ib");
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
SETFLAGS(X_OF|X_CF, SF_SUBSET);
GETED32(1);
u8 = (F8)&(rex.w?0x3f:0x1f);
emit_rol32c(dyn, ninst, rex, ed, u8, x3, x4);
@@ -164,7 +164,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 1:
INST_NAME("ROR Ed, Ib");
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
SETFLAGS(X_OF|X_CF, SF_SUBSET);
GETED32(1);
u8 = (F8)&(rex.w?0x3f:0x1f);
emit_ror32c(dyn, ninst, rex, ed, u8, x3, x4);
@@ -224,27 +224,20 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
break;
#define GO(NO, YES) \
BARRIER(BARRIER_MAYBE); \
JUMP(addr+i8, 1); \
if(dyn->insts[ninst].x64.jmp_insts==-1 || \
CHECK_CACHE()) { \
/* out of the block */ \
i32 = dyn->insts[ninst].epilog-(dyn->native_size); \
Bcond(NO, i32); \
if(dyn->insts[ninst].x64.jmp_insts==-1) { \
if(!dyn->insts[ninst].x64.barrier) \
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
jump_to_next(dyn, addr+i8, 0, ninst); \
} else { \
fpuCacheTransform(dyn, ninst, x1, x2, x3); \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);\
B(i32); \
} \
} else { \
/* inside the block */ \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
Bcond(YES, i32); \
#define GO(NO, YES) \
BARRIER(2); \
JUMP(addr+i8);\
if(dyn->insts) { \
if(dyn->insts[ninst].x64.jmp_insts==-1) { \
/* out of the block */ \
i32 = dyn->insts[ninst+1].address-(dyn->arm_size); \
Bcond(NO, i32); \
jump_to_next(dyn, addr+i8, 0, ninst); \
} else { \
/* inside the block */ \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->arm_size); \
Bcond(YES, i32); \
} \
}
case 0xE0:
INST_NAME("LOOPNZ (32bits)");
@@ -15,11 +15,11 @@
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "emu/x87emu_private.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64.h"
#include "dynarec_arm64_private.h"
#include "arm64_printer.h"
#include "emu/x87emu_private.h"
#include "dynarec_arm64_helper.h"
#include "dynarec_arm64_functions.h"
@@ -48,13 +48,9 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xC6:
case 0xC7:
INST_NAME("FADD ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FADDS(v1, v1, v2);
} else {
FADDD(v1, v1, v2);
}
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FADDD(v1, v1, v2);
break;
case 0xC8:
case 0xC9:
@@ -65,13 +61,9 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xCE:
case 0xCF:
INST_NAME("FMUL ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FMULS(v1, v1, v2);
} else {
FMULD(v1, v1, v2);
}
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FMULD(v1, v1, v2);
break;
case 0xD0:
case 0xD1:
@@ -82,13 +74,9 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xD6:
case 0xD7:
INST_NAME("FCOM ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
}
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FCMPD(v1, v2);
FCOM(x1, x2, x3);
break;
case 0xD8:
@@ -100,15 +88,11 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xDE:
case 0xDF:
INST_NAME("FCOMP ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
}
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FCMPD(v1, v2);
FCOM(x1, x2, x3);
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst);
break;
case 0xE0:
case 0xE1:
@@ -119,13 +103,9 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xE6:
case 0xE7:
INST_NAME("FSUB ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FSUBS(v1, v1, v2);
} else {
FSUBD(v1, v1, v2);
}
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FSUBD(v1, v1, v2);
break;
case 0xE8:
case 0xE9:
@@ -136,13 +116,9 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xEE:
case 0xEF:
INST_NAME("FSUBR ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FSUBS(v1, v2, v1);
} else {
FSUBD(v1, v2, v1);
}
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FSUBD(v1, v2, v1);
break;
case 0xF0:
case 0xF1:
@@ -153,13 +129,9 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xF6:
case 0xF7:
INST_NAME("FDIV ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FDIVS(v1, v1, v2);
} else {
FDIVD(v1, v1, v2);
}
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FDIVD(v1, v1, v2);
break;
case 0xF8:
case 0xF9:
@@ -170,123 +142,87 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xFE:
case 0xFF:
INST_NAME("FDIVR ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FDIVS(v1, v2, v1);
} else {
FDIVD(v1, v2, v1);
}
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FDIVD(v1, v2, v1);
break;
default:
switch((nextop>>3)&7) {
case 0:
INST_NAME("FADD ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
s0 = fpu_get_scratch(dyn);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
VLDR32_U12(s0, ed, fixedaddress);
if(ST_IS_F(0)) {
FADDS(v1, v1, s0);
} else {
FCVT_D_S(s0, s0);
FADDD(v1, v1, s0);
}
FCVT_D_S(s0, s0);
FADDD(v1, v1, s0);
break;
case 1:
INST_NAME("FMUL ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
s0 = fpu_get_scratch(dyn);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
VLDR32_U12(s0, ed, fixedaddress);
if(ST_IS_F(0)) {
FMULS(v1, v1, s0);
} else {
FCVT_D_S(s0, s0);
FMULD(v1, v1, s0);
}
FCVT_D_S(s0, s0);
FMULD(v1, v1, s0);
break;
case 2:
INST_NAME("FCOM ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
s0 = fpu_get_scratch(dyn);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
VLDR32_U12(s0, ed, fixedaddress);
if(ST_IS_F(0)) {
FCMPS(v1, s0);
} else {
FCVT_D_S(s0, s0);
FCMPD(v1, s0);
}
FCVT_D_S(s0, s0);
FCMPD(v1, s0);
FCOM(x1, x2, x3);
break;
case 3:
INST_NAME("FCOMP ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
s0 = fpu_get_scratch(dyn);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
VLDR32_U12(s0, ed, fixedaddress);
if(ST_IS_F(0)) {
FCMPS(v1, s0);
} else {
FCVT_D_S(s0, s0);
FCMPD(v1, s0);
}
FCVT_D_S(s0, s0);
FCMPD(v1, s0);
FCOM(x1, x2, x3);
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst);
break;
case 4:
INST_NAME("FSUB ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
s0 = fpu_get_scratch(dyn);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
VLDR32_U12(s0, ed, fixedaddress);
if(ST_IS_F(0)) {
FSUBS(v1, v1, s0);
} else {
FCVT_D_S(s0, s0);
FSUBD(v1, v1, s0);
}
FCVT_D_S(s0, s0);
FSUBD(v1, v1, s0);
break;
case 5:
INST_NAME("FSUBR ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
s0 = fpu_get_scratch(dyn);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
VLDR32_U12(s0, ed, fixedaddress);
if(ST_IS_F(0)) {
FSUBS(v1, s0, v1);
} else {
FCVT_D_S(s0, s0);
FSUBD(v1, s0, v1);
}
FCVT_D_S(s0, s0);
FSUBD(v1, s0, v1);
break;
case 6:
INST_NAME("FDIV ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
s0 = fpu_get_scratch(dyn);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
VLDR32_U12(s0, ed, fixedaddress);
if(ST_IS_F(0)) {
FDIVS(v1, v1, s0);
} else {
FCVT_D_S(s0, s0);
FDIVD(v1, v1, s0);
}
FCVT_D_S(s0, s0);
FDIVD(v1, v1, s0);
break;
case 7:
INST_NAME("FDIVR ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
s0 = fpu_get_scratch(dyn);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
VLDR32_U12(s0, ed, fixedaddress);
if(ST_IS_F(0)) {
FDIVS(v1, s0, v1);
} else {
FCVT_D_S(s0, s0);
FDIVD(v1, s0, v1);
}
FCVT_D_S(s0, s0);
FDIVD(v1, s0, v1);
break;
default:
DEFAULT;
@@ -15,11 +15,11 @@
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "emu/x87emu_private.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64.h"
#include "dynarec_arm64_private.h"
#include "arm64_printer.h"
#include "emu/x87emu_private.h"
#include "dynarec_arm64_helper.h"
#include "dynarec_arm64_functions.h"
@@ -50,18 +50,12 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xC6:
case 0xC7:
INST_NAME("FLD STx");
v2 = x87_do_push(dyn, ninst, x1, X87_ST(nextop&7));
v1 = x87_get_st(dyn, ninst, x1, x2, (nextop&7)+1, X87_COMBINE(0, (nextop&7)+1));
if(ST_IS_F(0)) {
FMOVS(v2, v1);
} else {
FMOVD(v2, v1);
}
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
v2 = x87_do_push(dyn, ninst);
FMOVD(v2, v1);
break;
case 0xC8:
INST_NAME("FXCH ST0");
break;
case 0xC9:
case 0xCA:
case 0xCB:
@@ -71,8 +65,11 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xCF:
INST_NAME("FXCH STx");
// swap the cache value, not the double value itself :p
x87_swapreg(dyn, ninst, x1, x2, 0, nextop&7);
// should set C1 to 0
i1 = x87_get_cache(dyn, ninst, x1, x2, nextop&7);
i2 = x87_get_cache(dyn, ninst, x1, x2, 0);
i3 = dyn->x87cache[i1];
dyn->x87cache[i1] = dyn->x87cache[i2];
dyn->x87cache[i2] = i3;
break;
case 0xD0:
@@ -81,31 +78,19 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xE0:
INST_NAME("FCHS");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
if(ST_IS_F(0)) {
FNEGS(v1, v1);
} else {
FNEGD(v1, v1);
}
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
FNEGD(v1, v1);
break;
case 0xE1:
INST_NAME("FABS");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
if(ST_IS_F(0)) {
FABSS(v1, v1);
} else {
FABSD(v1, v1);
}
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
FABSD(v1, v1);
break;
case 0xE4:
INST_NAME("FTST");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
if(ST_IS_F(0)) {
FCMPS_0(v1);
} else {
FCMPD_0(v1);
}
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
FCMPD_0(v1);
FCOM(x1, x2, x3); // same flags...
break;
case 0xE5:
@@ -117,44 +102,64 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xE8:
INST_NAME("FLD1");
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
if(ST_IS_F(0)) {
FMOVS_8(v1, 0b01110000);
} else {
FMOVD_8(v1, 0b01110000);
}
v1 = x87_do_push(dyn, ninst);
FTABLE64(v1, 1.0);
break;
case 0xE9:
INST_NAME("FLDL2T");
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
v1 = x87_do_push(dyn, ninst);
FTABLE64(v1, L2T);
break;
case 0xEA:
INST_NAME("FLDL2E");
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
v1 = x87_do_push(dyn, ninst);
FTABLE64(v1, L2E);
break;
case 0xEB:
INST_NAME("FLDPI");
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
v1 = x87_do_push(dyn, ninst);
FTABLE64(v1, PI);
break;
case 0xEC:
INST_NAME("FLDLG2");
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
v1 = x87_do_push(dyn, ninst);
FTABLE64(v1, LG2);
break;
case 0xED:
INST_NAME("FLDLN2");
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
v1 = x87_do_push(dyn, ninst);
FTABLE64(v1, LN2);
break;
case 0xEE:
INST_NAME("FLDZ");
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
VEOR(v1, v1, v1);
v1 = x87_do_push(dyn, ninst);
FTABLE64(v1, 0.0);
break;
case 0xFA:
INST_NAME("FSQRT");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
FSQRTD(v1, v1);
break;
case 0xFC:
INST_NAME("FRNDINT");
MESSAGE(LOG_DUMP, "Need Optimization\n");
// use C helper for now, nothing staightforward is available
x87_forget(dyn, ninst, x1, x2, 0);
CALL(arm_frndint, -1);
/*
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
VCMP_F64_0(v1);
VMRS_APSR();
B_NEXT(cVS); // Unordered, skip
B_NEXT(cEQ); // Zero, skip
u8 = x87_setround(dyn, ninst, x1, x2, x3);
VCVT_S32_F64(x1, v1); // limit to 32bits....
VCVT_F64_S32(v1, x1);
x87_restoreround(dyn, ninst, u8);
*/
break;
case 0xF0:
INST_NAME("F2XM1");
MESSAGE(LOG_DUMP, "Need Optimization\n");
@@ -167,19 +172,15 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(arm_fyl2x, -1);
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst);
break;
case 0xF2:
INST_NAME("FPTAN");
INST_NAME("FTAN");
MESSAGE(LOG_DUMP, "Need Optimization\n");
x87_forget(dyn, ninst, x1, x2, 0);
CALL(arm_ftan, -1);
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
if(ST_IS_F(0)) {
FMOVS_8(v1, 0b01110000);
} else {
FMOVD_8(v1, 0b01110000);
}
v1 = x87_do_push(dyn, ninst);
FTABLE64(v1, 1.0);
break;
case 0xF3:
INST_NAME("FPATAN");
@@ -187,7 +188,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(arm_fpatan, -1);
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst);
break;
case 0xF4:
INST_NAME("FXTRACT");
@@ -205,7 +206,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 0xF6:
INST_NAME("FDECSTP");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
fpu_purgecache(dyn, ninst, x1, x2, x3);
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
SUBw_U12(x2, x2, 1);
ANDw_mask(x2, x2, 0, 2); //mask=7
@@ -213,7 +214,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 0xF7:
INST_NAME("FINCSTP");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
fpu_purgecache(dyn, ninst, x1, x2, x3);
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
ADDw_U12(x2, x2, 1);
ANDw_mask(x2, x2, 0, 2); //mask=7
@@ -232,16 +233,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(arm_fyl2xp1, -1);
x87_do_pop(dyn, ninst, x3);
break;
case 0xFA:
INST_NAME("FSQRT");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
if(ST_IS_F(0)) {
FSQRTS(v1, v1);
} else {
FSQRTD(v1, v1);
}
x87_do_pop(dyn, ninst);
break;
case 0xFB:
INST_NAME("FSINCOS");
@@ -250,24 +242,6 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
x87_forget(dyn, ninst, x1, x2, 1);
CALL(arm_fsincos, -1);
break;
case 0xFC:
INST_NAME("FRNDINT");
MESSAGE(LOG_DUMP, "Need Optimization\n");
// use C helper for now, nothing staightforward is available
x87_forget(dyn, ninst, x1, x2, 0);
CALL(arm_frndint, -1);
/*
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
VCMP_F64_0(v1);
VMRS_APSR();
B_NEXT(cVS); // Unordered, skip
B_NEXT(cEQ); // Zero, skip
u8 = x87_setround(dyn, ninst, x1, x2, x3);
VCVT_S32_F64(x1, v1); // limit to 32bits....
VCVT_F64_S32(v1, x1);
x87_restoreround(dyn, ninst, u8);
*/
break;
case 0xFD:
INST_NAME("FSCALE");
MESSAGE(LOG_DUMP, "Need Optimization\n");
@@ -314,46 +288,33 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
switch((nextop>>3)&7) {
case 0:
INST_NAME("FLD ST0, float[ED]");
v1 = x87_do_push(dyn, ninst, x1, box64_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
if(ST_IS_F(0))
s0 = v1;
else
s0 = fpu_get_scratch(dyn);
v1 = x87_do_push(dyn, ninst);
s0 = fpu_get_scratch(dyn);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
VLDR32_U12(s0, ed, fixedaddress);
if(!ST_IS_F(0)) {
FCVT_D_S(v1, s0);
}
FCVT_D_S(v1, s0);
break;
case 2:
INST_NAME("FST float[ED], ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
if(ST_IS_F(0))
s0 = v1;
else {
s0 = fpu_get_scratch(dyn);
FCVT_S_D(s0, v1);
}
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
s0 = fpu_get_scratch(dyn);
FCVT_S_D(s0, v1);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
VSTR32_U12(s0, ed, fixedaddress);
break;
case 3:
INST_NAME("FSTP float[ED], ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
if(ST_IS_F(0))
s0 = v1;
else {
s0 = fpu_get_scratch(dyn);
FCVT_S_D(s0, v1);
}
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
s0 = fpu_get_scratch(dyn);
FCVT_S_D(s0, v1);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
VSTR32_U12(s0, ed, fixedaddress);
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst);
break;
case 4:
INST_NAME("FLDENV Ed");
MESSAGE(LOG_DUMP, "Need Optimization\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
fpu_purgecache(dyn, ninst, x1, x2, x3); // maybe only x87, not SSE?
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
if(ed!=x1) {
MOVx_REG(x1, ed);
@@ -371,7 +332,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 6:
INST_NAME("FNSTENV Ed");
MESSAGE(LOG_DUMP, "Need Optimization\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
fpu_purgecache(dyn, ninst, x1, x2, x3); // maybe only x87, not SSE?
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
if(ed!=x1) {
MOVx_REG(x1, ed);
@@ -15,11 +15,11 @@
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "emu/x87emu_private.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64.h"
#include "dynarec_arm64_private.h"
#include "arm64_printer.h"
#include "emu/x87emu_private.h"
#include "dynarec_arm64_helper.h"
#include "dynarec_arm64_functions.h"
@@ -53,14 +53,10 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xC7:
INST_NAME("FCMOVNB ST0, STx");
READFLAGS(X_CF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
TSTw_mask(xFlags, 0, 0); //mask=1<<F_CF
if(ST_IS_F(0)) {
FCSELS(v1, v2, v1, cEQ);
} else {
FCSELD(v1, v2, v1, cEQ); // F_CF==0
}
FCSELD(v1, v2, v1, cEQ); // F_CF==0
break;
case 0xC8:
case 0xC9:
@@ -72,14 +68,10 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xCF:
INST_NAME("FCMOVNE ST0, STx");
READFLAGS(X_ZF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
TSTw_mask(xFlags, 0b011010, 0); //mask=1<<F_ZF
if(ST_IS_F(0)) {
FCSELS(v1, v2, v1, cEQ);
} else {
FCSELD(v1, v2, v1, cEQ); // F_ZF==0
}
FCSELD(v1, v2, v1, cEQ); // F_ZF==0
break;
case 0xD0:
case 0xD1:
@@ -91,15 +83,11 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xD7:
INST_NAME("FCMOVNBE ST0, STx");
READFLAGS(X_CF|X_ZF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
MOV32w(x1, (1<<F_CF)|(1<<F_ZF));
TSTw_REG(xFlags, x1);
if(ST_IS_F(0)) {
FCSELS(v1, v2, v1, cEQ);
} else {
FCSELD(v1, v2, v1, cEQ); // F_CF==0 & F_ZF==0
}
FCSELD(v1, v2, v1, cEQ); // F_CF==0 & F_ZF==0
break;
case 0xD8:
case 0xD9:
@@ -111,14 +99,10 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xDF:
INST_NAME("FCMOVNU ST0, STx");
READFLAGS(X_PF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
TSTw_mask(xFlags, 0b011110, 0); //mask=1<<F_PF
if(ST_IS_F(0)) {
FCSELS(v1, v2, v1, cEQ);
} else {
FCSELD(v1, v2, v1, cEQ); // F_PF==0
}
FCSELD(v1, v2, v1, cEQ); // F_PF==0
break;
case 0xE1:
INST_NAME("FDISI8087_NOP"); // so.. NOP?
@@ -134,7 +118,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xE3:
INST_NAME("FNINIT");
MESSAGE(LOG_DUMP, "Need Optimization\n");
x87_purgecache(dyn, ninst, 0, x1, x2, x3);
x87_purgecache(dyn, ninst, x1, x2, x3);
CALL(reset_fpu, -1);
break;
case 0xE8:
@@ -147,13 +131,9 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xEF:
INST_NAME("FUCOMI ST0, STx");
SETFLAGS(X_ALL, SF_SET);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
}
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FCMPD(v1, v2);
FCOMI(x1, x2);
break;
case 0xF0:
@@ -166,13 +146,9 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xF7:
INST_NAME("FCOMI ST0, STx");
SETFLAGS(X_ALL, SF_SET);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
}
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FCMPD(v1, v2);
FCOMI(x1, x2);
break;
@@ -188,7 +164,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
switch((nextop>>3)&7) {
case 0:
INST_NAME("FILD ST0, Ed");
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
v1 = x87_do_push(dyn, ninst);
s0 = fpu_get_scratch(dyn);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
VLDR32_U12(s0, ed, fixedaddress);
@@ -197,7 +173,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 1:
INST_NAME("FISTTP Ed, ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
if(MODREG) {
ed = xRAX+(nextop&7)+(rex.b<<3);
wback = 0;
@@ -224,11 +200,11 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
STRw_U12(x5, wback, fixedaddress);
MARK3;
#endif
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst);
break;
case 2:
INST_NAME("FIST Ed, ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
u8 = x87_setround(dyn, ninst, x1, x2, x4); // x1 have the modified RPSCR reg
if(MODREG) {
ed = xRAX+(nextop&7)+(rex.b<<3);
@@ -260,7 +236,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 3:
INST_NAME("FISTP Ed, ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
u8 = x87_setround(dyn, ninst, x1, x2, x4); // x1 have the modified RPSCR reg
if(MODREG) {
ed = xRAX+(nextop&7)+(rex.b<<3);
@@ -289,7 +265,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MARK3;
#endif
x87_restoreround(dyn, ninst, u8);
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst);
break;
case 5:
INST_NAME("FLD tbyte");
@@ -321,7 +297,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MOVx_REG(x1, ed);
}
CALL(arm_fstp, -1);
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst);
break;
default:
DEFAULT;
@@ -15,11 +15,11 @@
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "emu/x87emu_private.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64.h"
#include "dynarec_arm64_private.h"
#include "arm64_printer.h"
#include "emu/x87emu_private.h"
#include "dynarec_arm64_helper.h"
#include "dynarec_arm64_functions.h"
@@ -46,13 +46,9 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xC6:
case 0xC7:
INST_NAME("FADD STx, ST0");
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FADDS(v1, v1, v2);
} else {
FADDD(v1, v1, v2);
}
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FADDD(v1, v1, v2);
break;
case 0xC8:
case 0xC9:
@@ -63,13 +59,9 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xCE:
case 0xCF:
INST_NAME("FMUL STx, ST0");
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FMULS(v1, v1, v2);
} else {
FMULD(v1, v1, v2);
}
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FMULD(v1, v1, v2);
break;
case 0xD0:
case 0xD1:
@@ -80,13 +72,9 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xD6:
case 0xD7:
INST_NAME("FCOM ST0, STx"); //yep
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
}
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FCMPD(v1, v2);
FCOM(x1, x2, x3);
break;
case 0xD8:
@@ -98,15 +86,11 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xDE:
case 0xDF:
INST_NAME("FCOMP ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
}
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FCMPD(v1, v2);
FCOM(x1, x2, x3);
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst);
break;
case 0xE0:
case 0xE1:
@@ -117,13 +101,9 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xE6:
case 0xE7:
INST_NAME("FSUBR STx, ST0");
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FSUBS(v1, v2, v1);
} else {
FSUBD(v1, v2, v1);
}
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FSUBD(v1, v2, v1);
break;
case 0xE8:
case 0xE9:
@@ -134,13 +114,9 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xEE:
case 0xEF:
INST_NAME("FSUB STx, ST0");
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FSUBS(v1, v1, v2);
} else {
FSUBD(v1, v1, v2);
}
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FSUBD(v1, v1, v2);
break;
case 0xF0:
case 0xF1:
@@ -151,13 +127,9 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xF6:
case 0xF7:
INST_NAME("FDIVR STx, ST0");
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FDIVS(v1, v2, v1);
} else {
FDIVD(v1, v2, v1);
}
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FDIVD(v1, v2, v1);
break;
case 0xF8:
case 0xF9:
@@ -168,19 +140,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xFE:
case 0xFF:
INST_NAME("FDIV STx, ST0");
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FDIVS(v1, v1, v2);
} else {
FDIVD(v1, v1, v2);
}
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FDIVD(v1, v1, v2);
break;
default:
switch((nextop>>3)&7) {
case 0:
INST_NAME("FADD ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = fpu_get_scratch(dyn);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
VLDR64_U12(v2, wback, fixedaddress);
@@ -188,7 +156,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 1:
INST_NAME("FMUL ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = fpu_get_scratch(dyn);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
VLDR64_U12(v2, wback, fixedaddress);
@@ -196,7 +164,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 2:
INST_NAME("FCOM ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = fpu_get_scratch(dyn);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
VLDR64_U12(v2, wback, fixedaddress);
@@ -205,17 +173,17 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 3:
INST_NAME("FCOMP ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = fpu_get_scratch(dyn);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
VLDR64_U12(v2, wback, fixedaddress);
FCMPD(v1, v2);
FCOM(x1, x2, x3);
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst);
break;
case 4:
INST_NAME("FSUB ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = fpu_get_scratch(dyn);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
VLDR64_U12(v2, wback, fixedaddress);
@@ -223,7 +191,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 5:
INST_NAME("FSUBR ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = fpu_get_scratch(dyn);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
VLDR64_U12(v2, wback, fixedaddress);
@@ -231,7 +199,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 6:
INST_NAME("FDIV ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = fpu_get_scratch(dyn);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
VLDR64_U12(v2, wback, fixedaddress);
@@ -239,7 +207,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 7:
INST_NAME("FDIVR ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = fpu_get_scratch(dyn);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 3, rex, 0, 0);
VLDR64_U12(v2, wback, fixedaddress);
@@ -15,11 +15,11 @@
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "emu/x87emu_private.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64.h"
#include "dynarec_arm64_private.h"
#include "arm64_printer.h"
#include "emu/x87emu_private.h"
#include "dynarec_arm64_helper.h"
#include "dynarec_arm64_functions.h"
@@ -49,8 +49,8 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xC7:
INST_NAME("FFREE STx");
MESSAGE(LOG_DUMP, "Need Optimization\n");
x87_purgecache(dyn, ninst, 0, x1, x2, x3);
MOV32w(x1, nextop&7);
x87_purgecache(dyn, ninst, x1, x2, x3);
MOV32w(x1, nextop-0xC0);
CALL(fpu_do_free, -1);
break;
case 0xD0:
@@ -62,17 +62,13 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xD6:
case 0xD7:
INST_NAME("FST ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FMOVS(v2, v1);
} else {
FMOVD(v2, v1);
}
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FMOVD(v2, v1);
break;
case 0xD8:
INST_NAME("FSTP ST0, ST0");
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst);
break;
case 0xD9:
case 0xDA:
@@ -82,9 +78,10 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xDE:
case 0xDF:
INST_NAME("FSTP ST0, STx");
// copy the cache value for st0 to stx
x87_swapreg(dyn, ninst, x1, x2, 0, nextop&7);
x87_do_pop(dyn, ninst, x3);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FMOVD(v2, v1);
x87_do_pop(dyn, ninst);
break;
case 0xE0:
@@ -96,13 +93,9 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xE6:
case 0xE7:
INST_NAME("FUCOM ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
}
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FCMPD(v1, v2);
FCOM(x1, x2, x3);
break;
case 0xE8:
@@ -114,15 +107,11 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xEE:
case 0xEF:
INST_NAME("FUCOMP ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
}
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FCMPD(v1, v2);
FCOM(x1, x2, x3);
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst);
break;
case 0xC8:
@@ -156,37 +145,37 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
switch((nextop>>3)&7) {
case 0:
INST_NAME("FLD double");
v1 = x87_do_push(dyn, ninst, x3, NEON_CACHE_ST_D);
v1 = x87_do_push(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
VLDR64_U12(v1, ed, fixedaddress);
break;
case 1:
INST_NAME("FISTTP i64, ST0");
v1 = x87_do_push(dyn, ninst, x3, NEON_CACHE_ST_D);
v1 = x87_do_push(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
s0 = fpu_get_scratch(dyn);
FRINT64ZD(s0, v1);
FCVTZSxD(x2, s0);
STRx_U12(x2, ed, fixedaddress);
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst);
break;
case 2:
INST_NAME("FST double");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
VSTR64_U12(v1, ed, fixedaddress);
break;
case 3:
INST_NAME("FSTP double");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
VSTR64_U12(v1, ed, fixedaddress);
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst);
break;
case 4:
INST_NAME("FRSTOR m108byte");
MESSAGE(LOG_DUMP, "Need Optimization\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
fpu_purgecache(dyn, ninst, x1, x2, x3);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
if(ed!=x1) {MOVx_REG(x1, ed);}
CALL(arm_frstor, -1);
@@ -194,27 +183,18 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 6:
INST_NAME("FSAVE m108byte");
MESSAGE(LOG_DUMP, "Need Optimization\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
fpu_purgecache(dyn, ninst, x1, x2, x3);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
if(ed!=x1) {MOVx_REG(x1, ed);}
CALL(arm_fsave, -1);
break;
case 7:
INST_NAME("FNSTSW m2byte");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
fpu_purgecache(dyn, ninst, x1, x2, x3);
addr = geted(dyn, addr, ninst, nextop, &ed, x4, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
LDRw_U12(x1, xEmu, offsetof(x64emu_t, top));
LDRH_U12(x3, xEmu, offsetof(x64emu_t, sw));
if(dyn->n.x87stack) {
// update top
if(dyn->n.x87stack>0) {
SUBw_U12(x2, x2, dyn->n.x87stack);
} else {
ADDw_U12(x2, x2, -dyn->n.x87stack);
}
ANDw_mask(x2, x2, 0, 2);
}
BFIw(x3, x2, 11, 3); // inject TOP at bit 11 (3 bits)
BFIw(x3, x1, 11, 3); // inject TOP at bit 11 (3 bits)
STRH_U12(x3, ed, fixedaddress); // store whole sw flags
break;
default:
@@ -15,11 +15,11 @@
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "emu/x87emu_private.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64.h"
#include "dynarec_arm64_private.h"
#include "arm64_printer.h"
#include "emu/x87emu_private.h"
#include "dynarec_arm64_helper.h"
#include "dynarec_arm64_functions.h"
@@ -51,7 +51,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xC7:
INST_NAME("FFREEP STx");
// not handling Tag...
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst);
break;
case 0xE0:
@@ -71,16 +71,11 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xEF:
INST_NAME("FUCOMIP ST0, STx");
SETFLAGS(X_ALL, SF_SET);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0))
{
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
}
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FCMPD(v1, v2);
FCOMI(x1, x2);
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst);
break;
case 0xF0:
case 0xF1:
@@ -92,16 +87,11 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xF7:
INST_NAME("FCOMIP ST0, STx");
SETFLAGS(X_ALL, SF_SET);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0))
{
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
}
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
FCMPD(v1, v2);
FCOMI(x1, x2);
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst);
break;
case 0xC8:
@@ -150,23 +140,19 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
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);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
LDRSHw_U12(x1, wback, fixedaddress);
if(ST_IS_F(0)) {
SCVTFSw(v1, x1);
} else {
SCVTFDw(v1, x1);
}
SCVTFDw(v1, x1);
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);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
ed = x1;
s0 = fpu_get_scratch(dyn);
#if 0
// this version needs ARM v8.5, //TODO: add detection of this extension to use it
// this version needs ARM v8.5, //TODO: add detection of this extensio to use it
FRINT32ZD(s0, v1);
// no saturation instruction on Arm, so using NEON
VFCVTZSd(s0, s0);
@@ -177,12 +163,8 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MRS_fpsr(x5);
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
if(ST_IS_F(0)) {
VFCVTZSs(s0, v1);
} else {
VFCVTZSd(s0, v1);
SQXTN_S_D(s0, s0);
}
VFCVTZSd(s0, v1);
SQXTN_S_D(s0, s0);
SQXTN_H_S(s0, s0);
VSTR16_U12(s0, wback, fixedaddress);
MRS_fpsr(x5); // get back FPSR to check the IOC bit
@@ -191,11 +173,11 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
STRH_U12(x5, wback, fixedaddress);
MARK3;
#endif
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, 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);
u8 = x87_setround(dyn, ninst, x1, x2, x4);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
ed = x1;
@@ -211,14 +193,9 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MRS_fpsr(x5);
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
if(ST_IS_F(0)) {
FRINTXS(s0, v1);
VFCVTZSs(s0, s0);
} else {
FRINTXD(s0, v1);
VFCVTZSd(s0, s0);
SQXTN_S_D(s0, s0);
}
FRINTXD(s0, v1);
VFCVTZSd(s0, s0);
SQXTN_S_D(s0, s0);
SQXTN_H_S(s0, s0);
VSTR16_U12(s0, wback, fixedaddress);
MRS_fpsr(x5); // get back FPSR to check the IOC bit
@@ -231,7 +208,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
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);
u8 = x87_setround(dyn, ninst, x1, x2, x4);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<1, 1, rex, 0, 0);
ed = x1;
@@ -247,14 +224,9 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MRS_fpsr(x5);
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
if(ST_IS_F(0)) {
FRINTXS(s0, v1);
VFCVTZSs(s0, s0);
} else {
FRINTXD(s0, v1);
VFCVTZSd(s0, s0);
SQXTN_S_D(s0, s0);
}
FRINTXD(s0, v1);
VFCVTZSd(s0, s0);
SQXTN_S_D(s0, s0);
SQXTN_H_S(s0, s0);
VSTR16_U12(s0, wback, fixedaddress);
MRS_fpsr(x5); // get back FPSR to check the IOC bit
@@ -263,7 +235,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
STRH_U12(x5, wback, fixedaddress);
MARK3;
#endif
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst);
x87_restoreround(dyn, ninst, u8);
break;
case 4:
@@ -275,7 +247,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 5:
INST_NAME("FILD ST0, i64");
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
v1 = x87_do_push(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
LDRx_U12(x1, wback, fixedaddress);
SCVTFDx(v1, x1);
@@ -286,11 +258,11 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, rex, 0, 0);
if(ed!=x1) {MOVx_REG(x1, ed);}
CALL(fpu_fbst, -1);
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst);
break;
case 7:
INST_NAME("FISTP i64, ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
u8 = x87_setround(dyn, ninst, x1, x2, x4);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
ed = x1;
@@ -313,7 +285,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MARK3;
#endif
x87_restoreround(dyn, ninst, u8);
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst);
break;
default:
DEFAULT;
@@ -15,11 +15,11 @@
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "dynarec_arm64.h"
#include "dynarec_arm64_private.h"
#include "arm64_printer.h"
#include "../tools/bridge_private.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "dynarec_arm64_functions.h"
#include "dynarec_arm64_helper.h"
@@ -15,11 +15,11 @@
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "dynarec_arm64.h"
#include "dynarec_arm64_private.h"
#include "arm64_printer.h"
#include "../tools/bridge_private.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "dynarec_arm64_functions.h"
#include "dynarec_arm64_helper.h"
@@ -15,11 +15,11 @@
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "dynarec_arm64.h"
#include "dynarec_arm64_private.h"
#include "arm64_printer.h"
#include "../tools/bridge_private.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "dynarec_arm64_functions.h"
#include "dynarec_arm64_helper.h"
@@ -15,11 +15,11 @@
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "dynarec_arm64.h"
#include "dynarec_arm64_private.h"
#include "arm64_printer.h"
#include "../tools/bridge_private.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "dynarec_arm64_functions.h"
#include "dynarec_arm64_helper.h"
@@ -15,10 +15,10 @@
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64.h"
#include "dynarec_arm64_private.h"
#include "arm64_printer.h"
#include "dynarec_arm64_helper.h"
#include "dynarec_arm64_functions.h"
@@ -56,7 +56,6 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("LOCK ADD Eb, Gb");
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
DMB_ISH();
GETGB(x2);
if((nextop&0xC0)==0xC0) {
if(rex.rex) {
@@ -78,14 +77,12 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
STLXRB(x4, x1, wback);
CBNZx_MARKLOCK(x4);
}
DMB_ISH();
break;
case 0x01:
INST_NAME("LOCK ADD Ed, Gd");
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGD;
DMB_ISH();
if((nextop&0xC0)==0xC0) {
ed = xRAX+(nextop&7)+(rex.b<<3);
emit_add32(dyn, ninst, rex, ed, gd, x3, x4);
@@ -97,7 +94,6 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
STLXRxw(x3, x1, wback);
CBNZx_MARKLOCK(x3);
}
DMB_ISH();
break;
case 0x09:
@@ -105,7 +101,6 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGD;
DMB_ISH();
if(MODREG) {
ed = xRAX+(nextop&7)+(rex.b<<3);
emit_or32(dyn, ninst, rex, ed, gd, x3, x4);
@@ -117,63 +112,17 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
STLXRxw(x3, x1, wback);
CBNZx_MARKLOCK(x3);
}
DMB_ISH();
break;
case 0x0F:
nextop = F8;
switch(nextop) {
case 0xB0:
INST_NAME("LOCK CMPXCHG Eb, Gb");
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGB(x1);
UBFXx(x6, xRAX, 0, 8);
DMB_ISH();
if(MODREG) {
if(rex.rex) {
wback = xRAX+(nextop&7)+(rex.b<<3);
wb2 = 0;
} else {
wback = (nextop&7);
wb2 = (wback>>2)*8;
wback = xRAX+(wback&3);
}
UBFXx(x2, wback, wb2, 8);
wb1 = 0;
ed = x2;
UFLAG_IF {emit_cmp8(dyn, ninst, x6, ed, x3, x4, x5);}
CMPSxw_REG(x6, x2);
B_MARK2(cNE);
BFIx(wback, x2, wb2, 8);
MOVxw_REG(ed, gd);
MARK2;
BFIx(xRAX, x2, 0, 8);
B_NEXT_nocond;
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, 0, 0);
// Aligned version
MARKLOCK;
LDAXRB(x2, wback);
CMPSxw_REG(x6, x2);
B_MARK(cNE);
// EAX == Ed
STLXRB(x4, gd, wback);
CBNZx_MARKLOCK(x4);
// done
MARK;
UFLAG_IF {emit_cmp32(dyn, ninst, rex, x6, x2, x3, x4, x5);}
BFIx(xRAX, x2, 0, 8); // upper par of RAX will be erase on 32bits, no mater what
}
DMB_ISH();
break;
case 0xB1:
INST_NAME("LOCK CMPXCHG Ed, Gd");
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGD;
DMB_ISH();
if(MODREG) {
ed = xRAX+(nextop&7)+(rex.b<<3);
wback = 0;
@@ -214,7 +163,6 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
UFLAG_IF {emit_cmp32(dyn, ninst, rex, xRAX, x1, x3, x4, x5);}
MOVxw_REG(xRAX, x1); // upper par of RAX will be erase on 32bits, no mater what
}
DMB_ISH();
break;
case 0xC1:
@@ -222,7 +170,6 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGD;
DMB_ISH();
if(MODREG) {
ed = xRAX+(nextop&7)+(rex.b<<3);
MOVxw_REG(x1, ed);
@@ -254,7 +201,6 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
MOVxw_REG(gd, x1);
}
DMB_ISH();
break;
case 0xC7:
@@ -262,7 +208,6 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ZF, SF_SUBSET);
nextop = F8;
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 0, 0, rex, 0, 0);
DMB_ISH();
MARKLOCK;
LDAXPxw(x2, x3, wback);
CMPSxw_REG(xRAX, x2);
@@ -278,7 +223,6 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MOVxw_REG(xRDX, x3);
MOV32w(x1, 0);
MARK3;
DMB_ISH();
BFIw(xFlags, x1, F_ZF, 1);
break;
@@ -292,7 +236,6 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGD;
DMB_ISH();
if(MODREG) {
ed = xRAX+(nextop&7)+(rex.b<<3);
emit_sub32(dyn, ninst, rex, ed, gd, x3, x4);
@@ -304,38 +247,14 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
STLXRxw(x3, x1, wback);
CBNZx_MARKLOCK(x3);
}
DMB_ISH();
break;
case 0x66:
opcode = F8;
switch(opcode) {
case 0x09:
INST_NAME("LOCK OR Ew, Gw");
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGW(x5);
DMB_ISH();
if(MODREG) {
ed = xRAX+(nextop&7)+(rex.b<<3);
UXTHw(x6, ed);
emit_or16(dyn, ninst, x6, x5, x3, x4);
BFIx(ed, x6, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, 0);
MARKLOCK;
LDAXRH(x1, wback);
emit_or16(dyn, ninst, x1, x5, x3, x4);
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
}
DMB_ISH();
break;
case 0x81:
case 0x83:
nextop = F8;
DMB_ISH();
switch((nextop>>3)&7) {
case 0: //ADD
if(opcode==0x81) {
@@ -529,7 +448,6 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
break;
}
DMB_ISH();
break;
default:
DEFAULT;
@@ -538,7 +456,6 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0x80:
nextop = F8;
DMB_ISH();
switch((nextop>>3)&7) {
case 0: //ADD
INST_NAME("ADD Eb, Ib");
@@ -697,12 +614,10 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
default:
DEFAULT;
}
DMB_ISH();
break;
case 0x81:
case 0x83:
nextop = F8;
DMB_ISH();
switch((nextop>>3)&7) {
case 0: //ADD
if(opcode==0x81) {
@@ -719,20 +634,20 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?4:1);
if(opcode==0x81) i64 = F32S; else i64 = F8S;
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
MOV64xw(x5, i64);
TSTx_mask(wback, 1, 0, 0); // mask=1
B_MARK(cNE);
MARKLOCK;
LDAXRxw(x1, wback);
emit_add32c(dyn, ninst, rex, x1, i64, x3, x4, x5);
emit_add32(dyn, ninst, rex, x1, x5, x3, x4);
STLXRxw(x3, x1, wback);
CBNZx_MARKLOCK(x3);
DMB_ISH();
B_NEXT_nocond;
MARK; // unaligned! also, not enough
LDRxw_U12(x1, wback, 0);
LDAXRB(x4, wback);
BFIxw(x1, x4, 0, 8); // re-inject
emit_add32c(dyn, ninst, rex, x1, i64, x3, x4, x5);
emit_add32(dyn, ninst, rex, x1, x5, x3, x4);
STLXRB(x3, x1, wback);
CBNZx_MARK(x3);
STRxw_U12(x1, wback, 0); // put the whole value
@@ -827,20 +742,20 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, rex, 0, (opcode==0x81)?4:1);
if(opcode==0x81) i64 = F32S; else i64 = F8S;
TSTx_mask(wback, 1, 0, 1+rex.w); // mask=3 or 7
MOV64xw(x5, i64);
TSTx_mask(wback, 1, 0, 0); // mask=1
B_MARK(cNE);
MARKLOCK;
LDAXRxw(x1, wback);
emit_sub32c(dyn, ninst, rex, x1, i64, x3, x4, x5);
emit_sub32(dyn, ninst, rex, x1, x5, x3, x4);
STLXRxw(x3, x1, wback);
CBNZx_MARKLOCK(x3);
DMB_ISH();
B_NEXT_nocond;
MARK; // unaligned! also, not enough
LDRxw_U12(x1, wback, 0);
LDAXRB(x4, wback);
BFIxw(x1, x4, 0, 8); // re-inject
emit_sub32c(dyn, ninst, rex, x1, i64, x3, x4, x5);
emit_sub32(dyn, ninst, rex, x1, x5, x3, x4);
STLXRB(x3, x1, wback);
CBNZx_MARK(x3);
STRxw_U12(x1, wback, 0); // put the whole value
@@ -879,7 +794,6 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
break;
}
DMB_ISH();
break;
case 0x87:
@@ -893,7 +807,6 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MOVxw_REG(ed, x1);
} else {
GETGD;
DMB_ISH();
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, rex, 0, 0);
TSTx_mask(ed, 1, 0, 1+rex.w); // mask=3 or 7
B_MARK(cNE);
@@ -906,7 +819,6 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
LDRxw_U12(x1, ed, 0);
STRxw_U12(gd, ed, 0);
MARK2;
DMB_ISH();
MOVxw_REG(gd, x1);
}
break;
@@ -917,8 +829,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
{
case 0: // INC Ed
INST_NAME("LOCK INC Ed");
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
DMB_ISH();
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
if(MODREG) {
ed = xRAX+(nextop&7)+(rex.b<<3);
emit_inc32(dyn, ninst, rex, ed, x3, x4);
@@ -941,12 +852,10 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBNZw_MARK(x3);
STRxw_U12(x1, wback, 0);
}
DMB_ISH();
break;
case 1: //DEC Ed
INST_NAME("LOCK DEC Ed");
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
DMB_ISH();
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
if(MODREG) {
ed = xRAX+(nextop&7)+(rex.b<<3);
emit_dec32(dyn, ninst, rex, ed, x3, x4);
@@ -969,7 +878,6 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBNZw_MARK(x3);
STRxw_U12(x1, wback, 0);
}
DMB_ISH();
break;
default:
DEFAULT;
@@ -15,17 +15,17 @@
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64.h"
#include "dynarec_arm64_private.h"
#include "arm64_printer.h"
#include "dynarec_arm64_functions.h"
#include "dynarec_arm64_helper.h"
// Get Ex as a double, not a quad (warning, x2 get used)
#define GETEX(a, w, D) \
#define GETEX(a, D) \
if(MODREG) { \
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), w); \
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3)); \
} else { \
a = fpu_get_scratch(dyn); \
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, D); \
@@ -34,16 +34,12 @@
#define GETG gd = ((nextop&0x38)>>3)+(rex.r<<3)
#define GETGX(a, w) gd = ((nextop&0x38)>>3)+(rex.r<<3); \
a = sse_get_reg(dyn, ninst, x1, gd, w)
#define GETGX(a) gd = ((nextop&0x38)>>3)+(rex.r<<3); \
a = sse_get_reg(dyn, ninst, x1, gd)
#define GETGX_empty(a) gd = ((nextop&0x38)>>3)+(rex.r<<3); \
a = sse_get_reg_empty(dyn, ninst, x1, gd)
#define GETGM(a) \
gd = ((nextop&0x38)>>3); \
a = mmx_get_reg(dyn, ninst, x1, x2, x3, gd)
uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
{
(void)ip; (void)need_epilog;
@@ -53,7 +49,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
uint8_t gd, ed;
uint8_t wback;
uint8_t u8;
uint64_t u64, j64;
uint64_t u64;
int v0, v1;
int q0;
int d0, d1;
@@ -77,8 +73,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETG;
if(MODREG) {
ed = (nextop&7)+ (rex.b<<3);
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
d0 = sse_get_reg(dyn, ninst, x1, ed, 0);
v0 = sse_get_reg(dyn, ninst, x1, gd);
d0 = sse_get_reg(dyn, ninst, x1, ed);
VMOVeD(v0, 0, d0, 0);
} else {
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
@@ -90,10 +86,10 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
INST_NAME("MOVSD Ex, Gx");
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
v0 = sse_get_reg(dyn, ninst, x1, gd);
if(MODREG) {
ed = (nextop&7)+ (rex.b<<3);
d0 = sse_get_reg(dyn, ninst, x1, ed, 1);
d0 = sse_get_reg(dyn, ninst, x1, ed);
VMOVeD(d0, 0, v0, 0);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
@@ -105,7 +101,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
nextop = F8;
GETG;
if(MODREG) {
d0 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
d0 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
VMOVeD(v0, 0, d0, 0);
} else {
@@ -119,7 +115,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0x2A:
INST_NAME("CVTSI2SD Gx, Ed");
nextop = F8;
GETGX(v0, 1);
GETGX(v0);
GETED(0);
d1 = fpu_get_scratch(dyn);
if(rex.w) {
@@ -134,23 +130,23 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
INST_NAME("CVTTSD2SI Gd, Ex");
nextop = F8;
GETGD;
GETEX(q0, 0, 0);
GETEX(q0, 0);
FCVTZSxwD(gd, q0);
break;
case 0x2D:
INST_NAME("CVTSD2SI Gd, Ex");
nextop = F8;
GETGD;
GETEX(q0, 0, 0);
GETEX(q0, 0);
#ifdef PRECISE_CVT
LDRH_U12(x1, xEmu, offsetof(x64emu_t, mxcsr));
UBFXx(x1, x1, 13, 2); // extract round requested
LSLx_REG(x1, x1, 3);
ADDx_U12(x1, x1, 8); // add the actual add+jump opcodes
// Construct a "switch case", with each case 2 instructions, so 8 bytes
ADR(xLR, GETMARK);
BL(+4); // Branch with Link to next, so LR gets next PC address
ADDx_REG(xLR, xLR, x1);
B(xLR);
MARK;
B(xLR); // could use RET, but it's not really one
FCVTNSxwD(gd, q0); // 0: Nearest (even)
B_NEXT_nocond;
FCVTMSxwD(gd, q0); // 1: Toward -inf
@@ -167,70 +163,36 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0x51:
INST_NAME("SQRTSD Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETGX(v0);
d1 = fpu_get_scratch(dyn);
GETEX(d0, 0, 0);
if(!box64_dynarec_fastnan) {
v1 = fpu_get_scratch(dyn);
FCMLTD_0(v1, d0);
SHL_64(v1, v1, 63);
}
GETEX(d0, 0);
FSQRTD(d1, d0);
if(!box64_dynarec_fastnan) {
VORR(d1, d1, v1);
}
VMOVeD(v0, 0, d1, 0);
break;
case 0x58:
INST_NAME("ADDSD Gx, Ex");
nextop = F8;
GETGX(d1, 1);
v1 = fpu_get_scratch(dyn);
GETEX(d0, 0, 0);
if(!box64_dynarec_fastnan) {
v0 = fpu_get_scratch(dyn);
q0 = fpu_get_scratch(dyn);
// check if any input value was NAN
FMAXD(v0, d0, d1); // propagate NAN
FCMEQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
}
FADDD(v1, d1, d0); // the high part of the vector is erased...
if(!box64_dynarec_fastnan) {
FCMEQD(q0, v1, v1); // 0 => out is NAN
VBIC(q0, v0, q0); // forget it in any input was a NAN already
SHL_64(q0, q0, 63); // only keep the sign bit
VORR(v1, v1, q0); // NAN -> -NAN
}
VMOVeD(d1, 0, v1, 0);
GETGX(v0);
d1 = fpu_get_scratch(dyn);
GETEX(d0, 0);
FADDD(d1, v0, d0); // the high part of the vector is erased...
VMOVeD(v0, 0, d1, 0);
break;
case 0x59:
INST_NAME("MULSD Gx, Ex");
nextop = F8;
GETGX(d1, 1);
v1 = fpu_get_scratch(dyn);
GETEX(d0, 0, 0);
if(!box64_dynarec_fastnan) {
v0 = fpu_get_scratch(dyn);
q0 = fpu_get_scratch(dyn);
// check if any input value was NAN
FMAXD(v0, d0, d1); // propagate NAN
FCMEQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
}
FMULD(v1, d1, d0);
if(!box64_dynarec_fastnan) {
FCMEQD(q0, v1, v1); // 0 => out is NAN
VBIC(q0, v0, q0); // forget it in any input was a NAN already
SHL_64(q0, q0, 63); // only keep the sign bit
VORR(v1, v1, q0); // NAN -> -NAN
}
VMOVeD(d1, 0, v1, 0);
GETGX(v0);
d1 = fpu_get_scratch(dyn);
GETEX(d0, 0);
FMULD(d1, v0, d0);
VMOVeD(v0, 0, d1, 0);
break;
case 0x5A:
INST_NAME("CVTSD2SS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(d0, 0, 0);
GETGX(v0);
GETEX(d0, 0);
d1 = fpu_get_scratch(dyn);
FCVT_S_D(d1, d0);
VMOVeS(v0, 0, d1, 0);
@@ -239,85 +201,49 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0x5C:
INST_NAME("SUBSD Gx, Ex");
nextop = F8;
GETGX(d1, 1);
v1 = fpu_get_scratch(dyn);
GETEX(d0, 0, 0);
if(!box64_dynarec_fastnan) {
v0 = fpu_get_scratch(dyn);
q0 = fpu_get_scratch(dyn);
// check if any input value was NAN
FMAXD(v0, d0, d1); // propagate NAN
FCMEQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
}
FSUBD(v1, d1, d0);
if(!box64_dynarec_fastnan) {
FCMEQD(q0, v1, v1); // 0 => out is NAN
VBIC(q0, v0, q0); // forget it in any input was a NAN already
SHL_64(q0, q0, 63); // only keep the sign bit
VORR(v1, v1, q0); // NAN -> -NAN
}
VMOVeD(d1, 0, v1, 0);
GETGX(v0);
d1 = fpu_get_scratch(dyn);
GETEX(d0, 0);
FSUBD(d1, v0, d0);
VMOVeD(v0, 0, d1, 0);
break;
case 0x5D:
INST_NAME("MINSD Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 0);
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(v1, 0);
// MINSD: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
#if 0
d0 = fpu_get_scratch(dyn);
FMINNMD(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
VMOVeD(v0, 0, d0, 0); // to not erase uper part
#else
FCMPD(v0, v1);
B_NEXT(cLS); //Less than or equal
VMOVeD(v0, 0, v1, 0); // to not erase uper part
#endif
break;
case 0x5E:
INST_NAME("DIVSD Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETGX(v0);
d1 = fpu_get_scratch(dyn);
GETEX(v1, 0, 0);
if(!box64_dynarec_fastnan) {
d0 = fpu_get_scratch(dyn);
q0 = fpu_get_scratch(dyn);
// check if any input value was NAN
FMAXD(d0, v0, v1); // propagate NAN
FCMEQD(d0, d0, d0); // 0 if NAN, 1 if not NAN
}
FDIVD(d1, v0, v1);
if(!box64_dynarec_fastnan) {
FCMEQD(q0, d1, d1); // 0 => out is NAN
VBIC(q0, d0, q0); // forget it in any input was a NAN already
SHL_64(q0, q0, 63); // only keep the sign bit
VORR(d1, d1, q0); // NAN -> -NAN
}
GETEX(d0, 0);
FDIVD(d1, v0, d0);
VMOVeD(v0, 0, d1, 0);
break;
case 0x5F:
INST_NAME("MAXSD Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 0);
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(v1, 0);
// MAXSD: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
#if 0
d0 = fpu_get_scratch(dyn);
FMAXNMD(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
VMOVeD(v0, 0, d0, 0); // to not erase uper part
#else
FCMPD(v0, v1);
B_NEXT(cGE); //Greater than or equal
VMOVeD(v0, 0, v1, 0); // to not erase uper part
#endif
break;
case 0x70:
INST_NAME("PSHUFLW Gx, Ex, Ib");
nextop = F8;
GETEX(v1, 0, 1);
GETGX(v0, 1);
GETEX(v1, 1);
GETGX(v0);
u8 = F8;
// only low part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
@@ -339,9 +265,9 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0x7C:
INST_NAME("HADDPS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETGX(v0);
if(MODREG) {
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
v1 = fpu_get_scratch(dyn);
@@ -353,18 +279,22 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0xC2:
INST_NAME("CMPSD Gx, Ex, Ib");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 1);
GETGX(v0);
GETEX(v1, 1);
u8 = F8;
FCMPD(v0, v1);
if((u8&7)==6){
FCMPD(v1, v0);
} else {
FCMPD(v0, v1);
}
switch(u8&7) {
case 0: CSETMx(x2, cEQ); break; // Equal
case 1: CSETMx(x2, cCC); break; // Less than
case 2: CSETMx(x2, cLS); break; // Less or equal
case 0: CSETMx(x2, cEQ); CSELx(x2, xZR, x2, cVS); break; // Equal
case 1: CSETMx(x2, cMI); CSELx(x2, xZR, x2, cVS); break; // Less than
case 2: CSETMx(x2, cLE); CSELx(x2, xZR, x2, cVS); break; // Less or equal
case 3: CSETMx(x2, cVS); break; // NaN
case 4: CSETMx(x2, cNE); break; // Not Equal or unordered
case 4: CSETMx(x2, cNE); break; // Not Equal
case 5: CSETMx(x2, cCS); break; // Greater or equal or unordered
case 6: CSETMx(x2, cHI); break; // Greater or unordered, test inverted, N!=V so unordered or less than (inverted)
case 6: CSETMx(x2, cLT); break; // Greater or unordered, test inverted, N!=V so unordered or less than (inverted)
case 7: CSETMx(x2, cVC); break; // not NaN
}
VMOVQDfrom(v0, 0, x2);
@@ -373,8 +303,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0xD0:
INST_NAME("ADDSUBPS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 0);
GETGX(v0);
GETEX(v1, 0);
q0 = fpu_get_scratch(dyn);
static float addsubps[4] = {-1.f, 1.f, -1.f, 1.f};
MAYUSE(addsubps);
@@ -383,21 +313,13 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VFMLAQS(v0, v1, q0);
break;
case 0xD6:
INST_NAME("MOVDQ2Q Gm, Ex");
nextop = F8;
GETGM(v0);
GETEX(v1, 0, 0);
VMOV(v0, v1);
break;
case 0xE6:
INST_NAME("CVTPD2DQ Gx, Ex");
nextop = F8;
GETEX(v1, 0, 0);
GETEX(v1, 0);
GETGX_empty(v0);
u8 = sse_setround(dyn, ninst, x1, x2, x3);
VFRINTIDQ(v0, v1);
FRINTXD(v0, v1);
x87_restoreround(dyn, ninst, u8);
VFCVTNSQD(v0, v0); // convert double -> int64
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
@@ -408,7 +330,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
nextop = F8;
GETG;
if(MODREG) {
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
VMOVQ(v0, v1);
} else {
@@ -15,17 +15,17 @@
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64.h"
#include "dynarec_arm64_private.h"
#include "arm64_printer.h"
#include "dynarec_arm64_functions.h"
#include "dynarec_arm64_helper.h"
// Get Ex as a single, not a quad (warning, x2 get used)
#define GETEX(a, w, D) \
#define GETEX(a, D) \
if(MODREG) { \
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), w); \
a = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3)); \
} else { \
a = fpu_get_scratch(dyn); \
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, D); \
@@ -34,8 +34,8 @@
#define GETG gd = ((nextop&0x38)>>3)+(rex.r<<3)
#define GETGX(a, w) gd = ((nextop&0x38)>>3)+(rex.r<<3); \
a = sse_get_reg(dyn, ninst, x1, gd, w)
#define GETGX(a) gd = ((nextop&0x38)>>3)+(rex.r<<3); \
a = sse_get_reg(dyn, ninst, x1, gd)
#define GETGX_empty(a) gd = ((nextop&0x38)>>3)+(rex.r<<3); \
a = sse_get_reg_empty(dyn, ninst, x1, gd)
@@ -70,8 +70,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
nextop = F8;
GETG;
if(MODREG) {
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
v0 = sse_get_reg(dyn, ninst, x1, gd);
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
VMOVeS(v0, 0, q0, 0);
} else {
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
@@ -83,9 +83,9 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
INST_NAME("MOVSS Ex, Gx");
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
v0 = sse_get_reg(dyn, ninst, x1, gd);
if(MODREG) {
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
VMOVeS(q0, 0, v0, 0);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<2, 3, rex, 0, 0);
@@ -96,7 +96,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
INST_NAME("MOVSLDUP Gx, Ex");
nextop = F8;
if(MODREG) {
q1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
q1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
q1 = fpu_get_scratch(dyn);
@@ -110,7 +110,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
INST_NAME("MOVSHDUP Gx, Ex");
nextop = F8;
if(MODREG) {
q1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
q1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
q1 = fpu_get_scratch(dyn);
@@ -129,7 +129,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0x2A:
INST_NAME("CVTSI2SS Gx, Ed");
nextop = F8;
GETGX(v0, 1);
GETGX(v0);
GETED(0);
d1 = fpu_get_scratch(dyn);
if(rex.w) {
@@ -144,22 +144,23 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
INST_NAME("CVTTSS2SI Gd, Ex");
nextop = F8;
GETGD;
GETEX(d0, 0, 0);
GETEX(d0, 0);
FCVTZSxwS(gd, d0);
break;
case 0x2D:
INST_NAME("CVTSS2SI Gd, Ex");
nextop = F8;
GETGD;
GETEX(q0, 0, 0);
GETEX(q0, 0);
#ifdef PRECISE_CVT
LDRH_U12(x1, xEmu, offsetof(x64emu_t, mxcsr));
UBFXx(x1, x1, 13, 2); // extract round requested
LSLx_REG(x1, x1, 3);
ADDx_U12(x1, x1, 8); // add the actual add+jump opcodes
// Construct a "switch case", with each case 2 instructions, so 8 bytes
ADR(xLR, GETMARK);
BL(+4); // Branch with Link to next, so LR gets next PC address
ADDx_REG(xLR, xLR, x1);
B(xLR);
B(xLR); // could use RET, but it's not really one
FCVTNSxwS(gd, q0); // 0: Nearest (even)
B_NEXT_nocond;
FCVTMSxwS(gd, q0); // 1: Toward -inf
@@ -174,17 +175,17 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0x51:
INST_NAME("SQRTSS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETGX(v0);
d1 = fpu_get_scratch(dyn);
GETEX(d0, 0, 0);
GETEX(d0, 0);
FSQRTS(d1, d0);
VMOVeS(v0, 0, d1, 0);
break;
case 0x52:
INST_NAME("RSQRTSS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 0);
GETEX(v1, 0);
GETGX_empty(v0);
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
// so here: F32: Imm8 = abcd efgh that gives => aBbbbbbc defgh000 00000000 00000000
@@ -200,8 +201,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0x53:
INST_NAME("RCPSS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 0);
GETGX(v0);
GETEX(v1, 0);
d0 = fpu_get_scratch(dyn);
FMOVS_8(d0, 0b01110000); //1.0f
FDIVS(d0, d0, v1);
@@ -211,26 +212,26 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0x58:
INST_NAME("ADDSS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETGX(v0);
d1 = fpu_get_scratch(dyn);
GETEX(d0, 0, 0);
GETEX(d0, 0);
FADDS(d1, v0, d0); // the high part of the vector is erased...
VMOVeS(v0, 0, d1, 0);
break;
case 0x59:
INST_NAME("MULSS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETGX(v0);
d1 = fpu_get_scratch(dyn);
GETEX(d0, 0, 0);
GETEX(d0, 0);
FMULS(d1, v0, d0);
VMOVeS(v0, 0, d1, 0);
break;
case 0x5A:
INST_NAME("CVTSS2SD Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 0);
GETGX(v0);
GETEX(v1, 0);
d0 = fpu_get_scratch(dyn);
FCVT_D_S(d0, v1);
VMOVeD(v0, 0, d0, 0);
@@ -238,7 +239,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0x5B:
INST_NAME("CVTPS2DQ Gx, Ex");
nextop = F8;
GETEX(d0, 0, 0);
GETEX(d0, 0);
GETGX_empty(v0);
VFCVTZSQS(v0, d0);
break;
@@ -246,64 +247,51 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0x5C:
INST_NAME("SUBSS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETGX(v0);
d1 = fpu_get_scratch(dyn);
GETEX(d0, 0, 0);
GETEX(d0, 0);
FSUBS(d1, v0, d0);
VMOVeS(v0, 0, d1, 0);
break;
case 0x5D:
INST_NAME("MINSS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 0);
GETGX(v0);
GETEX(v1, 0);
// MINSS: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
#if 0
d0 = fpu_get_scratch(dyn);
FMINNMS(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
VMOVeS(v0, 0, d0, 0); // to not erase uper part
#else
FCMPS(v0, v1);
B_NEXT(cLS); //Less than or equal
VMOVeS(v0, 0, v1, 0); // to not erase uper part
#endif
break;
case 0x5E:
INST_NAME("DIVSS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETGX(v0);
d1 = fpu_get_scratch(dyn);
GETEX(d0, 0, 0);
GETEX(d0, 0);
FDIVS(d1, v0, d0);
VMOVeS(v0, 0, d1, 0);
break;
case 0x5F:
INST_NAME("MAXSS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 0);
GETGX(v0);
GETEX(v1, 0);
// MAXSS: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
#if 0
d0 = fpu_get_scratch(dyn);
FMAXNMS(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
VMOVeS(v0, 0, d0, 0); // to not erase uper part
#else
FCMPS(v0, v1);
B_NEXT(cGE); //Greater than or equal
VMOVeS(v0, 0, v1, 0); // to not erase uper part
#endif
break;
case 0x6F:
INST_NAME("MOVDQU Gx,Ex");// no alignment constraint on NEON here, so same as MOVDQA
nextop = F8;
GETG;
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
if(MODREG) {
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
GETGX_empty(v0);
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
VMOVQ(v0, v1);
} else {
GETGX_empty(v0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
VLDR128_U12(v0, ed, fixedaddress);
}
@@ -311,8 +299,9 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0x70:
INST_NAME("PSHUFHW Gx, Ex, Ib");
nextop = F8;
GETEX(v1, 0, 1);
GETGX(v0, 1);
GETEX(v1, 1);
GETGX(v0);
u8 = F8;
// only high part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
u64 = 0;
@@ -333,12 +322,13 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0x7E:
INST_NAME("MOVQ Gx, Ex");
nextop = F8;
GETG;
if(MODREG) {
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
GETGX_empty(v0);
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
FMOVD(v0, v1);
} else {
GETGX_empty(v0);
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
VLDR64_U12(v0, ed, fixedaddress);
}
@@ -346,11 +336,13 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0x7F:
INST_NAME("MOVDQU Ex,Gx");
nextop = F8;
GETGX(v0, 0);
GETG;
if(MODREG) {
v0 = sse_get_reg(dyn, ninst, x1, gd);
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
VMOVQ(v1, v0);
} else {
v0 = sse_get_reg(dyn, ninst, x1, gd);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<4, 15, rex, 0, 0);
VSTR128_U12(v0, ed, fixedaddress);
}
@@ -389,18 +381,22 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0xC2:
INST_NAME("CMPSS Gx, Ex, Ib");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 1);
GETGX(v0);
GETEX(v1, 1);
u8 = F8;
FCMPS(v0, v1);
if((u8&7)==6){
FCMPS(v1, v0);
} else {
FCMPS(v0, v1);
}
switch(u8&7) {
case 0: CSETMw(x2, cEQ); break; // Equal
case 1: CSETMw(x2, cCC); break; // Less than
case 2: CSETMw(x2, cLS); break; // Less or equal
case 0: CSETMw(x2, cEQ); CSELw(x2, xZR, x2, cVS); break; // Equal
case 1: CSETMw(x2, cMI); CSELw(x2, xZR, x2, cVS); break; // Less than
case 2: CSETMw(x2, cLE); CSELw(x2, xZR, x2, cVS); break; // Less or equal
case 3: CSETMw(x2, cVS); break; // NaN
case 4: CSETMw(x2, cNE); break; // Not Equal or unordered
case 4: CSETMw(x2, cNE); break; // Not Equal
case 5: CSETMw(x2, cCS); break; // Greater or equal or unordered
case 6: CSETMw(x2, cHI); break; // Greater or unordered, test inverted, N!=V so unordered or less than (inverted)
case 6: CSETMw(x2, cLT); break; // Greater or unordered, test inverted, N!=V so unordered or less than (inverted)
case 7: CSETMw(x2, cVC); break; // not NaN
}
VMOVQSfrom(v0, 0, x2);
@@ -411,7 +407,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
nextop = F8;
GETGX_empty(v0);
if(MODREG) {
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, (nextop&7));
v1 = mmx_get_reg(dyn, ninst, x1, (nextop&7));
VEORQ(v0, v0, v0); // usefull?
VMOV(v0, v1);
} else {
@@ -423,14 +419,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0xE6:
INST_NAME("CVTDQ2PD Gx, Ex");
nextop = F8;
// cannot use GETEX because we want 64bits not 32bits
if(MODREG) {
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
} else {
v1 = fpu_get_scratch(dyn);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0xfff<<3, 7, rex, 0, 0);
VLDR64_U12(v1, ed, fixedaddress);
}
GETEX(v1, 0);
GETGX_empty(v0);
d0 = fpu_get_scratch(dyn);
SXTL_32(v0, v1);
+466
View File
@@ -0,0 +1,466 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <math.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "tools/bridge_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "emu/x87emu_private.h"
#include "x64trace.h"
#include "signals.h"
#include "dynarec_arm64.h"
#include "dynarec_arm64_private.h"
#include "dynarec_arm64_functions.h"
#include "custommem.h"
#include "bridge.h"
void arm_fstp(x64emu_t* emu, void* p)
{
if(ST0.q!=STld(0).uref)
D2LD(&ST0.d, p);
else
memcpy(p, &STld(0).ld, 10);
}
void arm_print_armreg(x64emu_t* emu, uintptr_t reg, uintptr_t n)
{
(void)emu;
dynarec_log(LOG_DEBUG, "R%lu=0x%lx (%lu)\n", n, reg, reg);
}
void arm_f2xm1(x64emu_t* emu)
{
ST0.d = exp2(ST0.d) - 1.0;
}
void arm_fyl2x(x64emu_t* emu)
{
ST(1).d = log2(ST0.d)*ST(1).d;
}
void arm_ftan(x64emu_t* emu)
{
ST0.d = tan(ST0.d);
emu->sw.f.F87_C2 = 0;
}
void arm_fpatan(x64emu_t* emu)
{
ST1.d = atan2(ST1.d, ST0.d);
}
void arm_fxtract(x64emu_t* emu)
{
int32_t tmp32s = (ST1.q&0x7ff0000000000000LL)>>52;
tmp32s -= 1023;
ST1.d /= exp2(tmp32s);
ST0.d = tmp32s;
}
void arm_fprem(x64emu_t* emu)
{
int32_t tmp32s = ST0.d / ST1.d;
ST0.d -= ST1.d * tmp32s;
emu->sw.f.F87_C2 = 0;
emu->sw.f.F87_C0 = (tmp32s&1);
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
emu->sw.f.F87_C1 = ((tmp32s>>2)&1);
}
void arm_fyl2xp1(x64emu_t* emu)
{
ST(1).d = log2(ST0.d + 1.0)*ST(1).d;
}
void arm_fsincos(x64emu_t* emu)
{
sincos(ST1.d, &ST1.d, &ST0.d);
emu->sw.f.F87_C2 = 0;
}
void arm_frndint(x64emu_t* emu)
{
ST0.d = fpu_round(emu, ST0.d);
}
void arm_fscale(x64emu_t* emu)
{
if(ST0.d!=0.0)
ST0.d *= exp2(trunc(ST1.d));
}
void arm_fsin(x64emu_t* emu)
{
ST0.d = sin(ST0.d);
emu->sw.f.F87_C2 = 0;
}
void arm_fcos(x64emu_t* emu)
{
ST0.d = cos(ST0.d);
emu->sw.f.F87_C2 = 0;
}
void arm_fbld(x64emu_t* emu, uint8_t* ed)
{
fpu_fbld(emu, ed);
}
void arm_fild64(x64emu_t* emu, int64_t* ed)
{
int64_t tmp;
memcpy(&tmp, ed, sizeof(tmp));
ST0.d = tmp;
STll(0).sq = tmp;
STll(0).sref = ST0.sq;
}
void arm_fbstp(x64emu_t* emu, uint8_t* ed)
{
fpu_fbst(emu, ed);
}
void arm_fistp64(x64emu_t* emu, int64_t* ed)
{
// used of memcpy to avoid aligments issues
if(STll(0).sref==ST(0).sq) {
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))
tmp = 0x8000000000000000LL;
else
tmp = fpu_round(emu, ST0.d);
memcpy(ed, &tmp, sizeof(tmp));
}
}
void arm_fistt64(x64emu_t* emu, int64_t* ed)
{
// used of memcpy to avoid aligments issues
int64_t tmp = ST0.d;
memcpy(ed, &tmp, sizeof(tmp));
}
void arm_fld(x64emu_t* emu, uint8_t* ed)
{
memcpy(&STld(0).ld, ed, 10);
LD2D(&STld(0), &ST(0).d);
STld(0).uref = ST0.q;
}
void arm_ud(x64emu_t* emu)
{
emit_signal(emu, SIGILL, (void*)R_RIP, 0);
}
void arm_fsave(x64emu_t* emu, uint8_t* ed)
{
fpu_savenv(emu, (char*)ed, 0);
uint8_t* p = ed;
p += 28;
for (int i=0; i<8; ++i) {
LD2D(p, &ST(i).d);
p+=10;
}
}
void arm_frstor(x64emu_t* emu, uint8_t* ed)
{
fpu_loadenv(emu, (char*)ed, 0);
uint8_t* p = ed;
p += 28;
for (int i=0; i<8; ++i) {
D2LD(&ST(i).d, p);
p+=10;
}
}
void arm_fprem1(x64emu_t* emu)
{
// simplified version
int32_t tmp32s = round(ST0.d / ST1.d);
ST0.d -= ST1.d*tmp32s;
emu->sw.f.F87_C2 = 0;
emu->sw.f.F87_C0 = (tmp32s&1);
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
emu->sw.f.F87_C1 = ((tmp32s>>2)&1);
}
static uint8_t ff_mult(uint8_t a, uint8_t b)
{
int retval = 0;
for(int i = 0; i < 8; i++) {
if((b & 1) == 1)
retval ^= a;
if((a & 0x80)) {
a <<= 1;
a ^= 0x1b;
} else {
a <<= 1;
}
b >>= 1;
}
return retval;
}
void arm_aesimc(x64emu_t* emu, int xmm)
{
sse_regs_t eax1 = emu->xmm[xmm];
for(int j=0; j<4; ++j) {
emu->xmm[xmm].ub[0+j*4] = ff_mult(0x0E, eax1.ub[0+j*4]) ^ ff_mult(0x0B, eax1.ub[1+j*4]) ^ ff_mult(0x0D, eax1.ub[2+j*4]) ^ ff_mult(0x09, eax1.ub[3+j*4]);
emu->xmm[xmm].ub[1+j*4] = ff_mult(0x09, eax1.ub[0+j*4]) ^ ff_mult(0x0E, eax1.ub[1+j*4]) ^ ff_mult(0x0B, eax1.ub[2+j*4]) ^ ff_mult(0x0D, eax1.ub[3+j*4]);
emu->xmm[xmm].ub[2+j*4] = ff_mult(0x0D, eax1.ub[0+j*4]) ^ ff_mult(0x09, eax1.ub[1+j*4]) ^ ff_mult(0x0E, eax1.ub[2+j*4]) ^ ff_mult(0x0B, eax1.ub[3+j*4]);
emu->xmm[xmm].ub[3+j*4] = ff_mult(0x0B, eax1.ub[0+j*4]) ^ ff_mult(0x0D, eax1.ub[1+j*4]) ^ ff_mult(0x09, eax1.ub[2+j*4]) ^ ff_mult(0x0E, eax1.ub[3+j*4]);
}
}
void arm_aesmc(x64emu_t* emu, int xmm)
{
sse_regs_t eax1 = emu->xmm[xmm];
for(int j=0; j<4; ++j) {
emu->xmm[xmm].ub[0+j*4] = ff_mult(0x02, eax1.ub[0+j*4]) ^ ff_mult(0x03, eax1.ub[1+j*4]) ^ eax1.ub[2+j*4] ^ eax1.ub[3+j*4] ;
emu->xmm[xmm].ub[1+j*4] = eax1.ub[0+j*4] ^ ff_mult(0x02, eax1.ub[1+j*4]) ^ ff_mult(0x03, eax1.ub[2+j*4]) ^ eax1.ub[3+j*4] ;
emu->xmm[xmm].ub[2+j*4] = eax1.ub[0+j*4] ^ eax1.ub[1+j*4] ^ ff_mult(0x02, eax1.ub[2+j*4]) ^ ff_mult(0x03, eax1.ub[3+j*4]);
emu->xmm[xmm].ub[3+j*4] = ff_mult(0x03, eax1.ub[0+j*4]) ^ eax1.ub[1+j*4] ^ eax1.ub[2+j*4] ^ ff_mult(0x02, eax1.ub[3+j*4]);
}
}
void arm_aesdlast(x64emu_t* emu, int xmm)
{
// A0 B1 C2 D3 E4 F5 G6 H7 I8 J9 Ka Lb Mc Nd Oe Pf
// A N K H E B O L I F C P M J G D
const uint8_t invshiftrows[] = {0,13,10, 7, 4, 1,14,11, 8, 5, 2,15,12, 9, 6, 3};
const uint8_t invsubbytes[256] = {
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
};
sse_regs_t eax1;
for(int i=0; i<16; ++i)
eax1.ub[i] = emu->xmm[xmm].ub[invshiftrows[i]];
//STATE ← InvSubBytes( STATE );
for(int i=0; i<16; ++i)
emu->xmm[xmm].ub[i] = invsubbytes[eax1.ub[i]];
}
void arm_aeselast(x64emu_t* emu, int xmm)
{
// A0 B1 C2 D3 E4 F5 G6 H7 I8 J9 Ka Lb Mc Nd Oe Pf
// A F K P E J O D I N C H M B G L
const uint8_t shiftrows[] = {0, 5,10,15, 4, 9,14, 3, 8,13, 2, 7,12, 1, 6,11};
const uint8_t subbytes[256] = {
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
};
sse_regs_t eax1;
for(int i=0; i<16; ++i)
eax1.ub[i] = emu->xmm[xmm].ub[shiftrows[i]];
//STATE ← SubBytes( STATE );
for(int i=0; i<16; ++i)
emu->xmm[xmm].ub[i] = subbytes[eax1.ub[i]];
}
void arm_aesd(x64emu_t* emu, int xmm)
{
arm_aesdlast(emu, xmm);
arm_aesimc(emu, xmm);
}
void arm_aese(x64emu_t* emu, int xmm)
{
arm_aeselast(emu, xmm);
arm_aesmc(emu, xmm);
}
#define XMM0 0
#define XMM8 16
#define X870 8
#define EMM0 8
#define SCRATCH0 24
// Get a FPU scratch reg
int fpu_get_scratch(dynarec_arm_t* dyn)
{
return SCRATCH0 + dyn->fpu_scratch++; // return an Sx
}
// Reset scratch regs counter
void fpu_reset_scratch(dynarec_arm_t* dyn)
{
dyn->fpu_scratch = 0;
}
// Get a x87 double reg
int fpu_get_reg_x87(dynarec_arm_t* dyn)
{
int i=X870;
while (dyn->fpuused[i]) ++i;
dyn->fpuused[i] = 1;
return i; // return a Dx
}
// Free a FPU double reg
void fpu_free_reg(dynarec_arm_t* dyn, int reg)
{
// TODO: check upper limit?
dyn->fpuused[reg] = 0;
}
// Get an MMX double reg
int fpu_get_reg_emm(dynarec_arm_t* dyn, int emm)
{
dyn->fpuused[EMM0 + emm] = 1;
return EMM0 + emm;
}
// Get an XMM quad reg
int fpu_get_reg_xmm(dynarec_arm_t* dyn, int xmm)
{
if(xmm>7) {
dyn->fpuused[XMM8 + xmm - 8] = 1;
return XMM8 + xmm - 8;
} else {
dyn->fpuused[XMM0 + xmm] = 1;
return XMM0 + xmm;
}
}
// Reset fpu regs counter
void fpu_reset_reg(dynarec_arm_t* dyn)
{
dyn->fpu_reg = 0;
for (int i=0; i<32; ++i)
dyn->fpuused[i]=0;
}
#define F8 *(uint8_t*)(addr++)
#define F32 *(uint32_t*)(addr+=4, addr-4)
#define F32S64 (uint64_t)(int64_t)*(int32_t*)(addr+=4, addr-4)
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity, int delta)
{
(void)dyn; (void)ninst;
uint32_t tested = (1<<parity)-1;
if((nextop&0xC0)==0xC0)
return 0; // direct register, no parity...
if(!(nextop&0xC0)) {
if((nextop&7)==4) {
uint8_t sib = F8;
int sib_reg = (sib>>3)&7;
if((sib&0x7)==5) {
uint64_t tmp = F32S64;
if (sib_reg!=4) {
// if XXXXXX+reg<<N then check parity of XXXXX and N should be enough
return ((tmp&tested)==0 && (sib>>6)>=parity)?1:0;
} else {
// just a constant...
return (tmp&tested)?0:1;
}
} else {
if(sib_reg==4 && parity<3)
return 0; // simple [reg]
// don't try [reg1 + reg2<<N], unless reg1 is ESP
return ((sib&0x7)==4 && (sib>>6)>=parity)?1:0;
}
} else if((nextop&7)==5) {
uint64_t tmp = F32S64;
tmp+=addr+delta;
return (tmp&tested)?0:1;
} else {
return 0;
}
} else {
return 0; //Form [reg1 + reg2<<N + XXXXXX]
}
}
// Do the GETED, but don't emit anything...
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop)
{
(void)dyn; (void)addr; (void)ninst;
if((nextop&0xC0)==0xC0)
return addr;
if(!(nextop&0xC0)) {
if((nextop&7)==4) {
uint8_t sib = F8;
if((sib&0x7)==5) {
addr+=4;
}
} else if((nextop&7)==5) {
addr+=4;
}
} else {
if((nextop&7)==4) {
++addr;
}
if(nextop&0x80) {
addr+=4;
} else {
++addr;
}
}
return addr;
}
#undef F8
#undef F32
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn)
{
(void)dyn;
#define PK(a) *(uint8_t*)(addr+a)
#define PK32(a) *(int32_t*)(addr+a)
if(!addr || !getProtection(addr))
return 0;
if(PK(0)==0xff && PK(1)==0x25) { // "absolute" jump, maybe the GOT (well, RIP relative in fact)
uintptr_t a1 = addr + 6 + (PK32(2)); // need to add a check to see if the address is from the GOT !
addr = (uintptr_t)getAlternate(*(void**)a1);
}
if(!addr || !getProtection(addr))
return 0;
onebridge_t *b = (onebridge_t*)(addr);
if(b->CC==0xCC && b->S=='S' && b->C=='C' && b->w!=(wrapper_t)0 && b->f!=(uintptr_t)PltResolver) {
// found !
if(retn) *retn = (b->C3==0xC2)?b->N:0;
if(calladdress) *calladdress = addr+1;
return 1;
}
return 0;
#undef PK32
#undef PK
}
@@ -43,43 +43,16 @@ int fpu_get_scratch(dynarec_arm_t* dyn);
// Reset scratch regs counter
void fpu_reset_scratch(dynarec_arm_t* dyn);
// Get an x87 double reg
int fpu_get_reg_x87(dynarec_arm_t* dyn, int t, int n);
int fpu_get_reg_x87(dynarec_arm_t* dyn);
// Get an MMX double reg
int fpu_get_reg_emm(dynarec_arm_t* dyn, int emm);
// Get an XMM quad reg
int fpu_get_reg_xmm(dynarec_arm_t* dyn, int t, int xmm);
int fpu_get_reg_xmm(dynarec_arm_t* dyn, int xmm);
// Free a FPU/MMX/XMM reg
void fpu_free_reg(dynarec_arm_t* dyn, int reg);
// Reset fpu regs counter
void fpu_reset_reg(dynarec_arm_t* dyn);
// ---- Neon cache functions
// Get type for STx
int neoncache_get_st(dynarec_arm_t* dyn, int ninst, int a);
// Get if STx is FLOAT or DOUBLE
int neoncache_get_st_f(dynarec_arm_t* dyn, int ninst, int a);
// Get actual type for STx
int neoncache_get_current_st(dynarec_arm_t* dyn, int ninst, int a);
// Get actual STx is FLOAT or DOUBLE
int neoncache_get_current_st_f(dynarec_arm_t* dyn, int a);
// Back-propagate a change float->double
void neoncache_promote_double(dynarec_arm_t* dyn, int ninst, int a);
// Combine and propagate if needed (pass 1 only)
int neoncache_combine_st(dynarec_arm_t* dyn, int ninst, int a, int b); // with stack current dyn->n_stack*
// FPU Cache transformation (for loops)
int fpuCacheNeedsTransform(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);
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity, int delta);
// Do the GETED, but don't emit anything...
@@ -88,6 +61,4 @@ uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
// Is what pointed at addr a native call? And if yes, to what function?
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn);
const char* getCacheName(int t, int n);
#endif //__DYNAREC_ARM_FUNCTIONS_H__
File diff suppressed because it is too large. Load diff
@@ -244,8 +244,7 @@
ed = i; \
} else { \
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, rex, 0, D); \
ADDx_REG(x3, wback, i); \
if(wback!=x3) wback = x3; \
ADDx_REG(wback, wback, i); \
LDRB_U12(i, wback, fixedaddress); \
wb1 = 1; \
ed = i; \
@@ -313,145 +312,129 @@
// R0 will not be pushed/popd if ret is -2. Flags are not save/restored
#define CALL_S(F, ret) call_c(dyn, ninst, F, x7, ret, 0, 0)
#define MARK dyn->insts[ninst].mark = dyn->native_size
#define GETMARK dyn->insts[ninst].mark
#define MARK2 dyn->insts[ninst].mark2 = dyn->native_size
#define GETMARK2 dyn->insts[ninst].mark2
#define MARK3 dyn->insts[ninst].mark3 = dyn->native_size
#define GETMARK3 dyn->insts[ninst].mark3
#define MARKF dyn->insts[ninst].markf = dyn->native_size
#define GETMARKF dyn->insts[ninst].markf
#define MARKSEG dyn->insts[ninst].markseg = dyn->native_size
#define GETMARKSEG dyn->insts[ninst].markseg
#define MARKLOCK dyn->insts[ninst].marklock = dyn->native_size
#define GETMARKLOCK dyn->insts[ninst].marklock
#define MARK if(dyn->insts) {dyn->insts[ninst].mark = dyn->arm_size;}
#define GETMARK ((dyn->insts)?dyn->insts[ninst].mark:(dyn->arm_size+4))
#define MARK2 if(dyn->insts) {dyn->insts[ninst].mark2 = dyn->arm_size;}
#define GETMARK2 ((dyn->insts)?dyn->insts[ninst].mark2:(dyn->arm_size+4))
#define MARK3 if(dyn->insts) {dyn->insts[ninst].mark3 = dyn->arm_size;}
#define GETMARK3 ((dyn->insts)?dyn->insts[ninst].mark3:(dyn->arm_size+4))
#define MARKF if(dyn->insts) {dyn->insts[ninst].markf = dyn->arm_size;}
#define GETMARKF ((dyn->insts)?dyn->insts[ninst].markf:(dyn->arm_size+4))
#define MARKSEG if(dyn->insts) {dyn->insts[ninst].markseg = dyn->arm_size;}
#define GETMARKSEG ((dyn->insts)?dyn->insts[ninst].markseg:(dyn->arm_size+4))
#define MARKLOCK if(dyn->insts) {dyn->insts[ninst].marklock = dyn->arm_size;}
#define GETMARKLOCK ((dyn->insts)?dyn->insts[ninst].marklock:(dyn->arm_size+4))
// Branch to MARK if cond (use j64)
#define B_MARK(cond) \
j64 = GETMARK-(dyn->native_size); \
j64 = GETMARK-(dyn->arm_size); \
Bcond(cond, j64)
// Branch to MARK unconditionnal (use j64)
#define B_MARK_nocond \
j64 = GETMARK-(dyn->native_size); \
j64 = GETMARK-(dyn->arm_size); \
B(j64)
// Branch to MARK if reg is 0 (use j64)
#define CBZxw_MARK(reg) \
j64 = GETMARK-(dyn->native_size); \
j64 = GETMARK-(dyn->arm_size); \
CBZxw(reg, j64)
// Branch to MARK if reg is not 0 (use j64)
#define CBNZx_MARK(reg) \
j64 = GETMARK-(dyn->native_size); \
j64 = GETMARK-(dyn->arm_size); \
CBNZx(reg, j64)
// Branch to MARK if reg is not 0 (use j64)
#define CBNZw_MARK(reg) \
j64 = GETMARK-(dyn->native_size); \
j64 = GETMARK-(dyn->arm_size); \
CBNZw(reg, j64)
// Test bit N of A and branch to MARK if not set
#define TBZ_MARK(A, N) \
j64 = GETMARK-(dyn->native_size); \
TBZ(A, N, j64)
// Test bit N of A and branch to MARK if set
#define TBNZ_MARK(A, N) \
j64 = GETMARK-(dyn->native_size); \
TBNZ(A, N, j64)
// Branch to MARK2 if cond (use j64)
#define B_MARK2(cond) \
j64 = GETMARK2-(dyn->native_size); \
j64 = GETMARK2-(dyn->arm_size); \
Bcond(cond, j64)
// Branch to MARK2 unconditionnal (use j64)
#define B_MARK2_nocond \
j64 = GETMARK2-(dyn->native_size); \
j64 = GETMARK2-(dyn->arm_size); \
B(j64)
// Branch to MARK2 if reg is not 0 (use j64)
#define CBNZx_MARK2(reg) \
j64 = GETMARK2-(dyn->native_size); \
j64 = GETMARK2-(dyn->arm_size); \
CBNZx(reg, j64)
// Test bit N of A and branch to MARK2 if set
#define TBNZ_MARK2(A, N) \
j64 = GETMARK2-(dyn->native_size); \
j64 = GETMARK2-(dyn->arm_size); \
TBNZ(A, N, j64)
// Branch to MARK3 if cond (use j64)
#define B_MARK3(cond) \
j64 = GETMARK3-(dyn->native_size); \
j64 = GETMARK3-(dyn->arm_size); \
Bcond(cond, j64)
// Test bit N of A and branch to MARK3 if not set
#define TBZ_MARK2(A, N) \
j64 = GETMARK2-(dyn->native_size); \
TBZ(A, N, j64)
// Branch to MARK3 unconditionnal (use j64)
#define B_MARK3_nocond \
j64 = GETMARK3-(dyn->native_size); \
j64 = GETMARK3-(dyn->arm_size); \
B(j64)
// Branch to MARK3 if reg is not 0 (use j64)
#define CBNZx_MARK3(reg) \
j64 = GETMARK3-(dyn->native_size); \
j64 = GETMARK3-(dyn->arm_size); \
CBNZx(reg, j64)
// Branch to MARK3 if reg is 0 (use j64)
#define CBZx_MARK3(reg) \
j64 = GETMARK3-(dyn->native_size); \
CBZx(reg, j64)
// Test bit N of A and branch to MARK3 if not set
#define TBZ_MARK3(A, N) \
j64 = GETMARK3-(dyn->native_size); \
TBZ(A, N, j64)
// Test bit N of A and branch to MARK3 if set
#define TBNZ_MARK3(A, N) \
j64 = GETMARK3-(dyn->native_size); \
j64 = GETMARK3-(dyn->arm_size); \
TBNZ(A, N, j64)
// Test bit N of A and branch to MARK3 if not set
#define TBZ_MARK3(A, N) \
j64 = GETMARK3-(dyn->arm_size); \
TBZ(A, N, j64)
// Branch to next instruction if cond (use j64)
#define B_NEXT(cond) \
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0; \
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->arm_size)):0; \
Bcond(cond, j64)
// Branch to next instruction unconditionnal (use j64)
#define B_NEXT_nocond \
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;\
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->arm_size)):0;\
B(j64)
// Branch to next instruction if reg is 0 (use j64)
#define CBZw_NEXT(reg) \
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0; \
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->arm_size)):0; \
CBZw(reg, j64)
// Branch to next instruction if reg is 0 (use j64)
#define CBZx_NEXT(reg) \
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0; \
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->arm_size)):0; \
CBZx(reg, j64)
// Branch to next instruction if reg is not 0 (use j64)
#define CBNZx_NEXT(reg) \
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0; \
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->arm_size)):0; \
CBNZx(reg, j64)
// Test bit N of A and branch to next instruction if not set
#define TBZ_NEXT(A, N) \
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0; \
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->arm_size)):0; \
TBZ(A, N, j64)
// Test bit N of A and branch to next instruction if set
#define TBNZ_NEXT(A, N) \
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0; \
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->arm_size)):0; \
TBNZ(A, N, j64)
// Branch to MARKSEG if cond (use j64)
#define B_MARKSEG(cond) \
j64 = GETMARKSEG-(dyn->native_size); \
j64 = GETMARKSEG-(dyn->arm_size); \
Bcond(cond, j64)
// Branch to MARKSEG if reg is 0 (use j64)
#define CBZw_MARKSEG(reg) \
j64 = GETMARKSEG-(dyn->native_size); \
j64 = GETMARKSEG-(dyn->arm_size); \
CBZw(reg, j64)
// Branch to MARKSEG if reg is not 0 (use j64)
#define CBNZw_MARKSEG(reg) \
j64 = GETMARKSEG-(dyn->native_size); \
j64 = GETMARKSEG-(dyn->arm_size); \
CBNZw(reg, j64)
// Branch to MARKLOCK if cond (use j64)
#define B_MARKLOCK(cond) \
j64 = GETMARKLOCK-(dyn->native_size); \
j64 = GETMARKLOCK-(dyn->arm_size); \
Bcond(cond, j64)
// Branch to MARKLOCK if reg is not 0 (use j64)
#define CBNZx_MARKLOCK(reg) \
j64 = GETMARKLOCK-(dyn->native_size); \
j64 = GETMARKLOCK-(dyn->arm_size); \
CBNZx(reg, j64)
#define IFX(A) if((dyn->insts[ninst].x64.need_flags&(A)))
#define IFX_PENDOR0 if((dyn->insts[ninst].x64.need_flags&(X_PEND) || !dyn->insts[ninst].x64.need_flags))
#define IFXX(A) if((dyn->insts[ninst].x64.need_flags==(A)))
#define IFX2X(A, B) if((dyn->insts[ninst].x64.need_flags==(A) || dyn->insts[ninst].x64.need_flags==(B) || dyn->insts[ninst].x64.need_flags==((A)|(B))))
#define IFXN(A, B) if((dyn->insts[ninst].x64.need_flags&(A) && !(dyn->insts[ninst].x64.need_flags&(B))))
#define IFX(A) if(dyn->insts && (dyn->insts[ninst].x64.need_flags&(A)))
#define IFX_PENDOR0 if(dyn->insts && (dyn->insts[ninst].x64.need_flags&(X_PEND) || !dyn->insts[ninst].x64.need_flags))
#define IFXX(A) if(dyn->insts && (dyn->insts[ninst].x64.need_flags==(A)))
#define IFX2X(A, B) if(dyn->insts && (dyn->insts[ninst].x64.need_flags==(A) || dyn->insts[ninst].x64.need_flags==(B) || dyn->insts[ninst].x64.need_flags==((A)|(B))))
#define IFXN(A, B) if(dyn->insts && (dyn->insts[ninst].x64.need_flags&(A) && !(dyn->insts[ninst].x64.need_flags&(B))))
// Generate FCOM with s1 and s2 scratch regs (the VCMP is already done)
#define FCOM(s1, s2, s3) \
@@ -570,47 +553,35 @@
LDP_REGS(R12, R13); \
LDP_REGS(R14, R15)
#define SET_DFNONE(S) if(!dyn->f.dfnone) {MOVZw(S, d_none); STRw_U12(S, xEmu, offsetof(x64emu_t, df)); dyn->f.dfnone=1;}
#define SET_DF(S, N) if((N)!=d_none) {MOVZw(S, (N)); STRw_U12(S, xEmu, offsetof(x64emu_t, df)); dyn->f.dfnone=0;} else SET_DFNONE(S)
#define SET_NODF() dyn->f.dfnone = 0
#define SET_DFOK() dyn->f.dfnone = 1
#define SET_DFNONE(S) if(!dyn->dfnone) {MOVZw(S, d_none); STRw_U12(S, xEmu, offsetof(x64emu_t, df)); dyn->dfnone=1;}
#define SET_DF(S, N) if((N)!=d_none) {MOVZw(S, (N)); STRw_U12(S, xEmu, offsetof(x64emu_t, df)); dyn->dfnone=0;} else SET_DFNONE(S)
#define SET_NODF() dyn->dfnone = 0
#define SET_DFOK() dyn->dfnone = 1
#ifndef READFLAGS
#define READFLAGS(A) \
if(((A)!=X_PEND && dyn->f.pending!=SF_SET) \
&& (dyn->f.pending!=SF_SET_PENDING)) { \
if(dyn->f.pending!=SF_PENDING) { \
if(((A)!=X_PEND) && dyn->state_flags!=SF_SET && dyn->state_flags!=SF_SET_PENDING) { \
if(dyn->state_flags!=SF_PENDING) { \
LDRw_U12(x3, xEmu, offsetof(x64emu_t, df)); \
j64 = (GETMARKF)-(dyn->native_size); \
j64 = (GETMARKF)-(dyn->arm_size); \
CBZw(x3, j64); \
} \
CALL_(UpdateFlags, -1, 0); \
MARKF; \
dyn->f.pending = SF_SET; \
dyn->state_flags = SF_SET; \
SET_DFOK(); \
}
#endif
// SF_MAYSET doesn't change the flags status cache
// it also doesn't consume any needed flags
#ifndef SETFLAGS
#define SETFLAGS(A, B) \
if(dyn->f.pending!=SF_SET \
&& (B==SF_SUBSET || B==SF_SUBSET_PENDING) \
&& (dyn->insts[ninst].x64.need_flags&(~((A)|((B==SF_SUBSET_PENDING)?X_PEND:0))))) \
READFLAGS(dyn->insts[ninst].x64.need_flags&(~(A)|X_PEND)); \
if(dyn->insts[ninst].x64.need_flags) switch(B) { \
case SF_SUBSET: \
case SF_SET: dyn->f.pending = SF_SET; break; \
case SF_PENDING: dyn->f.pending = SF_PENDING; break; \
case SF_SUBSET_PENDING: \
case SF_SET_PENDING: \
dyn->f.pending = (dyn->insts[ninst].x64.need_flags&X_PEND)?SF_SET_PENDING:SF_SET; \
break; \
case SF_MAYSET: break; \
} else dyn->f.pending = SF_SET
#define SETFLAGS(A, B) \
if(dyn->state_flags!=SF_SET && B==SF_SUBSET && (dyn->insts[ninst].x64.need_flags&(~((A)/*|X_PEND*/)))) \
READFLAGS(dyn->insts[ninst].x64.need_flags&(~(A)|X_PEND)); \
dyn->state_flags = (B==SF_SUBSET)?SF_SET: \
((B==SF_SET_PENDING && !(dyn->insts[ninst].x64.need_flags&X_PEND)?SF_SET:B))
#endif
#ifndef JUMP
#define JUMP(A, C)
#define JUMP(A)
#endif
#ifndef BARRIER
#define BARRIER(A)
@@ -618,12 +589,12 @@
#ifndef BARRIER_NEXT
#define BARRIER_NEXT(A)
#endif
#define UFLAG_OP1(A) if(dyn->insts[ninst].x64.need_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, op1));}
#define UFLAG_OP2(A) if(dyn->insts[ninst].x64.need_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, op2));}
#define UFLAG_OP12(A1, A2) if(dyn->insts[ninst].x64.need_flags) {STRxw_U12(A1, xEmu, offsetof(x64emu_t, op1));STRxw_U12(A2, 0, offsetof(x64emu_t, op2));}
#define UFLAG_RES(A) if(dyn->insts[ninst].x64.need_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, res));}
#define UFLAG_DF(r, A) if(dyn->insts[ninst].x64.need_flags) {SET_DF(r, A)}
#define UFLAG_IF if(dyn->insts[ninst].x64.need_flags)
#define UFLAG_OP1(A) if(dyn->insts && dyn->insts[ninst].x64.need_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, op1));}
#define UFLAG_OP2(A) if(dyn->insts && dyn->insts[ninst].x64.need_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, op2));}
#define UFLAG_OP12(A1, A2) if(dyn->insts && dyn->insts[ninst].x64.need_flags) {STRxw_U12(A1, xEmu, offsetof(x64emu_t, op1));STRxw_U12(A2, 0, offsetof(x64emu_t, op2));}
#define UFLAG_RES(A) if(dyn->insts && dyn->insts[ninst].x64.need_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, res));}
#define UFLAG_DF(r, A) if(dyn->insts && dyn->insts[ninst].x64.need_flags) {SET_DF(r, A)}
#define UFLAG_IF if(dyn->insts && dyn->insts[ninst].x64.need_flags)
#ifndef DEFAULT
#define DEFAULT *ok = -1; BARRIER(2)
#endif
@@ -667,7 +638,6 @@
TABLE64(xRIP, (A)); \
}
#endif
#define CLEARIP() dyn->last_ip=0
#if STEP < 2
#define PASS2IF(A, B) if(A)
@@ -688,7 +658,7 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
#define STEPNAME(N) STEPNAME2(N, STEP)
#endif
#define native_pass STEPNAME(native_pass)
#define arm_pass STEPNAME(arm_pass)
#define dynarec64_00 STEPNAME(dynarec64_00)
#define dynarec64_0F STEPNAME(dynarec64_0F)
@@ -796,16 +766,12 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
#define x87_do_push STEPNAME(x87_do_push)
#define x87_do_push_empty STEPNAME(x87_do_push_empty)
#define x87_do_pop STEPNAME(x87_do_pop)
#define x87_get_current_cache STEPNAME(x87_get_current_cache)
#define x87_get_cache STEPNAME(x87_get_cache)
#define x87_get_neoncache STEPNAME(x87_get_neoncache)
#define x87_get_st STEPNAME(x87_get_st)
#define x87_get_st_empty STEPNAME(x87_get_st)
#define x87_refresh STEPNAME(x87_refresh)
#define x87_forget STEPNAME(x87_forget)
#define x87_reget_st STEPNAME(x87_reget_st)
#define x87_stackcount STEPNAME(x87_stackcount)
#define x87_swapreg STEPNAME(x87_swapreg)
#define x87_setround STEPNAME(x87_setround)
#define x87_restoreround STEPNAME(x87_restoreround)
#define sse_setround STEPNAME(sse_setround)
@@ -826,8 +792,6 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
#define fpu_reflectcache STEPNAME(fpu_reflectcache)
#endif
#define fpuCacheTransform STEPNAME(fpuCacheTransform)
/* setup r2 to address pointed by */
uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int absmax, uint32_t mask, rex_t rex, int s, int delta);
@@ -923,29 +887,21 @@ void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
// cache of the local stack counter, to avoid upadte at every call
void x87_stackcount(dynarec_arm_t* dyn, int ninst, int scratch);
// fpu push. Return the Dd value to be used
int x87_do_push(dynarec_arm_t* dyn, int ninst, int s1, int t);
int x87_do_push(dynarec_arm_t* dyn, int ninst);
// fpu push. Do not allocate a cache register. Needs a scratch register to do x87stack synch (or 0 to not do it)
void x87_do_push_empty(dynarec_arm_t* dyn, int ninst, int s1);
// fpu pop. All previous returned Dd should be considered invalid
void x87_do_pop(dynarec_arm_t* dyn, int ninst, int s1);
// get cache index for a x87 reg, return -1 if cache doesn't exist
int x87_get_current_cache(dynarec_arm_t* dyn, int ninst, int st, int t);
void x87_do_pop(dynarec_arm_t* dyn, int ninst);
// get cache index for a x87 reg, create the entry if needed
int x87_get_cache(dynarec_arm_t* dyn, int ninst, int populate, int s1, int s2, int a, int t);
// get neoncache index for a x87 reg
int x87_get_neoncache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a);
int x87_get_cache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a);
// get vfpu register for a x87 reg, create the entry if needed
int x87_get_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a, int t);
// get vfpu register for a x87 reg, create the entry if needed. Do not fetch the Stx if not already in cache
int x87_get_st_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a, int t);
int x87_get_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a);
// refresh a value from the cache ->emu (nothing done if value is not cached)
void x87_refresh(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st);
// refresh a value from the cache ->emu and then forget the cache (nothing done if value is not cached)
void x87_forget(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st);
// refresh the cache value from emu
void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st);
// swap 2 x87 regs
void x87_swapreg(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a, int b);
// Set rounding according to cw flags, return reg to restore flags
int x87_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
// Restore round flag
@@ -953,47 +909,15 @@ void x87_restoreround(dynarec_arm_t* dyn, int ninst, int s1);
// Set rounding according to mxcsr flags, return reg to restore flags
int sse_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
#if STEP < 2
#define CHECK_CACHE() 0
#else
#define CHECK_CACHE() fpuCacheNeedsTransform(dyn, ninst)
#endif
#define neoncache_st_coherency STEPNAME(neoncache_st_coherency)
int neoncache_st_coherency(dynarec_arm_t* dyn, int ninst, int a, int b);
#if STEP == 0
#define ST_IS_F(A) 0
#define X87_COMBINE(A, B) NEON_CACHE_ST_D
#define X87_ST0 NEON_CACHE_ST_D
#define X87_ST(A) NEON_CACHE_ST_D
#elif STEP == 1
#define ST_IS_F(A) (neoncache_get_current_st(dyn, ninst, A)==NEON_CACHE_ST_F)
#define X87_COMBINE(A, B) neoncache_combine_st(dyn, ninst, A, B)
#define X87_ST0 neoncache_get_current_st(dyn, ninst, 0)
#define X87_ST(A) neoncache_get_current_st(dyn, ninst, A)
#else
#define ST_IS_F(A) (neoncache_get_st(dyn, ninst, A)==NEON_CACHE_ST_F)
#if STEP == 3
#define X87_COMBINE(A, B) neoncache_st_coherency(dyn, ninst, A, B)
#else
#define X87_COMBINE(A, B) neoncache_get_st(dyn, ninst, A)
#endif
#define X87_ST0 neoncache_get_st(dyn, ninst, 0)
#define X87_ST(A) neoncache_get_st(dyn, ninst, A)
#endif
//MMX helpers
// get neon register for a MMX reg, create the entry if needed
int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a);
int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a);
// get neon register for a MMX reg, but don't try to synch it if it needed to be created
int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a);
int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a);
//SSE/SSE2 helpers
// get neon register for a SSE reg, create the entry if needed
int sse_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a, int forwrite);
int sse_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a);
// get neon register for a SSE reg, but don't try to synch it if it needed to be created
int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a);
// forget neon register for a SSE reg, create the entry if needed
@@ -1003,13 +927,13 @@ void sse_purge07cache(dynarec_arm_t* dyn, int ninst, int s1);
// common coproc helpers
// reset the cache
void fpu_reset(dynarec_arm_t* dyn);
void fpu_reset(dynarec_arm_t* dyn, int ninst);
// purge the FPU cache (needs 3 scratch registers)
void fpu_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int s3);
void fpu_purgecache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
// purge MMX cache
void mmx_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1);
void mmx_purgecache(dynarec_arm_t* dyn, int ninst, int s1);
// purge x87 cache
void x87_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 s1, int s2, int s3);
#ifdef HAVE_TRACE
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
#endif
+140
View File
@@ -0,0 +1,140 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <pthread.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_arm64.h"
#include "dynarec_arm64_private.h"
#include "arm64_printer.h"
#include "dynarec_arm64_functions.h"
#include "dynarec_arm64_helper.h"
#include "custommem.h"
#ifndef STEP
#error No STEP defined
#endif
uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
{
int ok = 1;
int ninst = 0;
uintptr_t ip = addr;
uintptr_t init_addr = addr;
rex_t rex;
int rep; // 0 none, 1=F2 prefix, 2=F3 prefix
int need_epilog = 1;
dyn->sons_size = 0;
// Clean up (because there are multiple passes)
dyn->state_flags = 0;
dyn->dfnone = 0;
dyn->last_ip = ip; // RIP is always set at start of block!
MAYUSE(init_addr);
fpu_reset(dyn, ninst);
// ok, go now
INIT;
while(ok) {
ip = addr;
if(dyn->insts && (dyn->insts[ninst].x64.barrier==1)) {
dyn->last_ip = 0;
NEW_BARRIER_INST;
}
NEW_INST;
fpu_reset_scratch(dyn);
#ifdef HAVE_TRACE
if(my_context->dec && box64_dynarec_trace) {
if((trace_end == 0)
|| ((ip >= trace_start) && (ip < trace_end))) {
MESSAGE(LOG_DUMP, "TRACE ----\n");
fpu_reflectcache(dyn, ninst, x1, x2, x3);
GETIP(ip);
MOVx_REG(x1, xRIP);
STORE_XEMU_CALL(xRIP);
MOV32w(x2, 1);
CALL(PrintTrace, -1);
LOAD_XEMU_CALL(xRIP);
MESSAGE(LOG_DUMP, "----------\n");
}
}
#endif
rep = 0;
uint8_t pk = PK(0);
while((pk==0xF2) || (pk==0xF3)) {
rep = pk-0xF1;
++addr;
pk = PK(0);
}
while(pk==0x3E) { //Branch Taken Hint ignored
++addr;
pk = PK(0);
}
rex.rex = 0;
while(pk>=0x40 && pk<=0x4f) {
rex.rex = pk;
++addr;
pk = PK(0);
}
addr = dynarec64_00(dyn, addr, ip, ninst, rex, rep, &ok, &need_epilog);
INST_EPILOG;
if(dyn->insts && dyn->insts[ninst+1].x64.barrier) {
fpu_purgecache(dyn, ninst, x1, x2, x3);
if(dyn->insts[ninst+1].x64.barrier!=2) {
dyn->state_flags = 0;
dyn->dfnone = 0;
}
}
if(!ok && !need_epilog && dyn->insts && (addr < (dyn->start+dyn->isize))) {
ok = 1;
}
if(!ok && !need_epilog && !dyn->insts && getProtection(addr+3)&~PROT_CUSTOM)
if(*(uint32_t*)addr!=0) { // check if need to continue (but is next 4 bytes are 0, stop)
uintptr_t next = get_closest_next(dyn, addr);
if(next && (
(((next-addr)<15) && is_nops(dyn, addr, next-addr))
||(((next-addr)<30) && is_instructions(dyn, addr, next-addr)) ))
{
dynarec_log(LOG_DEBUG, "Extend block %p, %p -> %p (ninst=%d)\n", dyn, (void*)addr, (void*)next, ninst);
ok = 1;
} else if(next && (next-addr)<30) {
dynarec_log(LOG_DEBUG, "Cannot extend block %p -> %p (%02X %02X %02X %02X %02X %02X %02X %02x)\n", (void*)addr, (void*)next, PK(0), PK(1), PK(2), PK(3), PK(4), PK(5), PK(6), PK(7));
}
}
if(ok<0) {ok = 0; need_epilog=1;}
++ninst;
#if STEP == 0
if(ok && !isJumpTableDefault64((void*)addr))
#else
if(ok && dyn->insts && (ninst==dyn->size))
#endif
{
#if STEP == 3
dynarec_log(LOG_DEBUG, "Stopping block %p (%d / %d)\n",(void*)init_addr, ninst, dyn->size);
#endif
BARRIER(2);
fpu_purgecache(dyn, ninst, x1, x2, x3);
jump_to_next(dyn, addr, 0, ninst);
ok=0; need_epilog=0;
}
}
if(need_epilog) {
fpu_purgecache(dyn, ninst, x1, x2, x3);
jump_to_epilog(dyn, ip, 0, ninst); // no linker here, it's an unknow instruction
}
FINI;
MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d, %d sons)\n", dyn->size, dyn->sons_size);
return addr;
}
+25
View File
@@ -0,0 +1,25 @@
#define INIT uintptr_t sav_addr=addr
#define FINI dyn->isize = addr-sav_addr
#define MESSAGE(A, ...)
#define SETFLAGS(A, B)
#define READFLAGS(A)
#define EMIT(A)
#define JUMP(A) add_next(dyn, (uintptr_t)A)
#define NEW_INST ++dyn->size
#define INST_EPILOG
#define INST_NAME(name)
#define DEFAULT \
--dyn->size; \
*ok = -1; \
if(box64_dynarec_log>=LOG_INFO) {\
dynarec_log(LOG_NONE, "%p: Dynarec stopped because of Opcode %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", \
(void*)ip, PKip(0), \
PKip(1), PKip(2), PKip(3), \
PKip(4), PKip(5), PKip(6), \
PKip(7), PKip(8), PKip(9), \
PKip(10),PKip(11),PKip(12), \
PKip(13),PKip(14)); \
printFunctionAddr(ip, " => "); \
dynarec_log(LOG_NONE, "\n"); \
}
+17
View File
@@ -0,0 +1,17 @@
#define INIT
#define FINI \
dyn->insts[ninst].x64.addr = addr; \
if(ninst) dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr;
#define MESSAGE(A, ...)
#define EMIT(A)
#define READFLAGS(A) dyn->insts[ninst].x64.use_flags = A
#define SETFLAGS(A,B) {dyn->insts[ninst].x64.set_flags = A; dyn->insts[ninst].x64.state_flags = B;}
#define JUMP(A) dyn->insts[ninst].x64.jmp = A
#define BARRIER(A) dyn->insts[ninst].x64.barrier = A
#define BARRIER_NEXT(A) if(ninst<dyn->size) dyn->insts[ninst+1].x64.barrier = A
#define NEW_INST \
dyn->insts[ninst].x64.addr = ip; \
if(ninst) dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr;
#define INST_EPILOG
#define INST_NAME(name)
+11
View File
@@ -0,0 +1,11 @@
#define INIT dyn->arm_size = 0
#define FINI if(ninst) {dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size);}
#define MESSAGE(A, ...)
#define EMIT(A) dyn->insts[ninst].size+=4; dyn->arm_size+=4
#define NEW_INST if(ninst) {dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size);}
#define INST_EPILOG dyn->insts[ninst].epilog = dyn->arm_size;
#define INST_NAME(name)
#define NEW_BARRIER_INST if(ninst) ++dyn->sons_size
#define TABLE64(A, V) {Table64(dyn, (V)); EMIT(0);}
#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q); EMIT(0);}
+36
View File
@@ -0,0 +1,36 @@
#define INIT
#define FINI
#define EMIT(A) \
if(box64_dynarec_dump) {dynarec_log(LOG_NONE, "\t%08x\t%s\n", (uint32_t)(A), arm64_print(A, (uintptr_t)dyn->block));} \
*(uint32_t*)(dyn->block) = (uint32_t)(A); \
dyn->block += 4; dyn->arm_size += 4;\
dyn->insts[ninst].size2 += 4
#define MESSAGE(A, ...) if(box64_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__)
#define NEW_INST
#define INST_EPILOG
#define INST_NAME(name) \
if(box64_dynarec_dump) {\
printf_x64_instruction(my_context->dec, &dyn->insts[ninst].x64, name); \
dynarec_log(LOG_NONE, "%s%p: %d emited opcodes, state=%d/%d, set=%X, use=%X, need=%X%s\n", \
(box64_dynarec_dump>1)?"\e[32m":"", \
(void*)(dyn->arm_start+dyn->insts[ninst].address), \
dyn->insts[ninst].size/4, \
dyn->insts[ninst].x64.state_flags, \
dyn->state_flags, \
dyn->insts[ninst].x64.set_flags, \
dyn->insts[ninst].x64.use_flags, \
dyn->insts[ninst].x64.need_flags, \
(box64_dynarec_dump>1)?"\e[m":""); \
}
#define NEW_BARRIER_INST \
if(ninst) { \
dyn->sons_x64[dyn->sons_size] = (uintptr_t)ip; \
dyn->sons_arm[dyn->sons_size] = dyn->block; \
MESSAGE(LOG_DUMP, "----> potential Son here\n");\
++dyn->sons_size; \
}
#define TABLE64(A, V) {int val64offset = Table64(dyn, (V)); MESSAGE(LOG_DUMP, " Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset);}
#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q); MESSAGE(LOG_DUMP, " FTable64: %g\n", v.d); VLDR64_literal(A, val64offset);}
+62
View File
@@ -0,0 +1,62 @@
#ifndef __DYNAREC_ARM_PRIVATE_H_
#define __DYNAREC_ARM_PRIVATE_H_
#include "dynarec_private.h"
typedef struct x64emu_s x64emu_t;
typedef struct instruction_arm_s {
instruction_x64_t x64;
uintptr_t address; // (start) address of the arm emited instruction
uintptr_t epilog; // epilog of current instruction (can be start of next, of barrier stuff)
int size; // size of the arm emited instruction
int size2; // size of the arm emited instrucion after pass2
uintptr_t mark, mark2, mark3;
uintptr_t markf;
uintptr_t markseg;
uintptr_t marklock;
int pass2choice;// value for choices that are fixed on pass2 for pass3
uintptr_t natcall;
int retn;
} instruction_arm64_t;
typedef struct dynarec_arm_s {
instruction_arm64_t *insts;
int32_t size;
int32_t cap;
uintptr_t start; // start of the block
uint32_t isize; // size in byte of x64 instructions included
void* block; // memory pointer where next instruction is emited
uintptr_t arm_start; // start of the arm code
size_t arm_size; // size of emitted arm code
int state_flags;// actual state for on-demand flags
uintptr_t last_ip; // last set IP in RIP (or NULL if unclean state)
int8_t x87cache[8];// cache status for the 8 x87 register behind the fpu stack
int8_t x87reg[8]; // reg used for x87cache entry
int8_t mmxcache[8];// cache status for the 8 MMX registers
int8_t ssecache[16];// cache status for the 16 SSE(2) registers
int8_t fpuused[32];// all 8..31 Q reg from fpu, used by x87, sse and mmx
int x87stack; // cache stack counter
int fpu_scratch;// scratch counter
int fpu_reg; // x87/sse/mmx reg counter
int dfnone; // if defered flags is already set to df_none
uint64_t *table64; // table of 64bits value
int table64size;// size of table (will be appended at end of executable code)
int table64cap;
uintptr_t tablestart;
uintptr_t* next; // variable array of "next" jump address
int next_sz;
int next_cap;
uintptr_t* sons_x64; // the x64 address of potential dynablock sons
void** sons_arm; // the arm address of potential dynablock sons
int sons_size; // number of potential dynablock sons
} dynarec_arm_t;
void add_next(dynarec_arm_t *dyn, uintptr_t addr);
uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr);
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n);
int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n);
int Table64(dynarec_arm_t *dyn, uint64_t val); // add a value to etable64 (if needed) and gives back the imm19 to use in LDR_literal
#endif //__DYNAREC_ARM_PRIVATE_H_
-12
View File
@@ -1,12 +0,0 @@
#ifndef __DYNAREC_HELPER__H_
#define __DYNAREC_HELPER__H_
#ifdef ARM64
#include "arm64/dynarec_arm64_helper.h"
#elif defined(LA464)
#include "la464/dynarec_la464_helper.h"
#else
#error Unsupported architecture
#endif
#endif //__DYNAREC_HELPER__H_
-247
View File
@@ -1,247 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include "debug.h"
#include "box64context.h"
#include "dynarec.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "x64run.h"
#include "x64emu.h"
#include "box64stack.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynablock.h"
#include "dynarec_native.h"
#include "custommem.h"
#include "dynarec_arch.h"
#include "dynarec_helper.h"
#ifndef STEP
#error No STEP defined
#endif
uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr)
{
int ok = 1;
int ninst = 0;
uintptr_t ip = addr;
uintptr_t init_addr = addr;
rex_t rex;
int rep; // 0 none, 1=F2 prefix, 2=F3 prefix
int need_epilog = 1;
dyn->sons_size = 0;
// Clean up (because there are multiple passes)
dyn->f.pending = 0;
dyn->f.dfnone = 0;
fpu_reset(dyn);
int reset_n = -1;
dyn->last_ip = (dyn->insts && dyn->insts[0].pred_sz)?0:ip; // RIP is always set at start of block unless there is a predecessor!
// ok, go now
INIT;
while(ok) {
ip = addr;
if (reset_n!=-1) {
dyn->last_ip = 0;
if(reset_n==-2) {
MESSAGE(LOG_DEBUG, "Reset Caches to zero\n");
dyn->f.dfnone = 0;
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(box64_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
dyn->f = dyn->insts[reset_n].f_exit;
if(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT) {
MESSAGE(LOG_DEBUG, "Apply Barrier Float\n");
fpu_reset(dyn);
}
if(dyn->insts[ninst].x64.barrier&BARRIER_FLAGS) {
MESSAGE(LOG_DEBUG, "Apply Barrier Flags\n");
dyn->f.dfnone = 0;
dyn->f.pending = 0;
}
}
reset_n = -1;
} else if(dyn->insts[ninst].pred_sz!=1)
dyn->last_ip = 0; // reset IP if some jump are comming here
// 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;
NEW_INST;
fpu_reset_scratch(dyn);
#ifdef HAVE_TRACE
if(my_context->dec && box64_dynarec_trace) {
if((trace_end == 0)
|| ((ip >= trace_start) && (ip < trace_end))) {
MESSAGE(LOG_DUMP, "TRACE ----\n");
fpu_reflectcache(dyn, ninst, x1, x2, x3);
GO_TRACE();
MESSAGE(LOG_DUMP, "----------\n");
}
}
#endif
rep = 0;
uint8_t pk = PK(0);
while((pk==0xF2) || (pk==0xF3)) {
rep = pk-0xF1;
++addr;
pk = PK(0);
}
while(pk==0x3E) { //Branch Taken Hint ignored
++addr;
pk = PK(0);
}
rex.rex = 0;
while(pk>=0x40 && pk<=0x4f) {
rex.rex = pk;
++addr;
pk = PK(0);
}
addr = dynarec64_00(dyn, addr, ip, ninst, rex, rep, &ok, &need_epilog);
INST_EPILOG;
int next = ninst+1;
#if STEP > 0
if(!dyn->insts[ninst].x64.has_next && dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts!=-1)
next = dyn->insts[ninst].x64.jmp_insts;
#endif
if(dyn->insts[ninst].x64.has_next && dyn->insts[next].x64.barrier) {
if(dyn->insts[next].x64.barrier&BARRIER_FLOAT)
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
if(dyn->insts[next].x64.barrier&BARRIER_FLAGS) {
dyn->f.pending = 0;
dyn->f.dfnone = 0;
dyn->last_ip = 0;
}
}
#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((dyn->insts[ii].x64.barrier&BARRIER_FULL)==BARRIER_FULL)
reset_n = -2; // hack to say Barrier!
else {
reset_n = getNominalPred(dyn, ii); // may get -1 if no predecessor are availble
if(reset_n==-1) {
reset_n = -2;
MESSAGE(LOG_DEBUG, "Warning, Reset Caches mark not found\n");
}
}
}
#else
if(!ok && !need_epilog && box64_dynarec_bigblock && getProtection(addr+3)&~PROT_CUSTOM)
if(*(uint32_t*)addr!=0) { // check if need to continue (but is next 4 bytes are 0, stop)
uintptr_t next = get_closest_next(dyn, addr);
if(next && (
(((next-addr)<15) && is_nops(dyn, addr, next-addr))
/*||(((next-addr)<30) && is_instructions(dyn, addr, next-addr))*/ ))
{
ok = 1;
// need to find back that instruction to copy the caches, as previous version cannot be used anymore
reset_n = -2;
for(int ii=0; ii<ninst; ++ii)
if(dyn->insts[ii].x64.jmp == next) {
reset_n = ii;
ii=ninst;
}
if(box64_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)<30) {
if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Cannot extend block %p -> %p (%02X %02X %02X %02X %02X %02X %02X %02x)\n", (void*)addr, (void*)next, PK(0), PK(1), PK(2), PK(3), PK(4), PK(5), PK(6), PK(7));
}
}
#endif
if(ok<0) {ok = 0; need_epilog=1;}
++ninst;
#if STEP == 0
if(ok && !isJumpTableDefault64((void*)addr) && (box64_dynarec_bigblock<2))
#else
if(ok && (ninst==dyn->size))
#endif
{
int j32;
MAYUSE(j32);
MESSAGE(LOG_DEBUG, "Stopping block %p (%d / %d)\n",(void*)init_addr, ninst, dyn->size);
--ninst;
if(!dyn->insts[ninst].x64.barrier) {
BARRIER(BARRIER_FLOAT);
}
#if STEP == 0
if(dyn->insts[ninst].x64.set_flags)
dyn->insts[ninst].x64.default_need |= X_PEND;
else
dyn->insts[ninst].x64.use_flags |= X_PEND;
#endif
++ninst;
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
jump_to_next(dyn, addr, 0, ninst);
ok=0; need_epilog=0;
}
}
if(need_epilog) {
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);
return addr;
}
+12 -23
View File
@@ -1,11 +1,6 @@
#ifndef __DYNAREC_PRIVATE_H_
#define __DYNAREC_PRIVATE_H_
#define BARRIER_NONE 0
#define BARRIER_FLAGS 1
#define BARRIER_FLOAT 2
#define BARRIER_FULL 3
// all flags for the use_flags field
#define X_CF (1<<0)
#define X_PF (1<<1)
@@ -14,32 +9,26 @@
#define X_SF (1<<4)
#define X_OF (1<<5)
#define X_ALL ((1<<6)-1)
#define X_PEND (0x80)
#define X_PEND (0x1000)
// all state flags
#define SF_UNKNOWN 0
#define SF_SET 1
#define SF_PENDING 2
#define SF_SET_PENDING (SF_SET|SF_PENDING)
#define SF_SUB 4
#define SF_SUBSET (SF_SUB|SF_SET)
#define SF_SUBSET_PENDING (SF_SUBSET|SF_PENDING)
#define SF_MAYSET 8
#define SF_SET_PENDING 3
#define SF_MAYSET 4
#define SF_SUBSET 5
typedef struct instruction_x64_s {
uintptr_t addr; //address of the instruction
int32_t size; // size of the instruction
uintptr_t jmp; // offset to jump to, even if conditionnal (0 if not), no relative offset here
uintptr_t addr; //address of the instruction
int32_t size; // size of the instruction
int barrier; // next instruction is a jump point, so no optim allowed
uintptr_t jmp; // offset to jump to, even if conditionnal (0 if not), no relative offset here
int jmp_insts; // instuction to jump to (-1 if out of the block)
uint8_t jmp_cond; // 1 of conditionnal jump
uint8_t has_next; // does this opcode can continue to the next?
uint8_t barrier; // next instruction is a jump point, so no optim allowed
uint8_t state_flags;// One of SF_XXX state
uint8_t use_flags; // 0 or combination of X_?F
uint8_t set_flags; // 0 or combination of X_?F
uint8_t default_need;// 0 or X_PEND basically
uint8_t need_flags; // calculated
uint8_t old_use; // calculated
uint32_t use_flags; // 0 or combination of X_?F
uint32_t set_flags; // 0 or combination of X_?F
uint32_t need_flags; // calculated
int state_flags; // One of SF_XXX state
} instruction_x64_t;
void printf_x64_instruction(zydis_dec_t* dec, instruction_x64_t* inst, const char* name);
-25
View File
@@ -1,25 +0,0 @@
#ifndef __NATIVE_LOCK__H__
#define __NATIVE_LOCK__H__
#ifdef ARM64
#include "arm64/arm64_lock.h"
#define native_lock_read_b(A) arm64_lock_read_b(A)
#define native_lock_write_b(A, B) arm64_lock_write_b(A, B)
#define native_lock_read_h(A) arm64_lock_read_h(A)
#define native_lock_write_h(A, B) arm64_lock_write_h(A, B)
#define native_lock_read_d(A) arm64_lock_read_d(A)
#define native_lock_write_d(A, B) arm64_lock_write_d(A, B)
#define native_lock_read_dd(A) arm64_lock_read_dd(A)
#define native_lock_write_dd(A, B) arm64_lock_write_dd(A, B)
#define native_lock_read_dq(A, B, C) arm64_lock_read_dq(A, B, C)
#define native_lock_write_dq(A, B, C) arm64_lock_write_dq(A, B, C)
#define native_lock_xchg(A, B) arm64_lock_xchg(A, B)
#define native_lock_storeifref(A, B, C) arm64_lock_storeifref(A, B, C)
#define native_lock_storeifnull(A, B) arm64_lock_storeifnull(A, B)
#else
#error Unsupported architecture
#endif
#endif //#define __NATIVE_LOCK__H__
-717
View File
@@ -1,717 +0,0 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "debug.h"
#include "elfloader_private.h"
#include "elfdwarf_private.h"
typedef struct dwarf_unwind_constr_s {
uint8_t reg_count;
uint64_t *table;
uint8_t *statuses;
#define GET_STATUS(n,i) (((n).statuses[(i) >> 1] >> (((i) & 1) << 2)) & 0xF)
#define SET_STATUS(n,i,v) (n).statuses[(i) >> 1] = ((n).statuses[(i) >> 1] & (0xF0 >> (((i) & 1) << 2))) | (v << (((i) & 1) << 2))
#define REGSTATUS_undefined 0b0000
#define REGSTATUS_same_val 0b0101
#define REGSTATUS_offset 0b0010
#define REGSTATUS_val_offset 0b0011
#define REGSTATUS_register 0b0100
} dwarf_unwind_constr_t;
#define DW_EH_PE_uptr 0x00
#define DW_EH_PE_uleb128 0x01
#define DW_EH_PE_udata2 0x02
#define DW_EH_PE_udata4 0x03
#define DW_EH_PE_udata8 0x04
#define DW_EH_PE_SIZE_MASK 0x07
#define DW_EH_PE_signed 0x08
#define DW_EH_PE_absptr 0x00
#define DW_EH_PE_pcrel 0x10
#define DW_EH_PE_textrel 0x20 // Unsupported
#define DW_EH_PE_datarel 0x30 // Unsupported
#define DW_EH_PE_indirect 0x80 // May crash
#define DW_EH_PE_omit 0xff
#define READ_U1(var, ptr) do { (var) = *( uint8_t*)(ptr); (ptr) += 1; } while (0)
#define READ_S1(var, ptr) do { (var) = *( int8_t*)(ptr); (ptr) += 1; } while (0)
#define READ_U2(var, ptr) do { (var) = *(uint16_t*)(ptr); (ptr) += 2; } while (0)
#define READ_S2(var, ptr) do { (var) = *( int16_t*)(ptr); (ptr) += 2; } while (0)
#define READ_U4(var, ptr) do { (var) = *(uint32_t*)(ptr); (ptr) += 4; } while (0)
#define READ_S4(var, ptr) do { (var) = *( int32_t*)(ptr); (ptr) += 4; } while (0)
#define READ_U8(var, ptr) do { (var) = *(uint64_t*)(ptr); (ptr) += 8; } while (0)
#define READ_S8(var, ptr) do { (var) = *( int64_t*)(ptr); (ptr) += 8; } while (0)
#define READ_ULEB128(var, ptr) readULEB(&(var), &(ptr))
#define READ_SLEB128(var, ptr) readSLEB((int64_t*)&(var), &(ptr))
// Seems like DW_EH_PE_signed is actually an invalid encoding
#define READ_ENCODED(var, ptr, enc, isptr) do { uintptr_t optr = (uintptr_t)(ptr); \
if ((((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_uleb128) && ((enc) & DW_EH_PE_signed)) READ_SLEB128(var, ptr); \
else if ((((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_uleb128) && !((enc) & DW_EH_PE_signed)) READ_ULEB128(var, ptr); \
else if ((((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_udata2 ) && ((enc) & DW_EH_PE_signed)) READ_S2 (var, ptr); \
else if ((((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_udata2 ) && !((enc) & DW_EH_PE_signed)) READ_U2 (var, ptr); \
else if ((((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_udata4 ) && ((enc) & DW_EH_PE_signed)) READ_S4 (var, ptr); \
else if ((((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_udata4 ) && !((enc) & DW_EH_PE_signed)) READ_U4 (var, ptr); \
else if ((((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_udata8 ) && ((enc) & DW_EH_PE_signed)) READ_S8 (var, ptr); \
else if ((((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_udata8 ) && !((enc) & DW_EH_PE_signed)) READ_U8 (var, ptr); \
else if ((((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_uptr ) && ((enc) & DW_EH_PE_signed)) READ_S8 (var, ptr); \
else if ((((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_uptr ) && !((enc) & DW_EH_PE_signed)) READ_U8 (var, ptr); \
else { printf_log(LOG_DEBUG, "Invalid encoding 0x%02X\n", (enc)); (var) = 0; } \
if (((enc) & DW_EH_PE_pcrel) && isptr) (var) += optr; \
if ((enc) & DW_EH_PE_indirect) (var) = *(uint64_t*)(var); \
} while (0)
#define SKIP_1(ptr) (ptr) += 1
#define SKIP_2(ptr) (ptr) += 2
#define SKIP_4(ptr) (ptr) += 4
#define SKIP_8(ptr) (ptr) += 8
#define SKIP_LEB128(ptr) do { ++(ptr); } while (((*(((unsigned char*)(ptr))-1))) & (1 << 7))
#define SKIP_ENCODED(ptr, enc) \
do { if (((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_uleb128) SKIP_LEB128(ptr); \
else if (((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_udata2 ) SKIP_2 (ptr); \
else if (((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_udata4 ) SKIP_4 (ptr); \
else if (((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_udata8 ) SKIP_8 (ptr); \
else if (((enc) & DW_EH_PE_SIZE_MASK) == DW_EH_PE_uptr ) SKIP_8 (ptr); \
else printf_log(LOG_DEBUG, "Invalid encoding 0x%02X\n", (enc)); \
} while (0)
// LEB128 wil only work on 64 bits numbers (unsigned long, like the Linux kernel)
void readULEB(uint64_t *var, unsigned char **ptr) {
*var = 0;
int shift = 0;
while (1) {
unsigned char byte = **ptr; ++*ptr;
*var |= ((byte & 0x7F) << shift);
if (!(byte & (1 << 7))) break;
shift += 7;
}
}
void readSLEB(int64_t *var, unsigned char **ptr) {
uint64_t tmp = 0;
int shift = 0;
unsigned char byte;
while (1) {
byte = **ptr; ++*ptr;
tmp |= ((byte & 0x7F) << shift);
if (!(byte & (1 << 7))) break;
shift += 7;
}
// Sign extend
if (byte & (1 << 6)) {
*(uint64_t*)var = tmp | (0xFFFFFFFFFFFFFFFFull << (shift + 7));
} else {
*var = tmp;
}
}
uintptr_t get_parent_registers(dwarf_unwind_t *unwind, const elfheader_t *ehdr, uintptr_t addr, char *success) {
if (!ehdr) {
*success = 0;
return 0;
}
unsigned char ehfh_version = *(unsigned char*)ehdr->ehframehdr;
if (ehfh_version != 1) {
*success = 0;
return 0;
}
// printf_log(LOG_NONE, "Address: 0x%016lX\nEH frame address: 0x%016lX\n", addr, ehdr->ehframe);
// Not using the binary search table (for now)
unsigned char *cur_addr = (unsigned char*)ehdr->ehframe;
unsigned char *end_addr = (unsigned char*)ehdr->ehframe_end;
#define AUG_EHDATA (1 << 0)
#define AUG_AUGDATA (1 << 1)
#define AUG_LSDA (1 << 2)
#define AUG_PARG (1 << 3)
#define AUG_FDEENC (1 << 4)
#define AUG_SIGHDLER (1 << 5)
unsigned short aug_fields = 0;
unsigned char lsda_encoding = DW_EH_PE_omit;
unsigned char fde_encoding = DW_EH_PE_omit;
uint64_t eh_data = 0; // Note: these are never reset, so use aug_fields & AUG_EHDATA
uint64_t code_alignment_factor = 0;
int64_t data_alignment_factor = 0;
uint64_t cie_aug_data_len = 0; // Note: these are never reset, so use aug_fields & AUG_AUGDATA
unsigned char *cie_aug_data = NULL; // Note: these are never reset, so use aug_fields & AUG_AUGDATA
unsigned char *initCIEinstr = NULL; // Never NULL if initialized
unsigned char *endCIEinstr = NULL; // Never NULL if initialized
uint64_t return_addr_reg = 0; // Description absent in the LSBCS 5.0, but still present
while (cur_addr < end_addr) {
// Length
uint64_t len; int extended = 0;
READ_U4(len, cur_addr);
if (!len) {
// Terminator, end parsing
*success = 0;
return 0;
} else if (len == 0xFFFFFFFF) {
// Extended Length (optional)
extended = 1;
READ_U8(len, cur_addr);
}
(void)extended;
// printf_log(LOG_NONE, "[???] Length %02X\n", len);
// printf_log(LOG_NONE, "[???] Extended %c\n", extended ? 'Y' : 'N');
unsigned char *next_addr = cur_addr + len;
// CIE ID (always 0) or CIE Pointer (never 0)
uint32_t cie_ptr;
READ_U4(cie_ptr, cur_addr);
if (cie_ptr == 0) {
// Current block is a CIE
// printf_log(LOG_NONE, "[CIE] ID %02X\n", cie_ptr);
// Version (always 1 or 3)
uint8_t cie_version;
READ_U1(cie_version, cur_addr);
// printf_log(LOG_NONE, "[CIE] Version %01X\n", cie_version);
if ((cie_version != 1) && (cie_version != 3)) { // Only 1 is in the LSBCS 5.0 but I found 3 exists as well
// Invalid CIE version
printf_log(LOG_DEBUG, "Invalid CIE version %d (should be 1 or 3), stopping parsing\n", cie_version);
// Failed to process CIE
*success = 0;
return 0;
}
// Augmentation String
char *aug_str = (char*)cur_addr; cur_addr += strlen(aug_str) + 1;
// printf_log(LOG_NONE, "[CIE] Augmentation st %s\n", aug_str);
aug_fields = (aug_str[0] == 'z') ? AUG_AUGDATA : 0;
for (char *aug_str2 = aug_str + ((aug_fields & AUG_AUGDATA) ? 1 : 0); *aug_str2; ++aug_str2) {
if ((aug_str2[0] == 'e') && (aug_str2[1] == 'h')) {
// Use has also been left untold in the Linux Standard Base Core Specification 3.0RC1
printf_log(LOG_DEBUG, "Warning: EH data detected but this was removed from the standard\n");
aug_fields |= AUG_EHDATA; ++aug_str2;
} else if (aug_fields & AUG_AUGDATA) {
if (aug_str2[0] == 'L') {
aug_fields |= AUG_LSDA;
} else if (aug_str2[0] == 'P') {
aug_fields |= AUG_PARG;
printf_log(LOG_DEBUG, "Warning: augmentation string attribute 'P' unsupported\n");
} else if (aug_str2[0] == 'S') {
aug_fields |= AUG_SIGHDLER;
printf_log(LOG_DEBUG, "Warning: augmentation string attribute 'S' ignored\n");
} else if (aug_str2[0] == 'R') {
aug_fields |= AUG_FDEENC;
} else {
printf_log(LOG_DEBUG, "Error: invalid augmentation string %s\n", aug_str);
// Failed to process augmentation string
break;
}
} else {
printf_log(LOG_DEBUG, "Error: invalid augmentation string %s\n", aug_str);
// Failed to process augmentation string
break;
}
}
// printf_log(LOG_NONE, "[CIE] Augmentation fs %02x\n", aug_fields);
// Code Alignment Factor
READ_ULEB128(code_alignment_factor, cur_addr);
// printf_log(LOG_NONE, "[CIE] Code AF %d\n", code_alignment_factor);
// Data Alignment Factor
READ_SLEB128(data_alignment_factor, cur_addr);
// printf_log(LOG_NONE, "[CIE] Data AF %d\n", data_alignment_factor);
if (cie_version == 1) {
READ_U1(return_addr_reg, cur_addr);
} else {
READ_ULEB128(return_addr_reg, cur_addr);
}
// printf_log(LOG_NONE, "[CIE] Return addr reg %01X\n", return_addr_reg);
lsda_encoding = DW_EH_PE_omit;
fde_encoding = DW_EH_PE_absptr;
if (aug_fields & AUG_AUGDATA) {
// Augmentation Data Length (optional)
READ_ULEB128(cie_aug_data_len, cur_addr);
// printf_log(LOG_NONE, "[CIE] Aug data len %01X\n", cie_aug_data_len);
// Augmentation Data (optional)
cie_aug_data = cur_addr; cur_addr += cie_aug_data_len;
char *cie_aug_data2 = (char*)cie_aug_data;
for (char *aug_str2 = aug_str + ((aug_fields & AUG_AUGDATA) ? 1 : 0); *aug_str2; ++aug_str2) {
if ((aug_str2[0] == 'e') && (aug_str2[1] == 'h')) {
break; // Unknown usage
} else if (aug_fields & AUG_AUGDATA) {
if (aug_str2[0] == 'L') {
READ_U1(lsda_encoding, cie_aug_data2);
if (lsda_encoding != DW_EH_PE_omit) printf_log(LOG_DEBUG, "Warning: LSDA unsupported\n");
} else if (aug_str2[0] == 'P') {
unsigned char pencoding;
READ_U1(pencoding, cie_aug_data2);
SKIP_ENCODED(cie_aug_data2, pencoding);
} else if (aug_str2[0] == 'S') {
} else if (aug_str2[0] == 'R') {
READ_U1(fde_encoding, cie_aug_data2);
// printf_log(LOG_NONE, "[CIE] FDE encoding %02X\n", fde_encoding);
if (fde_encoding == DW_EH_PE_omit) printf_log(LOG_DEBUG, "Error: FDE encoding set to 'omit'\n");
} else {
break;
}
} else {
break;
}
}
}
// Initial Instructions
initCIEinstr = cur_addr;
endCIEinstr = next_addr;
} else if (initCIEinstr) {
// Current block is a FDE
// printf_log(LOG_NONE, "[FDE] Ptr %02X\n", cie_ptr);
// PC Begin
uintptr_t pc_begin;
READ_ENCODED(pc_begin, cur_addr, fde_encoding, 1);
// printf_log(LOG_NONE, "[FDE] PC begin %016lX\n", pc_begin);
// PC Range
uint64_t pc_range;
READ_ENCODED(pc_range, cur_addr, fde_encoding, 0);
// printf_log(LOG_NONE, "[FDE] PC end %016lX\n", pc_begin + pc_range);
uint64_t aug_data_len;
unsigned char *aug_data;
if (aug_fields & AUG_AUGDATA) {
// Augmentation Data Length (optional)
READ_ULEB128(aug_data_len, cur_addr);
// printf_log(LOG_NONE, "[FDE] Aug data len %01X\n", aug_data_len);
// Augmentation Data (optional)
aug_data = cur_addr; cur_addr += aug_data_len;
(void)aug_data;
}
if (lsda_encoding != DW_EH_PE_omit) {
SKIP_ENCODED(cur_addr, lsda_encoding);
}
// Call Frame Instructions
if ((pc_begin <= addr) && (addr < pc_begin + pc_range)) {
// Corresponding Frame Descriptor Entry found!
#define setmax(a, b) a = (a < (b) ? (b) : a)
dwarf_unwind_constr_t unwind_constr;
unwind_constr.reg_count = return_addr_reg;
uint64_t maxstacksize = 0;
uint64_t curstacksize = 0;
unsigned char *cur_inst = initCIEinstr;
uint64_t nreg;
#define PARSE_INST \
switch (inst >> 6) { \
case 0b01: \
break; \
case 0b10: \
setmax(unwind_constr.reg_count, inst & 0x3F); \
SKIP_LEB128(cur_inst); \
break; \
case 0b11: \
setmax(unwind_constr.reg_count, inst & 0x3F); \
break; \
case 0b00: \
switch (inst & 0x3F) { \
case 0b000000: \
break; \
case 0b001010: \
++curstacksize; \
setmax(maxstacksize, curstacksize); \
break; \
case 0b001011: \
if (!curstacksize) { \
printf_log(LOG_DEBUG, "Negative stack size during CFI execution\n"); \
*success = 0; \
return 0; \
} \
--curstacksize; \
break; \
case 0b000010: \
SKIP_1(cur_inst); \
break; \
case 0b000011: \
SKIP_2(cur_inst); \
break; \
case 0b000100: \
SKIP_4(cur_inst); \
break; \
case 0b000001: \
SKIP_8(cur_inst); \
break; \
case 0b001110: \
case 0b010011: \
SKIP_LEB128(cur_inst); \
break; \
case 0b000110: \
case 0b000111: \
case 0b001000: \
case 0b001101: \
READ_ULEB128(nreg, cur_inst); \
setmax(unwind_constr.reg_count, nreg); \
break; \
case 0b000101: \
case 0b001100: \
case 0b010001: \
case 0b010010: \
case 0b010100: \
case 0b010101: \
READ_ULEB128(nreg, cur_inst); \
setmax(unwind_constr.reg_count, nreg); \
SKIP_LEB128(cur_inst); \
break; \
case 0b001001: \
READ_ULEB128(nreg, cur_inst); \
setmax(unwind_constr.reg_count, nreg); \
READ_ULEB128(nreg, cur_inst); \
setmax(unwind_constr.reg_count, nreg); \
break; \
default: \
/* Contains undefined, user and expression CFIs */ \
printf_log(LOG_DEBUG, "Unknown CFI 0x%02X\n", inst); \
*success = 0; \
return 0; \
} \
break; \
}
while (cur_inst < endCIEinstr) {
unsigned char inst; READ_U1(inst, cur_inst);
PARSE_INST
}
cur_inst = cur_addr;
while (cur_inst < next_addr) {
unsigned char inst; READ_U1(inst, cur_inst);
PARSE_INST
}
#undef PARSE_INST
uint64_t cfa_reg = -1;
unsigned char cfa_signed = 0;
union { uint64_t uoff; int64_t soff; } cfa_offset = { .uoff = 0 };
++unwind_constr.reg_count;
size_t tablelen = unwind_constr.reg_count * sizeof(uint64_t);
size_t statuseslen = ((unwind_constr.reg_count+1) >> 1) * sizeof(uint8_t);
unwind_constr.table = (uint64_t*)malloc(tablelen);
unwind_constr.statuses = (uint8_t*)calloc((unwind_constr.reg_count+1) >> 1, sizeof(uint8_t));
// ~~undefined is 0: no initialization needed~~ still initialize the first 17 to same_val
for (int i = 0; (i < 17) && (i <= unwind_constr.reg_count); ++i) {
SET_STATUS(unwind_constr, i, REGSTATUS_same_val);
}
curstacksize = 0;
uint64_t **table_stack = (uint64_t**)malloc(maxstacksize * sizeof(uint64_t*));
for (uint64_t i = 0; i < maxstacksize; ++i) {
table_stack[i] = (uint64_t*)malloc(tablelen);
}
cur_inst = initCIEinstr;
uintptr_t cur_pointed_addr = pc_begin;
// Missing:
/* DW_CFA_def_cfa_expression 0 0x0f BLOCK */
/* DW_CFA_expression 0 0x10 ULEB128 register BLOCK */
/* DW_CFA_val_expression 0 0x16 ULEB128 BLOCK */
/* DW_CFA_lo_user 0 0x1c */
/* DW_CFA_GNU_args_size 0 0x2e ULEB128 argsize */
/* DW_CFA_GNU_negative_offset_extended 0 0x2f ULEB128 register ULEB128 offset (obsoleted by DW_CFA_offset_extended_sf) */
/* DW_CFA_hi_user 0 0x3f */
// Known "bug": DW_CFA_set_loc can go backwards, this is ignored
uint64_t tmpreg;
uint64_t tmpuval;
int64_t tmpsval;
#define PARSE_INST \
switch (inst >> 6) { \
case 0b01: /* DW_CFA_advance_loc 0x1 delta */ \
cur_pointed_addr += (inst & 0x3F) * code_alignment_factor; \
break; \
case 0b10: /* DW_CFA_offset 0x2 register ULEB128 offset */ \
READ_ULEB128(tmpuval, cur_inst); \
SET_STATUS(unwind_constr, inst & 0x3F, REGSTATUS_offset); \
unwind_constr.table[inst & 0x3F] = (int64_t)tmpuval * data_alignment_factor; \
break; \
case 0b11: /* DW_CFA_restore 0x3 register */ \
RESTORE_REG(inst & 0x3F) \
break; \
case 0b00: \
switch (inst & 0x3F) { \
case 0b000001: /* DW_CFA_set_loc 0 0x01 address */ \
READ_U8(cur_pointed_addr, cur_inst); \
break; \
case 0b000010: /* DW_CFA_advance_loc1 0 0x02 1-byte delta */ \
READ_U1(tmpuval, cur_inst); \
cur_pointed_addr += tmpuval * code_alignment_factor; \
break; \
case 0b000011: /* DW_CFA_advance_loc2 0 0x03 2-byte delta */ \
READ_U2(tmpuval, cur_inst); \
cur_pointed_addr += tmpuval * code_alignment_factor; \
break; \
case 0b000100: /* DW_CFA_advance_loc4 0 0x04 4-byte delta */ \
READ_U4(tmpuval, cur_inst); \
cur_pointed_addr += tmpuval * code_alignment_factor; \
break; \
\
case 0b001100: /* DW_CFA_def_cfa 0 0x0c ULEB128 register ULEB128 offset */ \
READ_ULEB128(cfa_reg, cur_inst); \
cfa_signed = 0; \
READ_ULEB128(cfa_offset.uoff, cur_inst); \
break; \
case 0b010010: /* DW_CFA_def_cfa_sf 0 0x12 ULEB128 register SLEB128 offset */ \
READ_ULEB128(cfa_reg, cur_inst); \
cfa_signed = 1; \
READ_SLEB128(cfa_offset.soff, cur_inst); \
cfa_offset.soff *= data_alignment_factor; \
break; \
case 0b001101: /* DW_CFA_def_cfa_register 0 0x0d ULEB128 register */ \
READ_ULEB128(cfa_reg, cur_inst); \
break; \
case 0b001110: /* DW_CFA_def_cfa_offset 0 0x0e ULEB128 offset */ \
cfa_signed = 0; \
READ_ULEB128(cfa_offset.uoff, cur_inst); \
break; \
case 0b010011: /* DW_CFA_def_cfa_offset_sf 0 0x13 SLEB128 offset */ \
READ_SLEB128(cfa_offset.soff, cur_inst); \
cfa_offset.soff *= data_alignment_factor; \
break; \
/* DW_CFA_def_cfa_expression */ \
\
case 0b000111: /* DW_CFA_undefined 0 0x07 ULEB128 register */ \
READ_ULEB128(tmpreg, cur_inst); \
SET_STATUS(unwind_constr, tmpreg, REGSTATUS_undefined); \
break; \
case 0b001000: /* DW_CFA_same_value 0 0x08 ULEB128 register */ \
READ_ULEB128(tmpreg, cur_inst); \
SET_STATUS(unwind_constr, tmpreg, REGSTATUS_same_val); \
break; \
case 0b000101: /* DW_CFA_offset_extended 0 0x05 ULEB128 register ULEB128 offset */ \
READ_ULEB128(tmpreg, cur_inst); \
READ_ULEB128(tmpuval, cur_inst); \
SET_STATUS(unwind_constr, tmpreg, REGSTATUS_offset); \
unwind_constr.table[tmpreg] = (int64_t)tmpuval * data_alignment_factor; \
break; \
case 0b010001: /* DW_CFA_offset_extended_sf 0 0x11 ULEB128 register SLEB128 offset */ \
READ_ULEB128(tmpreg, cur_inst); \
READ_SLEB128(tmpsval, cur_inst); \
SET_STATUS(unwind_constr, tmpreg, REGSTATUS_offset); \
unwind_constr.table[tmpreg] = tmpsval * data_alignment_factor; \
break; \
case 0b010100: /* DW_CFA_val_offset 0 0x14 ULEB128 register ULEB128 offset */ \
READ_ULEB128(tmpreg, cur_inst); \
READ_ULEB128(tmpuval, cur_inst); \
SET_STATUS(unwind_constr, tmpreg, REGSTATUS_val_offset); \
unwind_constr.table[tmpreg] = (int64_t)tmpuval * data_alignment_factor; \
break; \
case 0b010101: /* DW_CFA_val_offset_sf 0 0x15 ULEB128 register SLEB128 offset */ \
READ_ULEB128(tmpreg, cur_inst); \
READ_SLEB128(tmpsval, cur_inst); \
SET_STATUS(unwind_constr, tmpreg, REGSTATUS_val_offset); \
unwind_constr.table[tmpreg] = tmpsval * data_alignment_factor; \
break; \
case 0b001001: /* DW_CFA_register 0 0x09 ULEB128 register ULEB128 register */ \
READ_ULEB128(tmpreg, cur_inst); \
READ_ULEB128(tmpuval, cur_inst); \
SET_STATUS(unwind_constr, tmpreg, REGSTATUS_register); \
unwind_constr.table[tmpreg] = tmpuval; \
break; \
/* DW_CFA_expression */ \
/* DW_CFA_val_expression */ \
case 0b000110: /* DW_CFA_restore_extended 0 0x06 ULEB128 register */ \
READ_ULEB128(tmpreg, cur_inst); \
RESTORE_REG(tmpreg) \
break; \
\
case 0b001010: /* DW_CFA_remember_state 0 0x0a */ \
memcpy(table_stack[curstacksize], unwind_constr.table, tablelen); \
++curstacksize; \
break; \
case 0b001011: /* DW_CFA_restore_state 0 0x0b */ \
--curstacksize; \
memcpy(unwind_constr.table, table_stack[curstacksize], tablelen); \
break; \
\
case 0b000000: /* DW_CFA_nop 0 0 */ \
break; \
default: \
/* Contains undefined, user and expression CFIs */ \
printf_log(LOG_DEBUG, "Unknown CFI 0x%02X\n", inst); \
FAILED \
} \
break; \
}
#define RESTORE_REG(reg) \
printf_log(LOG_DEBUG, "Trying to restore register 0x%02lX while in the intial CFIs\n", (uint64_t)reg); \
FAILED
#define FAILED \
free(unwind_constr.statuses); \
free(unwind_constr.table); \
for (uint64_t i = 0; i < maxstacksize; ++i) free(table_stack[i]); \
free(table_stack); \
*success = 0; return 0;
while (cur_inst < endCIEinstr) {
unsigned char inst; READ_U1(inst, cur_inst);
// printf_log(LOG_NONE, "Executing pre 0x%02X\n", inst);
PARSE_INST
}
#undef FAILED
#undef RESTORE_REG
uint64_t *init_table = (uint64_t*)malloc(tablelen);
memcpy(init_table, unwind_constr.table, tablelen);
uint8_t *init_statuses = (uint8_t*)malloc(statuseslen);
memcpy(init_statuses, unwind_constr.statuses, statuseslen);
cur_inst = cur_addr;
#define RESTORE_REG(reg) \
unwind_constr.table[reg] = init_table[reg]; \
SET_STATUS(unwind_constr, (reg), ((init_statuses[(reg) >> 1] >> (((reg) & 1) << 2)) & 0xF));
#define FAILED \
free(init_statuses); \
free(init_table); \
free(unwind_constr.statuses); \
free(unwind_constr.table); \
for (uint64_t i = 0; i < maxstacksize; ++i) free(table_stack[i]); \
free(table_stack); \
*success = 0; return 0;
while ((cur_inst < next_addr) && (cur_pointed_addr <= addr)) {
unsigned char inst; READ_U1(inst, cur_inst);
// printf_log(LOG_NONE, "Executing post 0x%02X\n", inst);
PARSE_INST
}
#undef FAILED
#undef RESTORE_REG
#undef PARSE_INST
free(init_statuses);
free(init_table);
for (int i = 0; i < maxstacksize; ++i) {
free(table_stack[i]);
}
free(table_stack);
dwarf_unwind_t new_unwind;
new_unwind.reg_count = unwind_constr.reg_count;
new_unwind.regs = calloc(unwind_constr.reg_count, sizeof(uint64_t));
uintptr_t cfa = unwind->regs[cfa_reg];
if (cfa_signed) cfa += cfa_offset.soff;
else cfa += cfa_offset.uoff;
// printf_log(LOG_NONE, "Done, rewriting registers (CFA at r%d(0x%016lX) + %lld (%c) -> 0x%016lX\n", cfa_reg, unwind->regs[cfa_reg], cfa_offset.soff, cfa_signed ? 's' : 'u', cfa);
for (uint64_t i = 0; i < unwind_constr.reg_count; ++i) {
switch (GET_STATUS(unwind_constr, i)) {
case REGSTATUS_undefined:
// printf_log(LOG_NONE, "Register %02lX: (undefined)\n", i);
break;
case REGSTATUS_same_val:
if (i >= unwind->reg_count) {
printf_log(LOG_DEBUG, "Invalid register status (value copied from register 0x%02lX)\n", i);
free(unwind_constr.statuses);
free(unwind_constr.table);
free(new_unwind.regs);
*success = 0;
return 0;
}
new_unwind.regs[i] = unwind->regs[i];
// printf_log(LOG_NONE, "Register %02lX: copy %016lX\n", i, new_unwind.regs[i]);
break;
case REGSTATUS_offset:
new_unwind.regs[i] = *(uint64_t*)(cfa + (int64_t)unwind_constr.table[i]);
// printf_log(LOG_NONE, "Register %02lX: offset %016lX [%016lX + %lld]\n", i, new_unwind.regs[i], cfa, (int64_t)unwind_constr.table[i]);
break;
case REGSTATUS_val_offset:
new_unwind.regs[i] = (uint64_t)(cfa + (int64_t)unwind_constr.table[i]);
// printf_log(LOG_NONE, "Register %02lX: voff %016lX\n", i, new_unwind.regs[i]);
break;
case REGSTATUS_register:
if (unwind_constr.table[i] >= unwind->reg_count) {
printf_log(LOG_DEBUG, "Invalid register status (value copied from register 0x%02lX)\n", unwind_constr.table[i]);
free(unwind_constr.statuses);
free(unwind_constr.table);
free(new_unwind.regs);
*success = 0;
return 0;
}
new_unwind.regs[i] = unwind->regs[unwind_constr.table[i]];
// printf_log(LOG_NONE, "Register %02lX: reg %016lX\n", i, new_unwind.regs[i]);
break;
}
}
*success = (GET_STATUS(unwind_constr, return_addr_reg) == REGSTATUS_undefined) ? 0 : ((aug_fields & AUG_SIGHDLER) ? 2 : 1);
free(unwind_constr.statuses);
free(unwind_constr.table);
free(unwind->regs);
unwind->reg_count = new_unwind.reg_count;
unwind->regs = new_unwind.regs;
// Maybe?
unwind->regs[cfa_reg] = cfa;
// printf_log(LOG_NONE, "Returning %016lX\n", unwind->regs[return_addr_reg]);
return unwind->regs[return_addr_reg];
}
} else {
// printf_log(LOG_NONE, "[FDE] Ptr %02X\n", cie_ptr);
printf_log(LOG_DEBUG, "Unexpected FDE, corresponding CIE missing\n");
return 0;
}
cur_addr = next_addr;
}
*success = 0;
return 0;
}
dwarf_unwind_t *init_dwarf_unwind_registers(x64emu_t *emu) {
dwarf_unwind_t *unwind_struct = (dwarf_unwind_t*)malloc(sizeof(dwarf_unwind_t));
unwind_struct->reg_count = 17;
unwind_struct->regs = (uint64_t*)malloc(17*sizeof(uint64_t));
/* x86_64-abi-0.99.pdf
* Register Name | Number | Abbreviation
* General Purpose Register RAX | 0 | %rax
* General Purpose Register RDX | 1 | %rdx
* General Purpose Register RCX | 2 | %rcx
* General Purpose Register RBX | 3 | %rbx
* General Purpose Register RSI | 4 | %rsi
* General Purpose Register RDI | 5 | %rdi
* Frame Pointer Register RBP | 6 | %rbp
* Stack Pointer Register RSP | 7 | %rsp
* Extended Integer Registers 8-15 | 8-15 | %r8-%r15
* Return Address RA | 16 |
* Vector Registers 0-7 | 17-24 | %xmm0-%xmm7
* Extended Vector Registers 8-15 | 25-32 | %xmm8-%xmm15
* Floating Point Registers 0-7 | 33-40 | %st0-%st7
* MMX Registers 0-7 | 41-48 | %mm0-%mm7
* Flag Register | 49 | %rFLAGS
* Segment Register ES | 50 | %es
* Segment Register CS | 51 | %cs
* Segment Register SS | 52 | %ss
* Segment Register DS | 53 | %ds
* Segment Register FS | 54 | %fs
* Segment Register GS | 55 | %gs
* Reserved | 56-57 |
* FS Base address | 58 | %fs.base
* GS Base address | 59 | %gs.base
* Reserved | 60-61 |
* Task Register | 62 | %tr
* LDT Register | 63 | %ldtr
* 128-bit Media Control and Status | 64 | %mxcsr
* x87 Control Word | 65 | %fcw
* x87 Status Word | 66 | %fsw
*/
unwind_struct->regs[ 0] = emu->regs[_RAX].q[0];
unwind_struct->regs[ 1] = emu->regs[_RDX].q[0];
unwind_struct->regs[ 2] = emu->regs[_RCX].q[0];
unwind_struct->regs[ 3] = emu->regs[_RBX].q[0];
unwind_struct->regs[ 4] = emu->regs[_RSI].q[0];
unwind_struct->regs[ 5] = emu->regs[_RDI].q[0];
unwind_struct->regs[ 6] = emu->regs[_RBP].q[0];
unwind_struct->regs[ 7] = emu->regs[_RSP].q[0] + 8;
unwind_struct->regs[ 8] = emu->regs[_R8 ].q[0];
unwind_struct->regs[ 9] = emu->regs[_R9 ].q[0];
unwind_struct->regs[10] = emu->regs[_R10].q[0];
unwind_struct->regs[11] = emu->regs[_R11].q[0];
unwind_struct->regs[12] = emu->regs[_R12].q[0];
unwind_struct->regs[13] = emu->regs[_R13].q[0];
unwind_struct->regs[14] = emu->regs[_R14].q[0];
unwind_struct->regs[15] = emu->regs[_R15].q[0];
unwind_struct->regs[16] = emu->ip.q[0];
return unwind_struct;
}
void free_dwarf_unwind_registers(dwarf_unwind_t **unwind_struct) {
free((*unwind_struct)->regs);
free(*unwind_struct);
*unwind_struct = NULL;
}
-19
View File
@@ -1,19 +0,0 @@
#ifndef __ELFDWARF_PRIVATE_H_
#define __ELFDWARF_PRIVATE_H_
#include "emu/x64emu_private.h"
typedef struct dwarf_unwind_s {
uint8_t reg_count;
uint64_t *regs;
} dwarf_unwind_t;
typedef struct elfheader_s elfheader_t;
dwarf_unwind_t *init_dwarf_unwind_registers(x64emu_t *emu);
void free_dwarf_unwind_registers(dwarf_unwind_t **unwind_struct);
// Returns the callee's address on success or NULL on failure (may be NULL regardless).
// If success equals 2, the frame is a signal frame.
uintptr_t get_parent_registers(dwarf_unwind_t *emu, const elfheader_t *ehdr, uintptr_t addr, char *success);
#endif // __ELFDWARF_PRIVATE_H_
+28 -135
View File
@@ -134,9 +134,9 @@ int CalcLoadAddr(elfheader_t* head)
head->tlssize++;
}
}
printf_log(LOG_DEBUG, "Elf Addr(v/p)=%p/%p Memsize=0x%zx (align=0x%zx)\n", (void*)head->vaddr, (void*)head->paddr, head->memsz, head->align);
printf_log(LOG_DEBUG, "Elf Stack Memsize=%zu (align=%zu)\n", head->stacksz, head->stackalign);
printf_log(LOG_DEBUG, "Elf TLS Memsize=%zu (align=%zu)\n", head->tlssize, head->tlsalign);
printf_log(LOG_DEBUG, "Elf Addr(v/p)=%p/%p Memsize=0x%lx (align=0x%zx)\n", (void*)head->vaddr, (void*)head->paddr, head->memsz, head->align);
printf_log(LOG_DEBUG, "Elf Stack Memsize=%lu (align=%zu)\n", head->stacksz, head->stackalign);
printf_log(LOG_DEBUG, "Elf TLS Memsize=%lu (align=%zu)\n", head->tlssize, head->tlsalign);
return 0;
}
@@ -147,19 +147,13 @@ 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(box64context_t* context, elfheader_t* head, int mainbin)
{
uintptr_t offs = 0;
if(mainbin && head->vaddr==0) {
char* load_addr = getenv("BOX64_LOAD_ADDR");
if(load_addr)
if(sscanf(load_addr, "0x%zx", &offs)!=1)
if(sscanf(load_addr, "0x%lx", &offs)!=1)
offs = 0;
}
if(!offs)
@@ -191,7 +185,7 @@ int AllocElfMemory(box64context_t* context, elfheader_t* head, int mainbin)
uintptr_t end = head->multiblock_offs[j] + head->multiblock_size[j];
start &= ~balign;
if( (head->e_type == ET_DYN) ||
(((bstart>=start) && (bstart<=end+0x1000)) || ((bend>=start) && (bend<=end)) || ((bstart<start) && (bend>end))))
(((bstart>=start) && (bstart<=end)) || ((bend>=start) && (bend<=end)) || ((bstart<start) && (bend>end))))
{
// merge
ok = 1;
@@ -216,12 +210,12 @@ int AllocElfMemory(box64context_t* context, elfheader_t* head, int mainbin)
, MAP_PRIVATE | MAP_ANONYMOUS /*| ((wine_preloaded)?MAP_FIXED:0)*/
, -1, 0);
if(p==MAP_FAILED) {
printf_log(LOG_NONE, "Cannot create memory map (@%p 0x%zx/0x%zx) for elf \"%s\"\n", (void*)head->multiblock_offs[i], head->multiblock_size[i], head->align, head->name);
printf_log(LOG_NONE, "Cannot create memory map (@%p 0x%lx/0x%zx) for elf \"%s\"\n", (void*)head->multiblock_offs[i], head->multiblock_size[i], head->align, head->name);
return 1;
}
if(head->multiblock_offs[i] &&( p!=(void*)head->multiblock_offs[i])) {
if((head->e_type!=ET_DYN)) {
printf_log(LOG_NONE, "Error, memory map (@%p 0x%zx/0x%zx) for elf \"%s\" allocated @%p\n", (void*)head->multiblock_offs[i], head->multiblock_size[i], head->align, head->name, p);
printf_log(LOG_NONE, "Error, memory map (@%p 0x%lx/0x%zx) for elf \"%s\" allocated @%p\n", (void*)head->multiblock_offs[i], head->multiblock_size[i], head->align, head->name, p);
return 1;
} else {
printf_log(LOG_INFO, "Allocated memory is not at hinted %p but %p (size %lx) \"%s\"\n", (void*)head->multiblock_offs[i], p, head->multiblock_size[i], head->name);
@@ -245,17 +239,17 @@ int AllocElfMemory(box64context_t* context, elfheader_t* head, int mainbin)
// vaddr is 0, load everything has a One block
if(!offs && box64_wine)
offs = (uintptr_t)find47bitBlock(head->memsz); // limit to 47bits...
printf_log(LOG_DEBUG, "Allocating 0x%zx memory @%p for Elf \"%s\"\n", head->memsz, (void*)offs, head->name);
printf_log(LOG_DEBUG, "Allocating 0x%lx memory @%p for Elf \"%s\"\n", head->memsz, (void*)offs, head->name);
void* p = mmap((void*)offs, head->memsz
, PROT_READ | PROT_WRITE | PROT_EXEC
, MAP_PRIVATE | MAP_ANONYMOUS /*| (((offs&&wine_preloaded)?MAP_FIXED:0))*/
, -1, 0);
if(p==MAP_FAILED) {
printf_log(LOG_NONE, "Cannot create memory map (@%p 0x%zx/0x%zx) for elf \"%s\"\n", (void*)offs, head->memsz, head->align, head->name);
printf_log(LOG_NONE, "Cannot create memory map (@%p 0x%lx/0x%zx) for elf \"%s\"\n", (void*)offs, head->memsz, head->align, head->name);
return 1;
}
if(offs && (p!=(void*)offs) && (head->e_type!=ET_DYN)) {
printf_log(LOG_NONE, "Error, memory map (@%p 0x%zx/0x%zx) for elf \"%s\" allocated @%p\n", (void*)offs, head->memsz, head->align, head->name, p);
printf_log(LOG_NONE, "Error, memory map (@%p 0x%lx/0x%zx) for elf \"%s\" allocated @%p\n", (void*)offs, head->memsz, head->align, head->name, p);
return 1;
}
setProtection((uintptr_t)p, head->memsz, PROT_READ | PROT_WRITE | PROT_EXEC);
@@ -295,7 +289,7 @@ int LoadElfMemory(FILE* f, box64context_t* context, elfheader_t* head)
if(head->PHEntries[i].p_type == PT_LOAD) {
Elf64_Phdr * e = &head->PHEntries[i];
char* dest = (char*)e->p_paddr + head->delta;
printf_log(LOG_DEBUG, "MMap block #%zu @%p offset=%p (0x%zx/0x%zx)\n", i, dest, (void*)e->p_offset, e->p_filesz, e->p_memsz);
printf_log(LOG_DEBUG, "MMap block #%zu @%p offset=%p (0x%lx/0x%lx)\n", i, dest, (void*)e->p_offset, e->p_filesz, e->p_memsz);
void* p = (void*)-1;
if(e->p_memsz==e->p_filesz && !(e->p_align&0xfff)) {
printf_log(LOG_DEBUG, "MMap block #%zu @%p offset=%p (0x%zx/0x%zx, flags:0x%x)\n", i, dest, (void*)e->p_offset, e->p_filesz, e->p_memsz, e->p_flags);
@@ -325,11 +319,11 @@ int LoadElfMemory(FILE* f, box64context_t* context, elfheader_t* head)
if(head->PHEntries[i].p_type == PT_TLS) {
Elf64_Phdr * e = &head->PHEntries[i];
char* dest = (char*)(context->tlsdata+context->tlssize+head->tlsbase);
printf_log(LOG_DEBUG, "Loading TLS block #%zu @%p (0x%zx/0x%zx)\n", i, dest, e->p_filesz, e->p_memsz);
printf_log(LOG_DEBUG, "Loading TLS block #%zu @%p (0x%lx/0x%lx)\n", i, dest, e->p_filesz, e->p_memsz);
if(e->p_filesz) {
fseeko64(f, e->p_offset, SEEK_SET);
if(fread(dest, e->p_filesz, 1, f)!=1) {
printf_log(LOG_NONE, "Fail to read PT_TLS part #%zu (size=%zd)\n", i, e->p_filesz);
printf_log(LOG_NONE, "Fail to read PT_TLS part #%zu (size=%ld)\n", i, e->p_filesz);
return 1;
}
}
@@ -349,7 +343,7 @@ int ReloadElfMemory(FILE* f, box64context_t* context, elfheader_t* head)
if(head->PHEntries[i].p_type == PT_LOAD) {
Elf64_Phdr * e = &head->PHEntries[i];
char* dest = (char*)e->p_paddr + head->delta;
printf_log(LOG_DEBUG, "Re-loading block #%zu @%p (0x%zx/0x%zx)\n", i, dest, e->p_filesz, e->p_memsz);
printf_log(LOG_DEBUG, "Re-loading block #%zu @%p (0x%lx/0x%lx)\n", i, dest, e->p_filesz, e->p_memsz);
int ret = fseeko64(f, e->p_offset, SEEK_SET);
if(ret==-1) {printf_log(LOG_NONE, "Fail to (re)seek PT_LOAD part #%zu (offset=%ld, errno=%d/%s)\n", i, e->p_offset, errno, strerror(errno)); return 1;}
#ifdef DYNAREC
@@ -360,7 +354,7 @@ int ReloadElfMemory(FILE* f, box64context_t* context, elfheader_t* head)
if(e->p_filesz) {
ssize_t r = -1;
if((r=fread(dest, e->p_filesz, 1, f))!=1) {
printf_log(LOG_NONE, "Fail to (re)read PT_LOAD part #%zu (dest=%p, size=%zd, return=%zd, feof=%d/ferror=%d/%s)\n", i, dest, e->p_filesz, r, feof(f), ferror(f), strerror(ferror(f)));
printf_log(LOG_NONE, "Fail to (re)read PT_LOAD part #%zu (dest=%p, size=%ld, return=%ld, feof=%d/ferror=%d/%s)\n", i, dest, e->p_filesz, r, feof(f), ferror(f), strerror(ferror(f)));
return 1;
}
}
@@ -377,22 +371,22 @@ int FindR64COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint64_t**
{
if(!h)
return 0;
Elf64_Rela * rela = (Elf64_Rela *)(h->rela + h->delta);
Elf64_Rela * rel = (Elf64_Rela *)(h->rela + h->delta);
if(!h->rela)
return 0;
int cnt = h->relasz / h->relaent;
for (int i=0; i<cnt; ++i) {
int t = ELF64_R_TYPE(rela[i].r_info);
Elf64_Sym *sym = &h->DynSym[ELF64_R_SYM(rela[i].r_info)];
int t = ELF64_R_TYPE(rel[i].r_info);
Elf64_Sym *sym = &h->DynSym[ELF64_R_SYM(rel[i].r_info)];
const char* symname = SymName(h, sym);
if(t==R_X86_64_COPY && symname && !strcmp(symname, name)) {
int version2 = h->VerSym?((Elf64_Half*)((uintptr_t)h->VerSym+h->delta))[ELF64_R_SYM(rela[i].r_info)]:-1;
int version2 = h->VerSym?((Elf64_Half*)((uintptr_t)h->VerSym+h->delta))[ELF64_R_SYM(rel[i].r_info)]:-1;
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)) {
*offs = sym->st_value + h->delta;
*p = (uint64_t*)(rela[i].r_offset + h->delta + rela[i].r_addend);
*p = (uint64_t*)(rel[i].r_offset + h->delta + rel[i].r_addend);
return 1;
}
}
@@ -472,7 +466,7 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t*
}
if (!offs) {
if(strcmp(symname, "__gmon_start__") && strcmp(symname, "data_start") && strcmp(symname, "__data_start"))
printf_log(LOG_NONE, "%s: Global Symbol %s not found, cannot apply R_X86_64_GLOB_DAT @%p (%p) in %s\n", (bind==STB_WEAK)?"Warning":"Error", symname, p, *(void**)p, head->name);
printf_log(LOG_NONE, "Error: Global Symbol %s not found, cannot apply R_X86_64_GLOB_DAT @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
} else {
printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT @%p (%p -> %p) on sym=%s (ver=%d/%s)\n", (bind==STB_LOCAL)?"Local":"Global", p, (void*)(p?(*p):0), (void*)offs, symname, version, vername?vername:"(none)");
*p = offs;
@@ -610,7 +604,7 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
uint64_t* globp;
uintptr_t tmp = 0;
intptr_t delta;
switch(t) {
switch(ELF64_R_TYPE(rela[i].r_info)) {
case R_X86_64_NONE:
break;
case R_X86_64_PC32:
@@ -645,8 +639,8 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
// set global offs / size for the symbol
offs = sym->st_value + head->delta;
end = offs + sym->st_size;
if(sym->st_size && offs) {
printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT with R_X86_64_COPY @%p/%p (%p/%p -> %p/%p) size=%zd on sym=%s (ver=%d/%s) \n",
if(sym->st_size) {
printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT with R_X86_64_COPY @%p/%p (%p/%p -> %p/%p) size=%ld on sym=%s (ver=%d/%s) \n",
(bind==STB_LOCAL)?"Local":"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
@@ -665,7 +659,7 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, elfheader_t
}
if (!offs) {
if(strcmp(symname, "__gmon_start__") && strcmp(symname, "data_start") && strcmp(symname, "__data_start"))
printf_log(LOG_NONE, "%s: Global Symbol %s not found, cannot apply R_X86_64_GLOB_DAT @%p (%p) in %s\n", (bind==STB_WEAK)?"Warning":"Error", symname, p, *(void**)p, head->name);
printf_log(LOG_NONE, "Error: Global Symbol %s not found, cannot apply R_X86_64_GLOB_DAT @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
} else {
printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT @%p (%p -> %p) on sym=%s (ver=%d/%s)\n", (bind==STB_LOCAL)?"Local":"Global", p, (void*)(p?(*p):0), (void*)offs, symname, version, vername?vername:"(none)");
*p = offs/* + rela[i].r_addend*/; // not addend it seems
@@ -945,7 +939,7 @@ void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* wea
int bind = ELF64_ST_BIND(h->SymTab[i].st_info);
int type = ELF64_ST_TYPE(h->SymTab[i].st_info);
int vis = h->SymTab[i].st_other&0x3;
size_t sz = h->SymTab[i].st_size;
uint64_t sz = h->SymTab[i].st_size;
if((type==STT_OBJECT || type==STT_FUNC || type==STT_COMMON || type==STT_TLS || type==STT_NOTYPE)
&& (vis==STV_DEFAULT || vis==STV_PROTECTED) && (h->SymTab[i].st_shndx!=0)) {
if(sz && strstr(symname, "@@")) {
@@ -1003,7 +997,7 @@ void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* wea
if((type==STT_OBJECT || type==STT_FUNC || type==STT_COMMON || type==STT_TLS || type==STT_NOTYPE)
&& (vis==STV_DEFAULT || vis==STV_PROTECTED) && (h->DynSym[i].st_shndx!=0 && h->DynSym[i].st_shndx<=65521)) {
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;
uint64_t sz = h->DynSym[i].st_size;
int version = h->VerSym?((Elf64_Half*)((uintptr_t)h->VerSym+h->delta))[i]:-1;
if(version!=-1) version &= 0x7fff;
const char* vername = GetSymbolVersion(h, version);
@@ -1024,7 +1018,7 @@ void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* wea
if(bind==STB_WEAK) {
AddSymbol(weaksymbols, symname, offs, sz, version, vername);
} else {
AddWeakSymbol(mapsymbols, symname, offs, sz, version?version:1, vername);
AddSymbol(mapsymbols, symname, offs, sz, version, vername);
}
}
}
@@ -1081,20 +1075,6 @@ int LoadNeededLibs(elfheader_t* h, lib_t *maplib, needed_libs_t* neededlibs, lib
rpath = tmp;
free(origin);
}
while(strstr(rpath, "${PLATFORM}")) {
char* platform = strdup("x86_64");
char* p = strrchr(platform, '/');
if(p) *p = '\0'; // remove file name to have only full path, without last '/'
char* tmp = (char*)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)
free(rpath);
rpath = tmp;
free(platform);
}
if(strchr(rpath, '$')) {
printf_log(LOG_INFO, "BOX64: Warning, RPATH with $ variable not supported yet (%s)\n", rpath);
} else {
@@ -1137,8 +1117,6 @@ int ElfCheckIfUseTCMallocMinimal(elfheader_t* h)
char *needed = h->DynStrTab+h->delta+h->Dynamic[i].d_un.d_val;
if(!strcmp(needed, "libtcmalloc_minimal.so.4")) // tcmalloc needs to be the 1st lib loaded
return 1;
else if(!strcmp(needed, "libtcmalloc_minimal.so.0")) // tcmalloc needs to be the 1st lib loaded
return 1;
else
return 0;
}
@@ -1390,13 +1368,6 @@ void* GetTLSPointer(box64context_t* context, elfheader_t* h)
return ptr->tlsdata+(ptr->tlssize+h->tlsbase);
}
void* GetDynamicSection(elfheader_t* h)
{
if(!h)
return NULL;
return h->Dynamic;
}
#ifdef DYNAREC
dynablocklist_t* GetDynablocksFromAddress(box64context_t *context, uintptr_t addr)
{
@@ -1547,8 +1518,6 @@ void CreateMemorymapFile(box64context_t* context, int fd)
st.st_ino = 0;
}
// TODO: create heap entry?
for (size_t i=0; i<h->numPHEntries; ++i) {
if (h->PHEntries[i].p_memsz == 0) continue;
@@ -1561,11 +1530,6 @@ void CreateMemorymapFile(box64context_t* context, int fd)
dummy = write(fd, buff, strlen(buff));
}
// create stack entry
sprintf(buff, "%16lx-%16lx %c%c%c%c %16lx %02x:%02x %ld %s\n",
(uintptr_t)context->stack, (uintptr_t)context->stack+context->stacksz,
'r','w','-','p', 0L, 0, 0, 0L, "[stack]");
dummy = write(fd, buff, strlen(buff));
}
void ElfAttachLib(elfheader_t* head, library_t* lib)
@@ -1575,77 +1539,6 @@ void ElfAttachLib(elfheader_t* head, library_t* lib)
head->lib = lib;
}
typedef struct search_symbol_s{
const char* name;
void* addr;
void* lib;
} search_symbol_t;
int dl_iterate_phdr_findsymbol(struct dl_phdr_info* info, size_t size, void* data)
{
search_symbol_t* s = (search_symbol_t*)data;
for(int j = 0; j<info->dlpi_phnum; ++j) {
if (info->dlpi_phdr[j].p_type == PT_DYNAMIC) {
ElfW(Sym)* sym = NULL;
ElfW(Word) sym_cnt = 0;
ElfW(Verdef)* verdef = NULL;
ElfW(Word) verdef_cnt = 0;
char *strtab = NULL;
ElfW(Dyn)* dyn = (ElfW(Dyn)*)(info->dlpi_addr + info->dlpi_phdr[j].p_vaddr); //Dynamic Section
// grab the needed info
while(dyn->d_tag != DT_NULL) {
switch(dyn->d_tag) {
case DT_STRTAB:
strtab = (char *)(dyn->d_un.d_ptr);
break;
case DT_VERDEF:
verdef = (ElfW(Verdef)*)(info->dlpi_addr + dyn->d_un.d_ptr);
break;
case DT_VERDEFNUM:
verdef_cnt = dyn->d_un.d_val;
break;
}
++dyn;
}
if(strtab && verdef && verdef_cnt) {
if((uintptr_t)strtab < (uintptr_t)info->dlpi_addr) // this test is need for linux-vdso on PI and some other OS (looks like a bug to me)
strtab=(char*)((uintptr_t)strtab + info->dlpi_addr);
// Look fr all defined versions now
ElfW(Verdef)* v = verdef;
while(v) {
ElfW(Verdaux)* vda = (ElfW(Verdaux)*)(((uintptr_t)v) + v->vd_aux);
if(v->vd_version>0 && !v->vd_flags)
for(int i=0; i<v->vd_cnt; ++i) {
const char* vername = (strtab+vda->vda_name);
if(vername && vername[0] && (s->addr = dlvsym(s->lib, s->name, vername))) {
printf_log(/*LOG_DEBUG*/LOG_INFO, "Found symbol with version %s, value = %p\n", vername, s->addr);
return 1; // stop searching
}
vda = (ElfW(Verdaux)*)(((uintptr_t)vda) + vda->vda_next);
}
v = v->vd_next?(ElfW(Verdef)*)((uintptr_t)v + v->vd_next):NULL;
}
}
}
}
return 0;
}
void* GetNativeSymbolUnversionned(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;
s.name = name;
s.addr = NULL;
if(lib)
s.lib = lib;
else
s.lib = my_context->box64lib;
printf_log(LOG_INFO, "Look for %s in loaded elfs\n", name);
dl_iterate_phdr(dl_iterate_phdr_findsymbol, &s);
return s.addr;
}
uintptr_t pltResolver = ~0LL;
EXPORT void PltResolver(x64emu_t* emu)
{
+1 -5
View File
@@ -8,8 +8,7 @@ typedef struct dynablocklist_s dynablocklist_t;
typedef struct library_s library_t;
typedef struct needed_libs_s needed_libs_t;
#include <elf.h>
#include "elfloader.h"
#include <pthread.h>
struct elfheader_s {
char* name;
@@ -67,9 +66,6 @@ struct elfheader_s {
uintptr_t plt_end;
uintptr_t text;
size_t textsz;
uintptr_t ehframe;
uintptr_t ehframe_end;
uintptr_t ehframehdr;
uintptr_t paddr;
uintptr_t vaddr;
-15
View File
@@ -246,10 +246,6 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
h->initarray_sz = val / sizeof(Elf64_Addr);
printf_log(LOG_DEBUG, "The DT_INIT_ARRAYSZ is %zu\n", h->initarray_sz);
break;
case DT_PREINIT_ARRAYSZ:
if(val)
printf_log(LOG_NONE, "Warning, PreInit Array (size=%d) present and ignored!\n", val);
break;
case DT_FINI: // Exit hook
h->finientry = ptr;
printf_log(LOG_DEBUG, "The DT_FINI is at address %p\n", (void*)h->finientry);
@@ -349,17 +345,6 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
h->textsz = h->SHEntries[ii].sh_size;
printf_log(LOG_DEBUG, "The .text is at address %p, and is %zu big\n", (void*)h->text, h->textsz);
}
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_log(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_log(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);
-2
View File
@@ -459,8 +459,6 @@ void EmuCall(x64emu_t* emu, uintptr_t addr)
uint64_t old_rsi = R_RSI;
uint64_t old_rbp = R_RBP;
uint64_t old_rip = R_RIP;
//Push64(emu, GetRBP(emu)); // set frame pointer
//SetRBP(emu, GetRSP(emu)); // save RSP
PushExit(emu);
R_RIP = addr;
emu->df = d_none;
+7 -11
View File
@@ -97,17 +97,13 @@ void x64Int3(x64emu_t* emu)
s = GetNativeName((void*)addr);
if(addr==(uintptr_t)PltResolver) {
snprintf(buff, 256, "%s", " ... ");
} else if (!strcmp(s, "__open") || !strcmp(s, "open") || !strcmp(s, "open ") || !strcmp(s, "open64")) {
} else if (!strcmp(s, "__open") || !strcmp(s, "open") || !strcmp(s, "open ")) {
tmp = (char*)(R_RDI);
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d (,%d))", tid, *(void**)(R_RSP), s, (tmp)?tmp:"(nil)", (int)(R_ESI), (int)(R_EDX));
perr = 1;
} else if (!strcmp(s, "shm_open")) {
tmp = (char*)(R_RDI);
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d, %d)", tid, *(void**)(R_RSP), s, (tmp)?tmp:"(nil)", (int)(R_ESI), (int)(R_EDX));
perr = 1;
} else if (!strcmp(s, "fopen") || !strcmp(s, "fopen64")) {
tmp = (char*)(R_RDI);
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)(R_RSP), s, (tmp)?tmp:"(nil)", (char*)(R_RSI));
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d)", tid, *(void**)(R_RSP), s, (tmp)?tmp:"(nil)", (int)(R_ESI));
perr = 2;
} else if (!strcmp(s, "__openat64") || !strcmp(s, "openat64") || !strcmp(s, "__openat64_2")) {
tmp = (char*)(R_RSI);
@@ -131,10 +127,10 @@ void x64Int3(x64emu_t* emu)
tmp = (char*)(R_RDI);
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", 0x%x)", tid, *(void**)(R_RSP), s, (tmp)?tmp:"(nil)", R_ESI);
perr = 1;
} else if (!strcmp(s, "lseek64")) {
} else if (!strcmp(s, "lseek64") || !strcmp(s, "my_lseek64")) {
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %ld, %d)", tid, *(void**)(R_RSP), s, (int)R_EDI, (int64_t)R_RSI, (int)R_EDX);
perr = 1;
} else if (!strcmp(s, "lseek")) {
} else if (!strcmp(s, "lseek") || !strcmp(s, "my_lseek")) {
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %ld, %d)", tid, *(void**)(R_RSP), s, (int)R_EDI, (int64_t)R_RSI, (int)R_EDX);
perr = 1;
} else if (strstr(s, "puts")==s) {
@@ -152,15 +148,15 @@ void x64Int3(x64emu_t* emu)
} else if (!strcmp(s, "poll")) {
struct pollfd* pfd = (struct pollfd*)(R_RDI);
snprintf(buff, 255, "%04d|%p: Calling %s(%p[%d/%d/%d, ...], %d, %d)", tid, *(void**)(R_RSP), s, pfd, pfd->fd, pfd->events, pfd->revents, R_ESI, R_EDX);
} else if (strstr(s, "__printf_chk")) {
} else if (strstr(s, "my___printf_chk") || !strcmp(s, "__printf_chk")) {
tmp = (char*)(R_RSI);
snprintf(buff, 255, "%04d|%p: Calling %s(%d, \"%s\" (,%p))", tid, *(void**)(R_RSP), s, R_EDI, (tmp)?tmp:"(nil)", (void*)(R_RDX));
} else if (strstr(s, "__snprintf_chk")) {
} else if (strstr(s, "my___snprintf_chk") || !strcmp(s, "__snprintf_chk")) {
tmp = (char*)(R_R8);
pu64 = (uint64_t*)R_RDI;
post = 3;
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %zu, %d, %zu, \"%s\" (,%p))", tid, *(void**)(R_RSP), s, (void*)R_RDI, R_RSI, R_EDX, R_RCX, (tmp)?tmp:"(nil)", (void*)(R_R9));
} else if (!strcmp(s, "snprintf")) {
} else if (strstr(s, "my_snprintf") || !strcmp(s, "snprintf")) {
tmp = (char*)(R_RDX);
pu64 = (uint64_t*)R_RDI;
post = 3;
+9 -9
View File
@@ -1191,9 +1191,9 @@ uint16_t sbb16(x64emu_t *emu, uint16_t d, uint16_t s)
res = d - s - 1;
else
res = d - s;
CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
/* calculate the borrow chain. See note at top */
bc = (res & (~d | s)) | (~d & s);
@@ -1213,9 +1213,9 @@ uint32_t sbb32(x64emu_t *emu, uint32_t d, uint32_t s)
res = d - s - 1;
else
res = d - s;
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
CONDITIONAL_SET_FLAG(!res, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
CONDITIONAL_SET_FLAG(!res, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
/* calculate the borrow chain. See note at top */
bc = (res & (~d | s)) | (~d & s);
@@ -1235,9 +1235,9 @@ uint64_t sbb64(x64emu_t *emu, uint64_t d, uint64_t s)
res = d - s - 1;
else
res = d - s;
CONDITIONAL_SET_FLAG(res & 0x8000000000000000LL, F_SF);
CONDITIONAL_SET_FLAG(!res, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
CONDITIONAL_SET_FLAG(res & 0x8000000000000000LL, F_SF);
CONDITIONAL_SET_FLAG(!res, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
/* calculate the borrow chain. See note at top */
bc = (res & (~d | s)) | (~d & s);
+6 -7
View File
@@ -21,7 +21,7 @@
#include "bridge.h"
#include "signals.h"
#ifdef DYNAREC
#include "../dynarec/native_lock.h"
#include "../dynarec/arm64_lock.h"
#endif
#include "modrm.h"
@@ -163,7 +163,6 @@ x64emurun:
GO(0x30, xor) /* XOR 0x30 -> 0x35 */
#undef GO
case 0x2E: /* segments are ignored */
case 0x36: /* SS: (ignored) */
break;
@@ -413,8 +412,8 @@ x64emurun:
EB->byte[0] = tmp8u;
} else {
do {
tmp8u = native_lock_read_b(EB);
} while(native_lock_write_b(EB, GB));
tmp8u = arm64_lock_read_b(EB);
} while(arm64_lock_write_b(EB, GB));
GB = tmp8u;
}
// dynarec use need it's own mecanism
@@ -447,11 +446,11 @@ x64emurun:
}
} else {
if(rex.w) {
GD->q[0] = native_lock_xchg(ED, GD->q[0]);
GD->q[0] = arm64_lock_xchg(ED, GD->q[0]);
} else {
do {
tmp32u = native_lock_read_d(ED);
} while(native_lock_write_d(ED, GD->dword[0]));
tmp32u = arm64_lock_read_d(ED);
} while(arm64_lock_write_d(ED, GD->dword[0]));
GD->q[0] = tmp32u;
}
}
+27 -70
View File
@@ -23,7 +23,7 @@
#include "signals.h"
#ifdef DYNAREC
#include "custommem.h"
#include "../dynarec/native_lock.h"
#include "../dynarec/arm64_lock.h"
#endif
#include "modrm.h"
@@ -311,33 +311,6 @@ int Run0F(x64emu_t *emu, rex_t rex)
}
break;
case 0x3A:
opcode = F8;
switch(opcode) {
case 0xF: /* palignr */
nextop = F8;
GETEM(1);
GETGM;
tmp8u = F8;
if (tmp8u >= 16) {
GM->q = 0;
} else if (tmp8u > 8) {
tmp8u -= 8;
GM->q >>= tmp8u*8;
} else if (tmp8u == 8 || tmp8u == 0) {
} else {
GM->q <<= (8-tmp8u)*8;
GM->q |= (EM->q >> tmp8u*8);
}
break;
default:
return 1;
}
break;
GOCOND(0x40
, nextop = F8;
GETED(0);
@@ -366,18 +339,8 @@ int Run0F(x64emu_t *emu, rex_t rex)
nextop = F8;
GETEX(0);
GETGX;
for(int i=0; i<4; ++i) {
if(EX->f[i]==0)
GX->f[i] = 1.0f/EX->f[i];
else if (EX->f[i]<0)
GX->f[i] = NAN;
else if (isnan(EX->f[i]))
GX->f[i] = EX->f[i];
else if (isinf(EX->f[i]))
GX->f[i] = 0.0;
else
GX->f[i] = 1.0f/sqrtf(EX->f[i]);
}
for(int i=0; i<4; ++i)
GX->f[i] = 1.0f/sqrtf(EX->f[i]);
break;
case 0x53: /* RCPPS Gx, Ex */
nextop = F8;
@@ -1258,36 +1221,30 @@ int Run0F(x64emu_t *emu, rex_t rex)
CHECK_FLAGS(emu);
nextop = F8;
GETED(0);
switch((nextop>>3)&7) {
case 1:
if(rex.w) {
tmp64u = ED->q[0];
tmp64u2= ED->q[1];
if(R_RAX == tmp64u && R_RDX == tmp64u2) {
SET_FLAG(F_ZF);
ED->q[0] = R_EBX;
ED->q[1] = R_ECX;
} else {
CLEAR_FLAG(F_ZF);
R_RAX = tmp64u;
R_RDX = tmp64u2;
}
} else {
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_RAX = tmp32u;
R_RDX = tmp32u2;
}
}
break;
default:
return 1;
if(rex.w) {
tmp64u = ED->q[0];
tmp64u2= ED->q[1];
if(R_RAX == tmp64u && R_RDX == tmp64u2) {
SET_FLAG(F_ZF);
ED->q[0] = R_EBX;
ED->q[1] = R_ECX;
} else {
CLEAR_FLAG(F_ZF);
R_RAX = tmp64u;
R_RDX = tmp64u2;
}
} else {
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_RAX = tmp32u;
R_RDX = tmp32u2;
}
}
break;
case 0xC8:
+1 -39
View File
@@ -136,12 +136,6 @@ int Run64(x64emu_t *emu, rex_t rex, int seg)
break;
case 0x11:
switch(rep) {
case 0: /* MOVUPS FS:Ex, Gx */
nextop = F8;
GETEX_OFFS(0, tlsdata);
GETGX;
EX->u128 = GX->u128;
break;
case 1: /* MOVSD Ex, Gx */
nextop = F8;
GETEX_OFFS(0, tlsdata);
@@ -187,20 +181,6 @@ int Run64(x64emu_t *emu, rex_t rex, int seg)
}
break;
case 0x6F:
switch(rep) {
case 2: /* MOVDQU Gx, Ex */
nextop = F8;
GETEX_OFFS(0, tlsdata);
GETGX;
memcpy(GX, EX, 16); // unaligned...
break;
default:
return 1;
}
break;
case 0xAF: /* IMUL Gd,Ed */
nextop = F8;
GETED_OFFS(0, tlsdata);
@@ -250,19 +230,6 @@ int Run64(x64emu_t *emu, rex_t rex, int seg)
break;
case 0x63: /* MOVSXD Gd,Ed */
nextop = F8;
GETED_OFFS(0, tlsdata);
GETGD;
if(rex.w)
GD->sq[0] = ED->sdword[0];
else
if(MODREG)
GD->q[0] = ED->dword[0]; // not really a sign extension
else
GD->sdword[0] = ED->sdword[0]; // meh?
break;
case 0x66:
return Run6664(emu, rex);
@@ -349,12 +316,7 @@ int Run64(x64emu_t *emu, rex_t rex, int seg)
ED->dword[0] = GD->dword[0];
}
break;
case 0x8A: /* MOV Gb,Eb */
nextop = F8;
GETEB_OFFS(0, tlsdata);
GETGB;
GB = EB->byte[0];
break;
case 0x8B: /* MOV Gd,Ed */
nextop = F8;
GETED_OFFS(0, tlsdata);
+7 -27
View File
@@ -20,7 +20,7 @@
#include "box64context.h"
#include "bridge.h"
#ifdef DYNAREC
#include "../dynarec/native_lock.h"
#include "../dynarec/arm64_lock.h"
#endif
#include "modrm.h"
@@ -160,26 +160,6 @@ int Run66(x64emu_t *emu, rex_t rex, int rep)
GW->word[0] = imul16(emu, EW->word[0], (uint16_t)tmp16s);
}
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 66 (and maybe other) prefix and use regular conditional jump
R_RIP--;
return 0;
case 0x81: /* GRP3 Ew,Iw */
case 0x83: /* GRP3 Ew,Ib */
@@ -471,12 +451,12 @@ int Run66(x64emu_t *emu, rex_t rex, int rep)
if(rex.w) {
while(tmp64u) {
--tmp64u;
tmp64u2 = *(uint64_t*)R_RDI;
tmp64u = *(uint64_t*)R_RDI;
R_RDI += tmp8s;
if(R_RAX==tmp64u2)
if(R_RAX==tmp64u)
break;
}
if(R_RCX) cmp64(emu, R_RAX, tmp64u2);
if(R_RCX) cmp64(emu, R_RAX, tmp64u);
} else {
while(tmp64u) {
--tmp64u;
@@ -494,12 +474,12 @@ int Run66(x64emu_t *emu, rex_t rex, int rep)
if(rex.w) {
while(tmp64u) {
--tmp64u;
tmp64u2 = *(uint64_t*)R_RDI;
tmp64u = *(uint64_t*)R_RDI;
R_RDI += tmp8s;
if(R_RAX!=tmp64u2)
if(R_RAX!=tmp64u)
break;
}
if(R_RCX) cmp64(emu, R_RAX, tmp64u2);
if(R_RCX) cmp64(emu, R_RAX, tmp64u);
} else {
while(tmp64u) {
--tmp64u;
+14 -137
View File
@@ -55,9 +55,6 @@ int Run660F(x64emu_t *emu, rex_t rex)
uint32_t tmp32u;
uint64_t tmp64u;
float tmpf;
#ifndef NOALIGN
int is_nan;
#endif
reg64_t *oped, *opgd;
sse_regs_t *opex, *opgx, eax1, *opex2;
mmx87_regs_t *opem, *opgm;
@@ -361,7 +358,6 @@ int Run660F(x64emu_t *emu, rex_t rex)
nextop = F8;
GETEX(0);
GETGX;
CHECK_FLAGS(emu);
CONDITIONAL_SET_FLAG(!(GX->u128&EX->u128), F_ZF);
CONDITIONAL_SET_FLAG(!((~GX->u128)&EX->u128), F_CF);
break;
@@ -371,7 +367,7 @@ int Run660F(x64emu_t *emu, rex_t rex)
GETEX(0);
GETGX;
for (int i=0; i<16; ++i) {
GX->ub[i] = abs(EX->sb[i]);
GX->sb[i] = abs(EX->sb[i]);
}
break;
case 0x1D: /* PABSW Gx, Ex */
@@ -379,7 +375,7 @@ int Run660F(x64emu_t *emu, rex_t rex)
GETEX(0);
GETGX;
for (int i=0; i<8; ++i) {
GX->uw[i] = abs(EX->sw[i]);
GX->sw[i] = abs(EX->sw[i]);
}
break;
case 0x1E: /* PABSD Gx, Ex */
@@ -387,7 +383,7 @@ int Run660F(x64emu_t *emu, rex_t rex)
GETEX(0);
GETGX;
for (int i=0; i<4; ++i) {
GX->ud[i] = abs(EX->sd[i]);
GX->sd[i] = abs(EX->sd[i]);
}
break;
@@ -433,49 +429,6 @@ int Run660F(x64emu_t *emu, rex_t rex)
for(int i=1; i>=0; --i)
GX->sq[i] = EX->sd[i];
break;
case 0x30: /* PMOVZXBW Gx, Ex */
nextop = F8;
GETEX(0);
GETGX;
for(int i=7; i>=0; --i)
GX->uw[i] = EX->ub[i];
break;
case 0x31: /* PMOVZXBD Gx, Ex */
nextop = F8;
GETEX(0);
GETGX;
for(int i=3; i>=0; --i)
GX->ud[i] = EX->ub[i];
break;
case 0x32: /* PMOVZXBQ Gx, Ex */
nextop = F8;
GETEX(0);
GETGX;
for(int i=1; i>=0; --i)
GX->q[i] = EX->ub[i];
break;
case 0x33: /* PMOVZXWD Gx, Ex */
nextop = F8;
GETEX(0);
GETGX;
for(int i=3; i>=0; --i)
GX->ud[i] = EX->uw[i];
break;
case 0x34: /* PMOVZXWQ Gx, Ex */
nextop = F8;
GETEX(0);
GETGX;
for(int i=1; i>=0; --i)
GX->q[i] = EX->uw[i];
break;
case 0x35: /* PMOVZXDQ Gx, Ex */
nextop = F8;
GETEX(0);
GETGX;
for(int i=1; i>=0; --i)
GX->q[i] = EX->ud[i];
break;
case 0x39: /* PMINSD Gx, Ex */
nextop = F8;
@@ -485,16 +438,8 @@ int Run660F(x64emu_t *emu, rex_t rex)
if(GX->sd[i]>EX->sd[i])
GX->sd[i] = EX->sd[i];
break;
case 0x3A: /* PMINUW Gx, Ex */
nextop = F8;
GETEX(0);
GETGX;
for(int i=0; i<8; ++i)
if(GX->uw[i]<EX->uw[i])
GX->uw[i] = EX->uw[i];
break;
case 0x3D: /* PMAXSD Gx, Ex */
case 0x3A: /* PMAXSD Gx, Ex */
nextop = F8;
GETEX(0);
GETGX;
@@ -688,25 +633,6 @@ int Run660F(x64emu_t *emu, rex_t rex)
}
break;
case 0x14: // PEXTRB EB, GX, u8
nextop = F8;
GETEB(1);
GETGX;
tmp8u = F8;
EB->byte[0] = GX->ub[tmp8u&0x0f];
break;
case 0x16: // PEXTRD/Q ED, GX, u8
nextop = F8;
GETED(1);
GETGX;
tmp8u = F8;
if(rex.w) {
ED->q[0] = GX->q[tmp8u&1];
} else {
ED->q[0] = GX->ud[tmp8u&3];
}
break;
case 0x17: // EXTRACTPS ED, GX, u8
nextop = F8;
GETED(1);
@@ -805,14 +731,8 @@ int Run660F(x64emu_t *emu, rex_t rex)
nextop = F8;
GETEX(0);
GETGX;
for (int i=0; i<2; ++i) {
#ifndef NOALIGN
if(EX->d[i]<0.0) // on x86, default nan are negative
GX->d[i] = -NAN; // but input NAN are not touched (so sqrt(+nan) -> +nan)
else
#endif
GX->d[i] = sqrt(EX->d[i]);
}
GX->d[0] = sqrt(EX->d[0]);
GX->d[1] = sqrt(EX->d[1]);
break;
case 0x54: /* ANDPD Gx, Ex */
@@ -847,29 +767,15 @@ int Run660F(x64emu_t *emu, rex_t rex)
nextop = F8;
GETEX(0);
GETGX;
for(int i=0; i<2; ++i) {
#ifndef NOALIGN
// add generate a -NAN only if doing inf + -inf
if((isinf(GX->d[i]) && isinf(EX->d[i]) && (EX->q[i]&0x8000000000000000LL)!=(GX->q[i]&0x8000000000000000LL)))
GX->d[i] = -NAN;
else
#endif
GX->d[i] += EX->d[i];
}
GX->d[0] += EX->d[0];
GX->d[1] += EX->d[1];
break;
case 0x59: /* MULPD Gx, Ex */
nextop = F8;
GETEX(0);
GETGX;
for(int i=0; i<2; ++i) {
#ifndef NOALIGN
// mul generate a -NAN only if doing (+/-)inf * (+/-)0
if((isinf(GX->d[i]) && EX->d[i]==0.0) || (isinf(EX->d[i]) && GX->d[i]==0.0))
GX->d[i] = -NAN;
else
#endif
GX->d[i] *= EX->d[i];
}
GX->d[0] *= EX->d[0];
GX->d[1] *= EX->d[1];
break;
case 0x5A: /* CVTPD2PS Gx, Ex */
nextop = F8;
@@ -914,15 +820,8 @@ int Run660F(x64emu_t *emu, rex_t rex)
nextop = F8;
GETEX(0);
GETGX;
for(int i=0; i<2; ++i) {
#ifndef NOALIGN
// sub generate a -NAN only if doing inf - inf
if((isinf(GX->d[i]) && isinf(EX->d[i]) && (EX->q[i]&0x8000000000000000LL)==(GX->q[i]&0x8000000000000000LL)))
GX->d[i] = -NAN;
else
#endif
GX->d[i] -= EX->d[i];
}
GX->d[0] -= EX->d[0];
GX->d[1] -= EX->d[1];
break;
case 0x5D: /* MINPD Gx, Ex */
nextop = F8;
@@ -937,16 +836,8 @@ int Run660F(x64emu_t *emu, rex_t rex)
nextop = F8;
GETEX(0);
GETGX;
for (int i=0; i<2; ++i) {
#ifndef NOALIGN
is_nan = isnan(GX->d[i]) || isnan(EX->d[i]);
#endif
GX->d[i] /= EX->d[i];
#ifndef NOALIGN
if(!is_nan && isnan(GX->d[i]))
GX->d[i] = -NAN;
#endif
}
GX->d[0] /= EX->d[0];
GX->d[1] /= EX->d[1];
break;
case 0x5F: /* MAXPD Gx, Ex */
nextop = F8;
@@ -1266,25 +1157,11 @@ int Run660F(x64emu_t *emu, rex_t rex)
nextop = F8;
GETEX(0);
GETGX;
#ifndef NOALIGN
is_nan = isnan(GX->d[0]) || isnan(GX->d[1]);
#endif
GX->d[0] += GX->d[1];
#ifndef NOALIGN
if(!is_nan && isnan(GX->d[0]))
GX->d[0] = -NAN;
#endif
if(EX==GX) {
GX->d[1] = GX->d[0];
} else {
#ifndef NOALIGN
is_nan = isnan(EX->d[0]) || isnan(EX->d[1]);
#endif
GX->d[1] = EX->d[0] + EX->d[1];
#ifndef NOALIGN
if(!is_nan && isnan(GX->d[1]))
GX->d[1] = -NAN;
#endif
}
break;
Loaded 100 of 289 files, more files were not shown because too many files have changed in this diff. Show more