298 Commits
Author SHA1 Message Date
ptitSeb bedacef673 Bumped version to v0.2.2 2021-05-24 10:44:00 +02:00
ptitSeb 78bafd8b33 [DYNAREC] Forgot this file on previous commit 2021-05-24 10:30:56 +02:00
ptitSeb 6ae9b28325 [DYNAREC] Added 65 69/81/83 opcodes 2021-05-24 09:53:52 +02:00
ptitSeb 68f01f4267 Merge pull request #388 from rajdakin/master
Fixed rpaths for tests 15 and 16
2021-05-23 21:58:55 +02:00
rajdakin d9f953ec82 Added copies of output for failed runs 2021-05-23 21:35:05 +02:00
rajdakin d06795e979 Fixed rpaths for tests 15 and 16 2021-05-23 21:20:11 +02:00
ptitSeb 979ce28de9 Merge pull request #387 from rajdakin/master
Added two linking tests
2021-05-23 21:04:24 +02:00
rajdakin 4aa2a95b59 Added two linking tests 2021-05-23 20:29:01 +02:00
ptitSeb b588709ad9 Changed the way Mutex are check for lock on Signal handling (should help with freeze) 2021-05-21 18:17:41 +02:00
ptitSeb ca95cdcb91 Added 0F FB opcodes ([DYNAREC] too) 2021-05-20 14:07:19 +02:00
ptitSeb bf046a68c4 Added signal mask handling in setjmp/longjmp functions 2021-05-18 11:12:59 +02:00
ptitSeb 490a4ab31c [DYNAREC] Fix unaligned LOCK INC/DEC opcodes 2021-05-17 16:01:59 +02:00
ptitSeb 205133554f [DYNAREC] Fixed some issue were x87 cache is not purged correctly 2021-05-16 15:22:09 +02:00
ptitSeb 4df9b9ac6f [DYNAREC] Force separation of x87 and mmx cache usage 2021-05-16 13:43:48 +02:00
ptitSeb 0b5a943799 Set theme jekyll-theme-hacker 2021-05-16 10:40:16 +02:00
ptitSeb ede0e9d4c3 Added wrapped libexpat (minium symbols for torchlight2) 2021-05-16 10:32:37 +02:00
ptitSeb d33d231120 Small hack to elfloader, so dosbox, unity3d and torchlight2 all seems to works now 2021-05-16 10:05:06 +02:00
ptitSeb 0c1ee23f55 Better log for my_open64 2021-05-12 10:34:03 +02:00
ptitSeb f5554dec6e [DYNAREC] Small fixes for BTC/BSR/BSF opcodes 2021-05-10 10:30:22 +02:00
ptitSeb 6239168118 [DYNAREC] Better race when jumping to nowhere for Trace enabled build 2021-05-10 10:29:31 +02:00
ptitSeb fe9fea0807 [DYNAREC] Small optim on NOT reg8bits opcode 2021-05-10 10:27:53 +02:00
ptitSeb d33917421b [DYNAREC] Fixed 66 0F C8..CF BSWAP opcode 2021-05-09 09:36:35 +02:00
ptitSeb 7c0b11e5e0 [DYNAREC] Added support for unaligned LOCK INC/DEC Ed opcode 2021-05-03 10:15:08 +02:00
ptitSeb 6a84e2eee9 Added support for unaligned LOCK INC/DEC Ed opcode 2021-05-03 10:07:59 +02:00
ptitSeb 26bad84244 Changed canary to have last byte NULL (not randomly placed) 2021-04-25 11:43:05 +02:00
ptitSeb eafd7081f3 Added some tips for winetricks desktop shortcut (for #380) 2021-04-25 10:30:00 +02:00
ptitSeb 2ad2851b2c Added basic support for Symbol Versionning (only consume, not generate yet), and use SymbolVersion on old pthread_cond* functions 2021-04-23 13:51:21 +02:00
ptitSeb f4924f6fd3 [DYNAREC] Added 66 0F F7 opcode 2021-04-23 08:24:36 +02:00
ptitSeb 78920a61ad Fixed some crash with wrapped libSDL_sound 2021-04-22 12:00:05 +02:00
ptitSeb 160f9f964f Added somesupport for R_386_TLS_TPOFF32 reloc (not sure it's 100% correct) 2021-04-22 11:36:55 +02:00
ptitSeb f81435cc2e Added 2 curl wrapped functions 2021-04-22 08:13:32 +02:00
ptitSeb 62df3cbe98 Added 1 more funciton to libSDL2 2021-04-21 15:29:58 +02:00
ptitSeb b0b000a3f2 Added Syscall 331 2021-04-20 20:39:04 +02:00
ptitSeb 9e244e068d Added some more gtk wrapped functions 2021-04-20 18:58:19 +02:00
ptitSeb 4a8d19da78 Another small change to custommem MaxFreeblock handling 2021-04-20 12:17:20 +02:00
ptitSeb 5a0fbcd7ba Fixed a typo in libatk-bridge-2.0.so.0 wrapping 2021-04-19 19:40:44 +02:00
ptitSeb 1ca20269b7 Improvments to ElfLoader Reloc handling 2021-04-19 14:44:26 +02:00
ptitSeb 5b3eb577fc Fixed a small issue with Custom Mem handler and MexFreeBlock calculation 2021-04-19 14:44:09 +02:00
ptitSeb 337d08d466 Added a few more FreeType wrapped functions 2021-04-18 10:40:44 +02:00
ptitSeb e784c34cb4 [DYNAREC] Try to fix some problem when re-loading a lib 2021-04-17 18:09:27 +02:00
ptitSeb 525c54a035 Added wrapped libXft 2021-04-17 17:12:30 +02:00
ptitSeb 65cc054c9c Fixed signature for wrapped function syslog 2021-04-17 16:46:13 +02:00
ptitSeb 64639ae623 Better handling of long double 2021-04-17 13:21:24 +02:00
ptitSeb 74fb70a675 [DYNAREC] Hack for sequence of FLD / FSTP tbytes 2021-04-17 13:20:58 +02:00
ptitSeb ca142fbc56 Use actual curl4 wrapping for curl3 2021-04-16 15:34:28 +02:00
ptitSeb af498728b0 Better trace for semop 2021-04-16 15:34:08 +02:00
ptitSeb a68c5dc00e Added DF D0..D7 opcodes 2021-04-16 08:10:24 +02:00
ptitSeb 7e279e1963 Added 65 40..4F opcodes 2021-04-15 16:20:50 +02:00
ptitSeb 01395347ce Added F3 C0/D0 ocpodes 2021-04-15 16:20:28 +02:00
ptitSeb b5493c779f [DYNAREC] fixed x86size of dynablock sons 2021-04-15 14:11:34 +02:00
ptitSeb 919b071990 Small improvement on custommem handlier 2021-04-15 14:11:02 +02:00
ptitSeb 46a9718d29 Fixed the unload of libs at exit 2021-04-15 13:08:30 +02:00
ptitSeb 82e3fbfbad Better wrapping and trace for __vsprintf_chk 2021-04-15 11:22:35 +02:00
ptitSeb 9004d2b80f Update FUNDING.yml 2021-04-15 10:48:20 +02:00
ptitSeb ddb91106c2 Merge pull request #377 from rajdakin/libFreeOrder
Libraries free order fix
2021-04-14 20:19:55 +02:00
rajdakin 9d7505a61c Fixed the exit crash... 2021-04-14 20:12:09 +02:00
rajdakin e1140c0401 (Hopefully) fixed the library freeing ordering (avoid crash) 2021-04-14 20:06:21 +02:00
ptitSeb 76a0d9bfa3 Also handle internal mutex in my_sighandler 2021-04-14 18:05:44 +02:00
ptitSeb a015c7a368 [DYNAREC] Fixed MVN emitter 2021-04-14 17:36:04 +02:00
ptitSeb 329ed0bb5b Merge pull request #376 from rajdakin/fix11
Stabilized test 11
2021-04-14 11:16:00 +02:00
rajdakin c3bc2808e9 Stabilized test 11 2021-04-14 10:42:50 +02:00
ptitSeb 584586dea8 Added wrapped libSDL_net-1.2.so 2021-04-14 08:53:03 +02:00
ptitSeb 8f84f73162 Added wrapped libSDL2_net-2.0.so (backported from box64) 2021-04-14 08:41:05 +02:00
ptitSeb ce3bf7151a Added wrapped libSDL_sound-1.0.so.1 2021-04-14 08:36:24 +02:00
ptitSeb 5cb5eb296d Merge pull request #375 from rajdakin/addDoc
Added documentation to the python scripts
2021-04-14 07:51:12 +02:00
rajdakin 336b0a42e9 Added a pseudo-documentation for the second generator 2021-04-13 22:32:13 +02:00
ptitSeb a32af2cf76 Adjusted Youtube channels comment on README 2021-04-13 22:21:34 +02:00
rajdakin 307a4f5010 Automated libbz2 and libcrypto 2021-04-13 22:15:11 +02:00
rajdakin 5320b4f22f Added some documentation 2021-04-13 22:14:41 +02:00
ptitSeb 70a1d452f3 Merge pull request #374 from rajdakin/mergeBox64
Improved box86 a bit, added an automation
2021-04-13 21:26:05 +02:00
rajdakin 61869a91c7 Re-added AuxVec 32 (vsyscall) 2021-04-13 21:12:26 +02:00
rajdakin 68bc003fd2 Improved box86 a bit, added an automation 2021-04-13 20:59:32 +02:00
ptitSeb f29912620d Fixed Non-Android build 2021-04-13 18:22:02 +02:00
ptitSeb 4a780af9fe Merge pull request #372 from io12/android
Initial Android support attempt
2021-04-13 17:56:47 +02:00
Benjamin Levy 6b6e6c874b Initial Android support attempt 2021-04-13 10:46:28 -04:00
ptitSeb d42d067945 Enable TokiTori2+ patch for RK3399 too 2021-04-13 11:46:24 +02:00
ptitSeb 17e80a3a09 Added a few syscall around inotify 2021-04-13 10:53:09 +02:00
ptitSeb 674c5b5819 Added wrapped libatk-bridge-2.0.so 2021-04-13 09:36:37 +02:00
ptitSeb 01629e1faf Some function signatures changes and fixed (backported from box64) 2021-04-12 18:34:36 +02:00
ptitSeb 38a33ab15b Fixed 0F E3 opcode 2021-04-11 16:38:08 +02:00
ptitSeb 2163365115 Improvement in internal mutex handling on signal, and [DYNAREC] multitasking changes to the JmpTable 2021-04-11 12:04:41 +02:00
ptitSeb f67902f098 Added F3 A0/E0 opcodes 2021-04-11 08:49:03 +02:00
ptitSeb bfe47b408d Removed a useless definition 2021-04-10 16:12:35 +02:00
ptitSeb aa2bea2d84 Fixed non-Dynarec build 2021-04-10 16:12:20 +02:00
ptitSeb 40c5b1b8d3 Added F3 80 opcode ([DYNAREC] too) 2021-04-10 08:13:35 +02:00
ptitSeb ee714259df Added wrapped GtkWindowClass 2021-04-08 14:26:42 +02:00
ptitSeb aa7b620d8e Some add/changes to libcrypto (for 1.0.2 on 1.1 emulation) 2021-04-07 15:24:59 +02:00
ptitSeb 794c16644b [DYNAREC] Ok, need to save D8..D15 in prolog / restaor them in epilog, they are callee saved 2021-04-07 13:20:02 +02:00
ptitSeb dda64c5b5e And another fix for potential deadlock (after a fork) 2021-04-06 11:55:55 +02:00
ptitSeb 6784a79db0 Fixed SDL AudioSpec structure definition 2021-04-06 11:01:53 +02:00
ptitSeb 564dfea143 Fixed some potentiel deadlock with bridge creation 2021-04-06 08:16:05 +02:00
ptitSeb 7e9f514d8b Removed a debug leftover 2021-04-05 18:38:23 +02:00
ptitSeb 68809a753d Added some more GL wrapped functions 2021-04-05 17:45:02 +02:00
ptitSeb 4ba390abd6 [DYNAREC] On useless test, store the values so defered flags can be computed 2021-04-05 17:44:42 +02:00
ptitSeb fe2b4cb8f3 Improve end of a program (backported frm box64) 2021-04-05 17:43:48 +02:00
ptitSeb dbef73bd75 Fix potential issue on GL when used via SDL2 only 2021-04-05 15:14:37 +02:00
ptitSeb ec19cc1e41 Removed a debugg leftover 2021-04-05 11:06:40 +02:00
ptitSeb 63e099a912 [DYNAREC] Added 66 87 and 66 0F C1/C8..CF opcodes 2021-04-05 11:04:57 +02:00
ptitSeb 282309ee9b Ignore a segfault on access when everything seems fine (probably a multitask glitch, makes linux Terraria works 2021-04-04 22:33:15 +02:00
ptitSeb bd48cae19f Simplified signal handling and [DYNAREC] Simplified dynablock/memory handling (backported from box64) 2021-04-04 18:17:24 +02:00
ptitSeb b2d8a5ceb8 Ooops, this typo must have broken some multitrheads apps 2021-04-04 15:17:48 +02:00
ptitSeb 438677e61a Small changes, mostly cosmetics ([DYNAREC] too) 2021-04-04 15:17:23 +02:00
ptitSeb 44a7535791 Added wrapped FcFreeTypeCharIndex to libfontconfig 2021-04-01 21:57:44 +02:00
ptitSeb 2117a62dc1 Added libdl.so as a dependancy to libGL.so 2021-04-01 21:06:25 +02:00
ptitSeb 99c27bed99 Added wrapped FcCharSetCount function to libfontconfig 2021-04-01 21:03:49 +02:00
ptitSeb 161cd9dc3f [DYNAREC] Change dlog level of this message (to much spam on LOG_INFO) 2021-04-01 18:57:00 +02:00
ptitSeb 0228fcd7d3 Added wrapped FcNameRegisterObjectTypes function to libfontconfig 2021-04-01 16:23:34 +02:00
ptitSeb 3da4e03ddc Merge pull request #367 from rajdakin/fix_rootc
[CMAKE] Fixed builds with '.c' in the path
2021-03-28 20:05:11 +02:00
rajdakin 8030af55b8 [CMAKE] Fixed builds with '.c' in the path 2021-03-28 20:01:56 +02:00
ptitSeb ee757c117c Use a simple pthread_exit wrapping, to not mess with pthread cancel stuff 2021-03-28 17:30:11 +02:00
ptitSeb a93665abf4 Fixed a warning 2021-03-28 14:05:24 +02:00
ptitSeb e3c39f4f97 Better handling of Stacks 2021-03-28 14:03:50 +02:00
ptitSeb 9bf5c20a9a Reworked README a bit 2021-03-27 19:48:55 +01:00
ptitSeb c02a069c5e Fixed aio_suspend64 function signature (fixing file transfert for TeamSpeak Server) 2021-03-27 19:15:08 +01:00
ptitSeb e5bf05c5c2 [DYNAREC] Better handling of bridge 2021-03-27 19:14:17 +01:00
ptitSeb 017d82d16e [DYNAREC] Removed lock on Memory Protection, and change Dynarec generation to have anticiped ending if a block already exist for next address (should help C# and Unity3D softwares) 2021-03-27 12:50:20 +01:00
ptitSeb 5f6d75da12 Added libudev1 as alternative to libudev0 2021-03-27 08:29:07 +01:00
ptitSeb 633919dd74 Small changes t libc and libdbus 2021-03-27 08:00:56 +01:00
ptitSeb e83a119cbb Added one more symbol from libfontconfig 2021-03-26 14:21:49 +01:00
ptitSeb 00ac8ec1aa Added some symbols from SDL2.0.12 and 2.0.14 2021-03-26 14:21:05 +01:00
ptitSeb 491f111caf [DYNAREC] Fixed F3 0F BC opcode 2021-03-25 15:07:52 +01:00
ptitSeb 8e92453f4c Cosmetic changes to some wrapped function signatures from libresolv 2021-03-25 13:58:06 +01:00
ptitSeb bc198c37d7 Improve shutdown sequence 2021-03-25 11:48:46 +01:00
ptitSeb 5ab84a6e78 Minor cosmetic changes to some libc wrapped functions signatures 2021-03-25 11:48:31 +01:00
ptitSeb 334080dfd0 Merge pull request #363 from Jai-JAP/patch-1
Add RPI4ARM64 compiling instructions.
2021-03-25 07:56:06 +01:00
Jai-JAP 46012a6a8c Update COMPILE.md
Add RPI4ARM64 compiling instructions.
2021-03-25 10:45:40 +05:30
ptitSeb 3b546a6048 Smale cosmetic changes 2021-03-24 19:28:52 +01:00
ptitSeb 522b8d5fc0 Fix non-Dynarec build that would crash at start 2021-03-24 19:28:52 +01:00
ptitSeb 74d3bb76da Various small (cosmetics) fixes 2021-03-24 11:42:28 +01:00
ptitSeb a28080e065 Better mecanism for pthreard_once callback handling 2021-03-24 11:42:09 +01:00
ptitSeb 638b341ba5 Avoid potential deadlock on bridge creation with dynarec (may help #217) 2021-03-18 14:26:05 +01:00
ptitSeb c254dc3121 Made the mutex for memory protection recursive, to try mitigate lock on #217 2021-03-17 08:43:43 +01:00
ptitSeb fe0778656b [DYNAREC] cosmetic change 2021-03-17 08:42:42 +01:00
ptitSeb e478b99307 [DYNAREC] Fixed NEON used reg push/pop when calling C function from dynablock 2021-03-15 13:47:59 +01:00
ptitSeb 9d2cd89a7c [DYNAREC] Fixed comment on dynarec on CMake project 2021-03-15 13:47:15 +01:00
ptitSeb be82ccbfcd Merged MMX and x87 regs (like in actual hardware) 2021-03-13 19:13:30 +01:00
ptitSeb 18dfbb61b4 Fixed a few minor leaks 2021-03-13 16:43:29 +01:00
ptitSeb 0f8e39d785 Another batch of various fix, mostly cosmetics 2021-03-13 14:36:02 +01:00
ptitSeb c4fdf490a2 Improve handling of rounding of SSE ([DYNAREC] too) 2021-03-13 08:56:10 +01:00
ptitSeb 55764011db Fixed png16 wrapped png_create_read_struct function signature 2021-03-13 08:51:03 +01:00
ptitSeb 9a483890b6 Merge pull request #360 from WheezyE/patch-3
Update X86WINE.md
2021-03-11 21:35:01 +01:00
Eric Wiessner (KI7POL) 4421377624 Update X86WINE.md
Fixed a typo in the example code section (downloaded libfaudio twice).  Also made more small cosmetic changes.
2021-03-11 13:32:55 -07:00
ptitSeb f817d06e14 Added a workaround for the '...' of g_set_error wrapped function 2021-03-11 17:37:46 +01:00
ptitSeb 6b0b389a69 Merge pull request #359 from Itai-Nelken/patch-1
Improve X86WINE.md
2021-03-10 20:33:07 +01:00
Itai Nelken 496899ffe3 Update X86WINE.md 2021-03-10 21:28:07 +02:00
ptitSeb 7a05331e76 Merge pull request #358 from WheezyE/patch-1
Update X86WINE.md
2021-03-10 19:58:34 +01:00
ptitSeb e7e725cb5e Merge pull request #357 from WheezyE/patch-2
Update README.md
2021-03-10 19:57:39 +01:00
Eric Wiessner (KI7POL) 8385f6ad4e Update README.md
Added Wine installation instructions
2021-03-10 11:19:18 -07:00
Eric Wiessner (KI7POL) aeb3f7a438 Update X86WINE.md
Moved things around a little for readability
2021-03-10 11:13:28 -07:00
ptitSeb d9fa04d2ed Merge pull request #356 from meveric/master
working on glib2 and png16
2021-03-10 11:29:03 +01:00
meveric d4b5e585d1 fixing typos 2021-03-10 10:09:02 +00:00
meveric 8579037bb1 copied symbols from png12 to png16 2021-03-10 09:59:48 +00:00
ptitSeb 13cce1a4dd Various (mostly cosmetics) adjustments to wrapped functions signature 2021-03-09 21:52:07 +01:00
meveric 5724dfad87 wrapped g_cond_init, g_cond_clear, g_cond_wait of glib2 2021-03-09 20:02:53 +00:00
ptitSeb f370bf77a8 [DYNAREC] Better handling of SMC dynablocks 2021-03-08 14:52:17 +01:00
ptitSeb fc3540ac08 Fixed libGLU callback wrapped function, and added libalure wrapped (was ready for a long time in fact) 2021-03-07 18:17:59 +01:00
ptitSeb c16f361c4a Refined .gitignore for TwisterOS Armbian 2021-03-07 17:14:49 +01:00
ptitSeb 92a0f507af Small cosmetics changes in signal handler 2021-03-07 16:54:28 +01:00
ptitSeb 6bb7cdbdd4 Some small improvment on interpretor fow a few MMX opcodes 2021-03-07 16:34:07 +01:00
ptitSeb 1809a2bac3 Small adjustments to pthread cancel handling and a few libc functions signatures 2021-03-07 14:20:44 +01:00
ptitSeb 430658c1a4 Merge pull request #353 from WheezyE/patch-1
Update X86WINE.md
2021-03-07 07:54:17 +01:00
Eric Wiessner (KI7POL) 746383b72b Update X86WINE.md
Just tidying things up a bit more.
2021-03-06 19:52:25 -07:00
ptitSeb d244151ca2 Added 65 13 ADC Gd,GS:Ed opcode (for #349) 2021-03-06 09:20:42 +01:00
ptitSeb e4c1626638 Fix a build error with NOALIGN 2021-03-06 09:20:11 +01:00
ptitSeb c07cee0d01 Merge pull request #350 from WheezyE/patch-1
Create X86WINE.md
2021-03-06 09:16:23 +01:00
Eric Wiessner (KI7POL) 43132bd9b0 Create X86WINE.md
Installation and use of x86 Wine for Box86
2021-03-05 23:37:21 -07:00
ptitSeb ed982e1d2c [DYNAREC] Fixed NotEqual on float/double SSE flag handling (help ut99 build 469) 2021-03-05 16:18:35 +01:00
ptitSeb 7420ea052d Small fix on atol function signature 2021-03-05 15:02:10 +01:00
ptitSeb 044326d337 Added 65 0F B6 opcode 2021-03-03 20:07:42 +01:00
ptitSeb 96c126bbcc Update Zydis header to latest version 2021-03-03 18:55:26 +01:00
ptitSeb ba0e524805 Merge pull request #348 from mobilegmYT/patch-1
Move install instructions higher up and add pi-apps mention
2021-03-02 19:40:57 +01:00
RPI News ba19f56338 Add RPI to pi-apps 2021-03-02 11:26:59 -07:00
RPI News 14df602fa4 Moved install instructions higher up and added pi-apps 2021-03-01 20:06:47 -07:00
ptitSeb d972e205ac Fixed jpeg62 compress issue (should help #343, WeChat and other Wine app that create jpeg with windowscodec) 2021-02-27 16:31:04 +01:00
ptitSeb 114f2b8cd2 Wrapped libtiff.so.5 (minimal set of functions for Wine) 2021-02-27 16:31:04 +01:00
ptitSeb 87f8830d16 [DYNAREC] Fixed DD /1 FISTTP opcode (fixed WK issue) 2021-02-26 11:21:43 +01:00
ptitSeb a0afe05995 [DYNAREC] Added new option BOX86_NODYNAREC to forbid creation of Dynablock in an interval range (to debug difference between Dynarec and Interpretor) 2021-02-26 10:16:35 +01:00
ptitSeb ddd4d37ad1 Merge pull request #345 from SpacingBat3/patch-2
Fixed link to "x86primop.c".
2021-02-25 20:53:14 +01:00
SpacingBat3 ede296ef01 Fixed link to "x86primop.c".
It seems that original link has been broken earlier and I haven't checked that earlier.
This commit should change that.
2021-02-25 20:07:29 +01:00
ptitSeb 1307ce364d [DYNAREC] Small fix for previous commit, adjusting ARM PC 2021-02-25 13:54:34 +01:00
ptitSeb 37fa84d762 [DYNAREC] Get a warning on trace build when jump to NULL address (with some info of the origin of the jump) 2021-02-25 13:46:06 +01:00
ptitSeb b3e984bd22 More fixes to elfloader when hinted memory is not satisfied 2021-02-23 18:43:26 +01:00
ptitSeb 7da5b9b7eb Added some log for elfloader with ET_DYN and hinted addr 2021-02-23 18:36:30 +01:00
ptitSeb 55b979f656 More try at fixing elfloader with ET_DYN that have hinted vaddr 2021-02-23 18:04:18 +01:00
ptitSeb 815a6c3ade More fixes to elfloader for ET_DYN type of elf 2021-02-23 16:04:01 +01:00
ptitSeb 33db7a8005 New change on elfloader and mmap handling 2021-02-23 15:18:49 +01:00
ptitSeb 963ac3039e Deactivated wine_prereserve if not wine_preloaded 2021-02-23 12:09:37 +01:00
ptitSeb 552db005b1 [DYNAREC] Fixed a compilation warning 2021-02-23 09:49:47 +01:00
ptitSeb 2d1e8cf1f2 Deactivated wine_preload again, the order between lib load and wine_preload doesn't seem correct 2021-02-23 07:51:30 +01:00
ptitSeb 8e44e8bf13 Fixed elfloader when using wine_preload (which need MAP_FIXED on mmap) 2021-02-22 22:02:56 +01:00
ptitSeb e7cc7b3409 [DYNAREC] quick fix to the ARM->x87 flags conversion improvment 2021-02-22 20:12:11 +01:00
ptitSeb 4e5473150a Use mmap for custommem (hardcoded optionnal for now), and improve JMPTABLE, DYNAMAP and MEMPROT memory handling 2021-02-22 19:10:09 +01:00
ptitSeb e8e7597c62 Reactivated and improved wine_loader detection and wine_prereserve mecanism 2021-02-22 19:10:09 +01:00
ptitSeb f9b03600d1 Added an error if elfloader mmap are not at the requested address 2021-02-22 19:10:09 +01:00
ptitSeb 88a8ebb1dc Removed the MAP_FIXED flag to elfloader mmap (maybe need to add a warning if allocated mem is at a different location?) 2021-02-22 19:10:09 +01:00
ptitSeb 4445785ee1 [DYNAREC] Improved the CALL 0 hack to make it more generic 2021-02-22 19:10:09 +01:00
ptitSeb 3b3460cbba [DYNAREC] Removed a useless opcode in FNSTSW AX opcode 2021-02-22 19:10:09 +01:00
ptitSeb 7eb6789a25 [DYNAREC] Fixed a warning 2021-02-22 19:10:09 +01:00
ptitSeb 870fed75ad [DYNAREC] Fixed ARM->x87/SSE flag conversion 2021-02-22 19:10:09 +01:00
ptitSeb 833c2809d9 Merge pull request #340 from SpacingBat3/patch-1
Some documentation fixes and improvements.
2021-02-22 09:55:25 +01:00
SpacingBat3 24ec881fe5 Update COMPILE.md
Use "make" command with a parallel jobs limited to the number of the CPU threads for "ODROID", "Other ARM Linux platforms" and "x86 Linux" (which should speed up compiling process for these platforms).
2021-02-20 13:31:06 +01:00
SpacingBat3 d7d7bc91a2 A fix for broken link in README.md
There was one broken link (pointing to `docs/src/` instead to `docs/`).
2021-02-20 12:43:58 +01:00
ptitSeb 1ea8dc828a Merge pull request #339 from SpacingBat3/master
Moved the documentation to "docs/" folder.
2021-02-19 11:53:32 +01:00
ptitSeb ade7d82e52 Test for mutex alignment on pthread_cond_timedwait and pthread_cond_wait 2021-02-18 11:45:31 +01:00
ptitSeb fa5c6652b6 [DYNAREC] Small change to LOCK XADD 2021-02-18 11:44:41 +01:00
ptitSeb a5ab6b1520 Added better way to generate SIGILL (and added 0F 3F Illegal Opcode) 2021-02-18 09:41:28 +01:00
ptitSeb bf74640917 [DYNAREC] Some speedup of signal handling, to help C# and Mono stuffs 2021-02-17 18:18:04 +01:00
ptitSeb 420d309db6 Some more fixes to elfloader (to get both CMR and Potatoman running) 2021-02-17 18:17:13 +01:00
ptitSeb c4d170ebb8 Added 3 data in glib2 wrapped lib 2021-02-17 17:54:06 +01:00
ptitSeb 9cc69095d5 Some fixes to elfloader (fixes SuperHexagon, maybe more) 2021-02-16 14:42:33 +01:00
SpacingBat3 eb5dd2c005 Moved the icon/logo to the "docs/img/" folder. 2021-02-16 14:21:44 +01:00
SpacingBat3 39fbbe61a3 Moved documentation to "docs/" folder. 2021-02-16 14:01:57 +01:00
ptitSeb ba71080fb2 Fixed a warning on threads 2021-02-15 11:41:44 +01:00
ptitSeb db176ad3e3 Update CHANGELOG.md 2021-02-11 21:08:29 +01:00
ptitSeb 002638ef96 Added _pthread_cleanup_pop and _pthread_cleanup_push wrapped function to pthreads lib 2021-02-10 14:33:55 +01:00
ptitSeb 22b74477ac Fixed vfprintf wrapped function for non POWERPCLE build 2021-02-10 14:33:16 +01:00
ptitSeb 9c5a9ebba7 [DYNAREC] Don't allocate too much memory blindly 2021-02-09 16:56:58 +01:00
ptitSeb fce3f38e3a [DYNAREC] Fixed previous optim on mem protectio handling for some special cases 2021-02-09 16:09:05 +01:00
ptitSeb aabb600aed [DYNAREC] Some optimisation with memory protection managment 2021-02-09 14:41:29 +01:00
ptitSeb a062a8efa6 Fixed many SDL2 issue with RWops 2021-02-08 20:18:58 +01:00
ptitSeb 9b690667dc Fixed a warning 2021-02-08 16:18:26 +01:00
ptitSeb de7897c5c2 Wrapped custom mremap to handle memory protection 2021-02-08 14:20:21 +01:00
ptitSeb d3d431d5b1 Improve memory protection managment and multi-threads 2021-02-08 14:19:49 +01:00
ptitSeb 6409f5d40a Merge branch 'master' of https://github.com/ptitSeb/box86 2021-02-08 13:09:11 +01:00
ptitSeb aeab3c815e Improved handling of R_386_COPY and R_386_GLOB_DAT reloc in elfloader (helps c++ progs) 2021-02-08 13:08:36 +01:00
ptitSeb 4837797fae Merge branch 'master' of https://github.com/ptitSeb/box86 2021-02-08 09:59:51 +01:00
ptitSeb 0ffc8682b1 Wrapped libcrypt.so.1 2021-02-07 16:21:01 +01:00
ptitSeb cb35a8d85c Merge branch 'master' of https://github.com/ptitSeb/box86 2021-02-06 14:11:07 +01:00
ptitSeb 5999255b5d Merge pull request #328 from rajdakin/rbit_clz
Added the CLZ and RBIT opcodes
2021-02-06 13:42:30 +01:00
rajdakin a7654c6a80 [PRINTER] Added the CLZ and RBIT opcodes 2021-02-06 13:39:10 +01:00
ptitSeb 2b3791f701 Fixed 2 wrapped functions signature from libudev.so.1 2021-02-06 13:31:42 +01:00
ptitSeb 7f52a18fac Simplified (again?) cancel thread handling 2021-02-05 12:36:44 +01:00
ptitSeb ff8bb3b2e4 [DYNAREC] Changed a bit how arm_lock_storeifnull works 2021-02-05 12:35:23 +01:00
ptitSeb 5b7cc6d4de Improved detection of non-libc header when building elfload_dump.c (should help #327) 2021-02-05 11:37:50 +01:00
ptitSeb 1d9774c913 [DYNAREC] Fixed shrd32c and shld32c emiter when used with c > 0x1f (helps WeChat #324) 2021-02-04 13:28:17 +01:00
ptitSeb 8b13ba26d7 [DYNAREC] Removed a useless opcode on 0F C0 XADD 2021-02-04 13:27:05 +01:00
ptitSeb 8730f4daa6 Merge pull request #325 from MichaIng/patch-1
Update notes about Steam
2021-02-03 12:03:15 +01:00
MichaIng 52f4d2a1a6 Update notes about Steam
The "Remember password" feature works only if libnm is installed, otherwise the next starts hang infinite.

Steam can be started with the small mode mini games list opened directly by using the "+open steam://open/minigameslist" command line arguments.

The Steam for Linux issues have been sorted into a listing, to get a better overview and separation between each issues. The Steam for Windows note has been mode below the list.

A few minor spelling and wording fixes have been applied: "Steam" always with capital S, full sentences, aligned package install instruction on Debian.

Signed-off-by: MichaIng <[email protected]>
2021-02-03 11:39:25 +01:00
ptitSeb 6a498c373c Creation of new bridge is now protected by a mutex 2021-02-02 15:49:03 +01:00
ptitSeb 007c7a887e Added 64 9C PUSHFD opcode (ignoring 64 prefix) 2021-02-02 09:44:28 +01:00
ptitSeb 922a8864e8 [DYNAREC] Optimized 0F BA opcodes 2021-02-01 17:17:24 +01:00
ptitSeb 16383f4577 [DYNAREC] Added 66 0F BA BT/BTS/BTR/BTC Ew, Ib opcodes 2021-02-01 17:17:06 +01:00
ptitSeb bc66bb5be9 [DYNAREC] Added handling of null-sized Dynablock (fixed avgn, maybe other too) 2021-02-01 15:13:32 +01:00
ptitSeb 84360f24c1 Another change on Elfloader to help loading c++ programs 2021-01-31 10:36:34 +01:00
ptitSeb cad160205f Fixed wrapped libusb transfert callbacks (should help #323) 2021-01-30 13:16:05 +01:00
ptitSeb 807519e3c4 Small change to elfloader to help Unity3D games, hopefully without breaking something else 2021-01-29 16:31:54 +01:00
ptitSeb 425ffb6e68 Added an empty crashhandler wrapped lib specific to steam (should help steam stability a bit) 2021-01-28 16:59:43 +01:00
ptitSeb 0ede6b8fa5 Various small fixes are warning removal (especialy for non-dynarec build) 2021-01-28 15:38:39 +01:00
ptitSeb 381d723462 Added preloaded libasan handling (same as libtcmalloc_minimum) 2021-01-28 15:31:05 +01:00
ptitSeb cad8de8cd8 [DYNAREC] Pre-calc entry point for thread only if dynarec is activated 2021-01-28 09:40:19 +01:00
ptitSeb 7d7d275e7e [DYNAREC] Sligtly improved dynarec log at DEBUG level 2021-01-28 09:39:29 +01:00
ptitSeb 80db7d9a21 [DYNAREC] Free all dynablockslist when exiting 2021-01-28 09:38:38 +01:00
ptitSeb d8943af79a [DYNAREC] Changed log level of the Wild block appear warning 2021-01-27 14:51:45 +01:00
ptitSeb bcbf9360af Small leak fix in pathcoll sources 2021-01-27 14:51:13 +01:00
ptitSeb 6320b0928e Improved handling of RPATH 2021-01-27 08:20:35 +01:00
ptitSeb 74afa2551a [DYNAREC] Fixed PF flag computation for TEST opcode that was broken a few commit ago 2021-01-26 15:34:40 +01:00
ptitSeb dd733c4128 [DYNAREC] Some more fixes for special cases in the handling of memory protection (should help #227) 2021-01-25 20:09:12 +01:00
ptitSeb 0eaa1b6c5e Added F3 50..62 opcodes 2021-01-24 16:45:24 +01:00
ptitSeb f595859cf0 [DYNAREC] Small optim on LL/GE/LE/G flahs handling 2021-01-24 16:26:10 +01:00
ptitSeb 85e0d01451 Some fixes for some BOX86_LOG=2 function call details 2021-01-24 15:24:53 +01:00
ptitSeb ec57e035d6 [DYNAREC] Small optim to avoidDefered flag handling when doing ADD/SUB on ESP with a constant 2021-01-24 13:54:21 +01:00
ptitSeb 0d0b4d7364 [DYNAREC] More work on logic and shift emiters and PF flag handling 2021-01-24 12:19:38 +01:00
ptitSeb aeb91fce74 [DYNAREC] Small optim of CF and ZF flag handling on emiters 2021-01-23 12:18:57 +01:00
ptitSeb e163bd842e [DYNAREC] Small optim on MOV32 pseudo arm opcode 2021-01-23 11:45:07 +01:00
ptitSeb 2ff7bd1bc7 [DYNAREC] Small optim on AND32c emiter 2021-01-23 10:45:22 +01:00
ptitSeb 533c703b0d [DYNAREC] Remove workaround for Unreal FMOD SMC code in 81 CMP i32 opcode as it's not more needed 2021-01-23 10:05:25 +01:00
ptitSeb 1d1a82f529 [DYNAREC] Small optim to LEA opcode 2021-01-23 09:50:29 +01:00
ptitSeb 911b95a505 [DYNAREC] Remove dynarec linker mecanism and use generic TableJump instead (also all memory that have a dynablock is protected now, should improve compatibility with C# and program taht use SelfModifyCode) 2021-01-22 16:16:12 +01:00
ptitSeb 8209cf8398 [DYNAREC] Fix a bug when freeing a large dynablock allocation 2021-01-21 18:35:21 +01:00
ptitSeb 02423d4a2d [DYNAREC] Small optim on JumpTable reset function 2021-01-21 16:10:47 +01:00
ptitSeb ba5c13fb6c [DYNAREC] Fixed previous commit, PvZ work again now 2021-01-21 15:58:33 +01:00
ptitSeb ddd13bcab0 [DYNAREC] Removed CALL/RET optimization and replace it with a generic JumpTable mecaniism (get a 10% speedup minimum, probably much more on Wine software) 2021-01-21 11:23:45 +01:00
ptitSeb 3b6800e38e Fixed some warning in RunFS66 function 2021-01-20 12:19:15 +01:00
ptitSeb 6c2ebf91c0 [DYNAREC] Change log level for the Call to 0x0 Warning 2021-01-20 12:09:16 +01:00
ptitSeb a64d1de7cd Added a workaround for glXSwapIntervalMESA to have a stub function if it's not exposed 2021-01-20 10:05:56 +01:00
ptitSeb d6ce7f5c16 Some small changes and trace improvement around glXGetProcAddress and Int 3 2021-01-20 09:00:56 +01:00
ptitSeb 1fe29c512f Added some code to check alignment on mutex and use a aligned one if needed (it's good 99% of the time) 2021-01-19 13:43:24 +01:00
ptitSeb e76176b663 Changed a bit how 66 64 prefix is handled 2021-01-18 16:39:39 +01:00
ptitSeb acbe0527d7 Small improvment to Unimplemented Opcode log 2021-01-18 16:39:21 +01:00
ptitSeb 81d8f2f5c3 Changed 660F opcodes back to a switch (no reason to keep the array of label here) 2021-01-18 14:46:37 +01:00
ptitSeb 8976e77109 Various small improvments to 64 and 65 prefixed opcodes 2021-01-18 14:30:47 +01:00
ptitSeb 31bd7ebfbc Added support for FO 0F BA/5 BTS opcode ([DYNAREC] Too) and fixed some F0 opcodes too (helps #314) 2021-01-18 11:41:30 +01:00
ptitSeb 487b979842 Added some F4 HLT opcode implementation, not sure if it's the best way to do it 2021-01-17 17:12:28 +01:00
ptitSeb efd1408809 Improved log on Double Segfault 2021-01-16 15:30:10 +01:00
ptitSeb 867e8aaa00 Small change in signal handling to allow multiple time a memory protection on same address 2021-01-16 15:28:54 +01:00
ptitSeb e3e5fd7568 Added 65 06 and 65 07 opcodes 2021-01-15 20:08:34 +01:00
ptitSeb 7e6b012a08 Fixed 66 F0 xx opcodes 2021-01-15 18:43:13 +01:00
ptitSeb 546fe18836 Added F0 66 83 ocpcode (only 66 F0 83 was there before) 2021-01-15 16:09:37 +01:00
ptitSeb 1cb7683636 Merge pull request #311 from heavygabriel/master
Clarified a bit more documentation, fixed a lot of typos and removed some redundant codes.
2021-01-14 23:14:00 +01:00
heavygabriel f89c7faf3c Changed documentation per PtitSeb's code review. 2021-01-14 15:12:02 -05:00
heavygabriel cf36c668b3 Merge pull request #1 from ptitSeb/master
sync fork with box86
2021-01-14 14:38:24 -05:00
ptitSeb dd41352392 Added 64 67 3B opcode (for #304) 2021-01-13 19:36:16 +01:00
ptitSeb ec42322f23 Start of a new dev. cycle 2021-01-13 19:35:27 +01:00
heavygabriel 3b8a9b5cc5 Fixed a few typos in README.md 2021-01-12 17:12:12 -05:00
heavygabriel 6d3b2fe902 Simplified some code. 2021-01-12 17:04:27 -05:00
heavygabriel 819ec41320 Updated Copyright year 2021-01-12 16:42:48 -05:00
heavygabriel 40fd950b40 Reworded a bunch of stuff, added consistent formatting and fixed typos. 2021-01-12 16:34:08 -05:00
heavygabriel 4f64c106a7 Removed a bunch of typos, reformulated a big batch of sentences. 2021-01-12 14:32:33 -05:00
303 changed files with 11967 additions and 4318 deletions

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
github: ptitSeb
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
+2
View File
@@ -4,3 +4,5 @@ build*/
.gdb_history
src/git_head.h
backup/
box86_update.sh
restore_backup.sh
-118
View File
@@ -1,118 +0,0 @@
v0.2.0
======
* Improvoment on x86 Flags handling
* A few more opcode added
* A few potential BusError fixed
* Added BOX86_NOVULKAN en. var. disable the wrapping of vulkan libs
* Improvments on libc O_XXXX flags handling
* Now use a custom allocator for Dynarec and Hash tables
* Improvment wrapping of pulse audio
* Optimisation to a few Dynarec opcode (like SHRD/SHLD)
* Improved the tracking of memory protection
* A few more wrapping of libs (like libgssapi_krb5)
* More function wrapping on libturbojpeg
* Preliminary support for POWER9 (ppcle) build
* Many contributed typo and rephrasing of README, COMPILE and USAGE docs
v0.1.8
======
* Fixes on some float to int x87 convertions opcodes
* Reworked all callback mecanisms
* Added libturbojpeg wrapping (and a hack for zoom to force using native one)
* Added BOX86_SAFEMMAP env. var.
* Reworked dynarec memory manager
* Added a few opcodes
* Improve elfloader to not force PltResolver all the time (fixing SuperHexagon and maybe other)
* Reworked Exet and Cancel Thread mecanism
* Added wrapped libldap_r and liblber library (used by wine)
* Reworked Dynarec block handling, and remove the "AddMark" mecanism that wasn't efficient enough
* Added TokiTori 2+ detection and runtime patch on PI
* Fixes on elfloader with TLS object
v0.1.6
======
* Changes in Dynarec to make flags optimizations before CALL and RET opcode less aggressive
* Added Vulkan wrapper
* Improved wrapping of SDL_mixer/ SDL2_mixer lib
* Improved wrapping of some gtk structures
* Added a quick and dirty wrapping of Gtk3 (based on current gtk2)
* Improved the signal handling, should be more stable now (the signal handler from syscall still need some works)
* Added RK3399 profile, and some hints to build the 32bits box86 on 64bits OS
* Fixed some wrapped printf formating not handled correctly
* Fixed some buserror with the new LOCK mecanism handling
* A few more Dynarec opcodes added
* If winedbg is tried to be launched, exit without launching it (it doesn't work anyway)
v0.1.4
======
* Change in Dynarec memory handling, to simplify it (and hopefully optimized it)
* Even more opcodes added.
* And some more Dynarec opcodes.
* Fixed some issue were PltResolver was injected but should not
* Fixed many Dynarec and non dynarec opcodes
* Improved Signal handling
* Added a few more wrapped lib (like curl)
* Gallium9 is wrapped (thx @icecream95)
* Fixed and simplied many wrapped functions (especialy the one were a callback is involved)
* Fixed Dynarec "freeing" a Dynablock somthime corrupting the heap (happens in case of JIT mainly)
* Optimized the way LOCK prefix work when using Dynarec on ARM
* Printer of ARM opcode (for dumping Dynarec blocks) improvement (thx @rajdakin)
v0.1.2
======
* The Dynarec now handle JIT code
* Added support for Unity games (not perfect yet)
* Added support for Wine (not perfect yet). You need an x86 build of Wine to use it
* Added support for Steam (not perfect yet). Note that steam have limited functionnalities on 32bits (only mini-mode is available)
* More wrapped libs
* Added support for "PltResolver", so order of library is less important and many symbol are resolved at runtime
* Added an option to build box86 as a lib (to wrapped dynamic library)
* Better Signal handling (not perfect yet)
* More opcodes added, more opcode fixes.
* More Dynarec opcodes.
* Added support for FS:, and creating custom selector (needed by Wine)
* There is now 1 x86emu_t structure per thread (simplifying/optimising many callback handling)
* Box86 now have a logo!
* Added options handling (only version and help for now). Now it's much usefull exept for version printing.
v0.1.0
=======
* Dynarec!!! Only for ARM (note that dynarec doesn't support JITed code for now)
* Added real support for getcontext/set/context/makecontext/swapcontext
* Preliminary signal handling
* Fixes to SDL(1/2) Image and SDL1 Mixer, and to SDL1.2 RWops usage
* Fixed numerous issues in opcodes (both interpretor and dynarec). FTL works fine now, among many others
* Added wrapped gtk support (still ongoing, many libs involved)
* Make loading of libs more configurable
* If a wrapped native libs is not found, try to use emulated one
* Add en env. var. to force use of emulated lib for certain libs
* Add an env. var. to define wich libGL to use
* Added Install / Uninstall target (using systemd binfmt)
* Added more hardware target (RPis, GameShell...)
* Wrapped more libs (including FreeType, smpeg, ncurses, sndfile...)
v0.0.4
=======
* Improved the Init of dependant Libs. More things work now.
* Added a lot of wrapped functions.
* Added a few wrapped libs (like libz or some other x11 related libs)
* For trace enabled build, Trace can be enabled only after a certain amount of opcodes (still, a debugger would be better)
* Some fixes in a few opcodes, and implemented x87 rounding (SuperMeatBoy behaves better now)
* FTL 1.6.9 still have corrupted music, but older 1.5.13 seems fine (different set of libs)
v0.0.2
=======
* A full commercial games runs fine on the Pandora: Airline Tycoon Deluxe
* Implemented all planed subpart of Box86 except JIT
* CPU Emulation is at 75%, roughly, including x87 and SSE/SSE2. MMX is barely implemented, but barely used anyway
* x87 emulation is simplified, no real x87 State handling (but should not be mandatory, as native libm is used)
* No Signal handling yet
* ELF Loader is crude and probably full of bug. Also, the Init of libs is defered after all symbols are resolved for now.
* Wrapped lib include libc, libm, rt, pthread, libdl, dllinux, libasound, GL, GLU, SDL1/mixer/image, SDL2/mixer/image/smpeg, OpenAL/ALUT, libz, libpng16, vorbisfile, x11/xrandr/xxf86vm.
* Most wrapped libs are still partially implemented (SDL1 & GL should be complete)
* Implemented specific mecanism for SDL(1/2) RWops, to be able to used them both in Native and x86 world
* WorldOfGoo works, but painfully slow on th Pandora (too much double math, and lack of JIT)
* FTL works, but sound is broken (issue with thread? asound? or CPU core?)
* Limbo launch but crash before main menu
+67 -26
View File
@@ -10,6 +10,7 @@ option(RK3399 "Set to ON if targeting an Rockchip RK3399 based device" ${RK3399}
option(GAMESHELL "Set to ON if targeting a GameShell device" ${GAMESHELL})
option(ODROID "Set to ON if targeting an ODroid device" ${ODROID})
option(POWER9 "Set to ON if targeting a POWER9 processor" ${POWER9})
option(ANDROID "Set to ON if targeting an Android device" ${ANDROID})
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 Box86" ${NO_LOADAADR})
@@ -20,9 +21,12 @@ if(PANDORA OR PYRA OR RPI2 OR RPI3 OR RPI4 OR GAMESHELL OR ODROID OR RK3399 OR R
set(NOALIGN OFF CACHE BOOL "")
set(ARM_DYNAREC ON CACHE BOOL "")
endif()
if(ANDROID)
set(NOLOADADDR 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 (WIP, don't use yet)" ${ARM_DYNAREC})
option(ARM_DYNAREC "Set to ON to use ARM Dynamic Recompilation" ${ARM_DYNAREC})
option(POWERPCLE "Set to ON if targeting a little-endian PowerPC device" ${POWERPCLE})
option(SYSV_VARARG "Set to ON if host device uses SysVR4 vararg calling convention" ${SYSV_VARARG})
@@ -228,7 +232,6 @@ set(ELFLOADER_SRC
"${BOX86_ROOT}/src/libtools/myalign.c"
"${BOX86_ROOT}/src/libtools/myalign64.c"
"${BOX86_ROOT}/src/libtools/myfts.c"
"${BOX86_ROOT}/src/libtools/obstack.c"
"${BOX86_ROOT}/src/libtools/sdl1rwops.c"
"${BOX86_ROOT}/src/libtools/sdl2rwops.c"
"${BOX86_ROOT}/src/libtools/signals.c"
@@ -237,6 +240,9 @@ set(ELFLOADER_SRC
"${BOX86_ROOT}/src/dynarec/dynarec.c"
"${BOX86_ROOT}/src/wrapped/generated/wrapper.c"
)
if(NOT ANDROID)
list(APPEND ELFLOADER_SRC "${BOX86_ROOT}/src/libtools/obstack.c")
endif()
set(WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedlibc.c"
@@ -250,10 +256,13 @@ set(WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedlibm.c"
"${BOX86_ROOT}/src/wrapped/wrappedsdl1.c"
"${BOX86_ROOT}/src/wrapped/wrappedsdl1mixer.c"
"${BOX86_ROOT}/src/wrapped/wrappedsdl1net.c"
"${BOX86_ROOT}/src/wrapped/wrappedsdl1image.c"
"${BOX86_ROOT}/src/wrapped/wrappedsdl1sound.c"
"${BOX86_ROOT}/src/wrapped/wrappedsdl1ttf.c"
"${BOX86_ROOT}/src/wrapped/wrappedsdl2.c"
"${BOX86_ROOT}/src/wrapped/wrappedsdl2mixer.c"
"${BOX86_ROOT}/src/wrapped/wrappedsdl2net.c"
"${BOX86_ROOT}/src/wrapped/wrappedsdl2image.c"
"${BOX86_ROOT}/src/wrapped/wrappedsdl2ttf.c"
"${BOX86_ROOT}/src/wrapped/wrappedsmpeg.c"
@@ -270,6 +279,7 @@ set(WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedlibxfixes.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxcursor.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxrender.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxft.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxi.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxss.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxpm.c"
@@ -294,10 +304,8 @@ set(WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedlibxmu.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibz.c"
"${BOX86_ROOT}/src/wrapped/wrappedopenal.c"
"${BOX86_ROOT}/src/wrapped/wrappedalure.c"
"${BOX86_ROOT}/src/wrapped/wrappedalut.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibjpeg.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibjpeg62.c"
"${BOX86_ROOT}/src/wrapped/wrappedturbojpeg.c"
"${BOX86_ROOT}/src/wrapped/wrappedcurl.c"
"${BOX86_ROOT}/src/wrapped/wrappedudev0.c"
"${BOX86_ROOT}/src/wrapped/wrappedudev1.c"
@@ -306,6 +314,7 @@ set(WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedlibdrm.c"
"${BOX86_ROOT}/src/wrapped/wrappedcrypto.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibssl.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibcrypt.c"
"${BOX86_ROOT}/src/wrapped/wrappedutil.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibuuid.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibresolv.c"
@@ -315,6 +324,7 @@ set(WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedfontconfig.c"
"${BOX86_ROOT}/src/wrapped/wrappedfreetype.c"
"${BOX86_ROOT}/src/wrapped/wrappedbz2.c"
"${BOX86_ROOT}/src/wrapped/wrappedexpat.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibsm.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibice.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibusb1.c"
@@ -339,6 +349,7 @@ set(WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappeddbusmenuglib.c"
"${BOX86_ROOT}/src/wrapped/wrappedappindicator.c"
"${BOX86_ROOT}/src/wrapped/wrappedatk.c"
"${BOX86_ROOT}/src/wrapped/wrappedatkbridge.c"
"${BOX86_ROOT}/src/wrapped/wrappedpangoft2.c"
"${BOX86_ROOT}/src/wrapped/wrappedpangocairo.c"
"${BOX86_ROOT}/src/wrapped/wrappedgthread2.c"
@@ -362,12 +373,24 @@ set(WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedlcms2.c"
"${BOX86_ROOT}/src/wrapped/wrappedkrb5.c"
"${BOX86_ROOT}/src/wrapped/wrappedgssapikrb5.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibtiff.c"
"${BOX86_ROOT}/src/wrapped/wrappedldlinux.c"
"${BOX86_ROOT}/src/wrapped/wrappedcrashhandler.c"
)
if(NOT ANDROID)
list(APPEND WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedlibjpeg.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibjpeg62.c"
"${BOX86_ROOT}/src/wrapped/wrappedturbojpeg.c"
)
endif()
set(WRAPPEDS_HEAD "${BOX86_ROOT}/src/wrapped/wrappedd3dadapter9_gen.h")
# If BOX86_ROOT contains a ".c", the build breaks...
string(REPLACE ".c" "_private.h" MODROOT ${BOX86_ROOT})
set(WRAPPEDS_HEAD "")
foreach(A ${WRAPPEDS})
string(REPLACE ".c" "_private.h" B ${A})
string(REPLACE ".c" "_private.h" C ${A})
string(REPLACE "${MODROOT}" "${BOX86_ROOT}" B ${C})
set(WRAPPEDS_HEAD ${WRAPPEDS_HEAD} ${B})
set_source_files_properties(${A} PROPERTIES OBJECT_DEPENDS ${B})
endforeach()
@@ -378,7 +401,7 @@ add_custom_command(
OUTPUT "${BOX86_ROOT}/src/wrapped/generated/functions_list.txt"
COMMAND "${PYTHON_EXECUTABLE}" "${BOX86_ROOT}/rebuild_wrappers.py"
"${BOX86_ROOT}"
"PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "POWERPCLE" "--"
"PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "POWERPCLE" "ANDROID" "--"
${WRAPPEDS_HEAD}
MAIN_DEPENDENCY "${BOX86_ROOT}/rebuild_wrappers.py"
DEPENDS ${WRAPPEDS} ${WRAPPEDS_HEAD}
@@ -406,8 +429,7 @@ if(ARM_DYNAREC)
"${BOX86_ROOT}/src/dynarec/arm_prolog.S"
"${BOX86_ROOT}/src/dynarec/arm_epilog.S"
"${BOX86_ROOT}/src/dynarec/arm_linker.S"
"${BOX86_ROOT}/src/dynarec/arm_table.S"
"${BOX86_ROOT}/src/dynarec/arm_next.S"
"${BOX86_ROOT}/src/dynarec/arm_lock_helper.S"
)
@@ -488,7 +510,11 @@ else()
add_library(${BOX86} OBJECT ${ELFLOADER_SRC} ${WRAPPEDS} "${BOX86_ROOT}/src/git_head.h")
endif()
if(ARM_DYNAREC)
target_link_libraries(${BOX86} dynarec m dl rt pthread)
if(ANDROID)
target_link_libraries(${BOX86} dynarec m dl)
else()
target_link_libraries(${BOX86} dynarec m dl rt pthread)
endif()
endif()
if(${CMAKE_VERSION} VERSION_LESS "3.13")
set_target_properties(${BOX86} PROPERTIES LINK_FLAGS -rdynamic)
@@ -506,7 +532,11 @@ else(BOX86LIB)
add_executable(${BOX86} ${ELFLOADER_SRC} ${WRAPPEDS} "${BOX86_ROOT}/src/git_head.h")
add_dependencies(${BOX86} WRAPPERS)
add_dependencies(${BOX86} PRINTER)
target_link_libraries(${BOX86} m dl rt pthread)
if(ANDROID)
target_link_libraries(${BOX86} m dl)
else()
target_link_libraries(${BOX86} m dl rt pthread)
endif()
if(ARM_DYNAREC)
target_link_libraries(${BOX86} dynarec)
endif()
@@ -547,76 +577,87 @@ if(NOT TARGET uninstall)
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
endif()
add_test(test01 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
add_test(NAME bootSyscall COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-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}/${BOX86}
add_test(NAME bootSyscallC COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-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}/${BOX86}
add_test(NAME printf COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-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}/${BOX86}
add_test(NAME args COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-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}/${BOX86}
add_test(NAME maths1 COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-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}/${BOX86}
add_test(NAME threadsStart COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-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}/${BOX86}
add_test(NAME trig COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-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}/${BOX86}
add_test(NAME pi COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-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}/${BOX86}
add_test(NAME fork COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-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}/${BOX86}
add_test(NAME cppThreads COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-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}/${BOX86}
add_test(NAME tlsData COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-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}/${BOX86}
add_test(NAME fpu COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-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}/${BOX86}
add_test(NAME contexts COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-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}/${BOX86}
add_test(NAME conditionalThreads COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-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 )
# WIP
#add_test(NAME linkingIndirectNoversion COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
# -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(NAME linkingIndirectVersion COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
# -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 )
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
foreach(file ${extension_tests})
get_filename_component(testname "${file}" NAME_WE)
-168
View File
@@ -1,168 +0,0 @@
Usage
----
There are many environment variables to control Box86 behaviour.
#### BOX86_LOG
Controls the Verbosity level of the logs
* 0
* NONE : Current default. No message (except some fatal error)
* 1
* INFO : Show some minimum log (like librairies not found)
* 2
* DEBUG : Details a lot of stuff (like relocations or function called)
* 3
* DUMP : All DEBUG plus DUMP of all ELF Info
#### BOX86_NOBANNER
Control Box86 printing its version and build
* 0 : Enable printing
* 1 : Disable printing
#### BOX86_LD_LIBRARY_PATH
Path to look for x86 libs. Default is current folder and `lib` in current folder.
Also `/usr/lib/i386-linux-gnu` and `/lib/i386-linux-gnu` are added if they exists
#### BOX86_PATH
Path to look for x86 executable. Default is current folder and `bin` in current folder.
#### BOX86_DLSYM_ERROR
* 0 : default. Don't log `dlsym` error
* 1 : Log dlsym error
#### BOX86_TRACE_FILE
Send all log and trace to a file instead of `stdout`
Also, if name contains `%pid` then this is replaced by the actual PID of box86 instance
#### BOX86_TRACE
Only on build with trace enabled. Trace allow the logging of all instruction executed, along with register dump
* 0 : No trace
* 1 : Trace enabled. Trace start after the initialisation of all depending libraries is done
* symbolname : Trace only `symbolname` (trace is disable if the symbol is not found)
* 0xXXXXXXX-0xYYYYYYY : trace only between the 2 addresses
#### BOX86_TRACE_INIT
Use BOX86_TRACE_INIT instead of BOX_TRACE to start trace before the initialisation of libraries and the running program
* 0 : No trace
* 1 : Trace enabled. The trace start with the init of all depending libs is done
#### BOX86_TRACE_START
Only on build with trace enabled.
* NNNNNNN : Start trace only after NNNNNNNN opcode execute (number is an `uint64_t`)
#### BOX86_TRACE_XMM
Only on build with trace enabled.
* 0 : Default, the XMM (i.e. SSE/SSE2) register will not be logged with the general and x86 registers
* 1 : Dump the XMM registers
#### BOX86_LOAD_ADDR
Try to load at 0xXXXXXX main binary (if binary is a PIE)
* 0xXXXXXXXX the load address (only active on PIE programs)
#### BOX86_NOSIGSEGV
Disable handling of SigSEGV ( Very useful for debugging.)
* 0 : default, let x86 program set sighandler for SEGV
* 1 : disable handling of SigSEGV
#### BOX86_NOSIGILL
Disable handling of SigILL (to ease debugging mainly)
* 0 : default, let x86 program set sighandler for Illegal Instruction
* 1 : disable handling of SigILL
#### BOX86_X11COLOR16
PANDORA only: Try converting X11 color from 32 bits to 16 bits (to avoid light green on light cyan windows)
* 0 : default, don't touch X11 colors
* 1 : Change colors arguments in XSetForeground, XSetBackground and XCreateGC
#### BOX86_X11THREADS
Call XInitThreads when loading X11 (for old Loki games with Loki_Compat lib)
* 0 : default, don't force call XInitThreads
* 1 : Call XInitThreads as soon as libX11 is loaded
#### BOX86_X11GLX
Force libX11 GLX extension to be present.
* 0 : Disable the force.
* 1 : default, GLX will always be present when using XQueryExtension
#### BOX86_DYNAREC_DUMP
Enables/disables box86's dynarec dump.
* 0 : Disable Dynarec blocks dump (default)
* 1 : Enable Dynarec blocks dump
* 2 : Enable Dynarec blocks dump with some colors
#### BOX86_DYNAREC_LOG
Set level of DynaRec log
* 0 :
* NONE : No Log for DynaRec
* 1 :
* INFO : Minimum Dynarec Log (only unimplemented OpCode)
* 2 :
* DEBUG : Debug Log for Dynarec (with detail on block created / executed)
* 3 :
* VERBOSE : All above plus more
#### BOX86_DYNAREC
* 0 : Disable Dynarec
* 1 : Enable Dynarec (default)
#### BOX86_DYNAREC_LINKER
* 0 : Disable Dynarec Linker (use that on debug, with dynarec log >= 2, to have detail on wich block get executed)
* 1 : Enable Dynarec Linker (default)
#### BOX86_DYNAREC_SAFEMMAP
* 0 : Default. Some mmp/mmap64 are consider unsafe (depending of flags mainly)
* 1 : Consider all mmap/mmap64 safe to use linker (potential speedup, but potential crash for apps using JIT/Dynarec)
#### BOX86_DYNAREC_TRACE
Enables/Disables trace for generated code
* 0 : Disable trace for generated code (default)
* 1 : Enable trace for generated code (like regular Trace, this will slow down a lot and generate huge logs)
#### BOX86_LIBGL
* libXXXX set the name for libGL (default to libGL.so.1)
* /PATH/TO/libGLXXX set the name and path for libGL
You can also use SDL_VIDEO_GL_DRIVER
#### BOX86_LD_PRELOAD
* XXXX[:YYYYY] force loading XXXX (and YYYY...) libraries with the binary
PreLoaded libs can be emulated or native, and are treated the same way as if they were comming from the binary
#### BOX86_EMULATED_LIBS
* XXXX[:YYYYY] force lib XXXX (and YYYY...) to be emulated (and not wrapped)
Some games uses an old version of some libraries, with an ABI incompatible with native version.
Note that LittleInferno for example is auto detected, and libvorbis.so.0 is automatical added to emulated libs, and same for Don't Starve (and Together / Server variant) that use an old SDL2 too
#### BOX86_ALLOWMISSINGLIBS
Allow box86 to continue even if a library is missing
* 0 : default, stop if a library cannot be loaded
* 1 : continue even if a needed library cannot be loaded. Unadvised, this will, in most cases, crash later on.
#### BOX86_NOPULSE
Disable the load of pulseaudio libraries
* 0 : default, load pulseaudio libraries if present
* 1 : disable the load of pulse audio libraries (libpulse and libpulse-simple), both native and x86 version
#### BOX86_NOGTK
Disable the load of wrapped GTK libraries
* 0 : default, load wrapped gtk libs if present
* 1 : disable the load of wrapped gtk libs (can be used with Steam, along with STEAM_RUNTIME=1 to use i386 versio of gtk)
#### BOX86_NOVULKAN
Disable the load of vulkan libraries
* 0 : default, load vulkan libraries if present
* 1 : disable the load of vulkan libraries both native and x86 version (can be usefull on Pi4)
#### BOX86_FIX_64BIT_INODES
* 0 : Don't fix 64bit inodes (default)
* 1 : Fix 64bit inodes. Helps when running on filesystems with 64bit inodes, the program uses API functions which doesn't support it and the program doesn't use inodes information.
#### BOX86_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_box86signalhandler` in is stack)
then probably need to `finish` 1 or 2 functions (inside `usleep(..)`) and then you'll be in `my_box86signalhandler`,
just before the printf of the Segfault message. Then simply `set waiting=0` to exit the infinite loop.
* 2 : Launch `gdbserver` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process, and go in an endless loop, waiting.
Use `gdb /PATH/TO/box86` and then `target remote 127.0.0.1:1234` to connect to the gdbserver (or use actual IP if not on the machine). After that, the procedure is the same as with ` BOX86_JITGDB=1`.
This mode can be usefull when program redirect all console output to a file (like Unity3D Games)
+131
View File
@@ -0,0 +1,131 @@
v0.2.2
======
* Reworked some elfloader relocation mecanism
* Removed old "smart linker" and replace with a simple "jump table"
* Also removed CALL/RET optomisation from Dynarec, simple Jump Table is faster
* Reworked all memory protection tracking
* A few more wrapped libs and wrapped functions
* A few more opcodes
* A few more dynarec opcodes
* Some optimisation in Dynarec around ZF and CF flags handlings, and LL/GE/LE/G conditionnal opcodes
* Some changes to the "cancel threads" handling
* Some changes to the "thread once" handling
v0.2.0
======
* Improvements on x86 Flags handling.
* A few more opcode has been added.
* A few potential BusError are now fixed.
* Added the BOX86_NOVULKAN en. var. . This is used to disable the wrapping of vulkan libraries.
* Improvments on libc O_XXXX flags handling.
* Box86 now uses a custom allocator for Dynarec and Hash tables.
* Improved the wrapping of pulse audio.
* Optimisation to a few Dynarec opcode (like SHRD/SHLD).
* Improved the tracking of memory protection.
* A few more wrapping of libraries (like libgssapi_krb5).
* More function wrapping on libturbojpeg
* Preliminary support for POWER9 (ppcle) build
* Many contributions to remove typos and rephrase the README, COMPILE and USAGE documents
v0.1.8
======
* Fixes on some float to int x86 convertions opcodes.
* Reworked all callback mecanisms.
* Added libturbojpeg wrapping (and a hack for zoom to force using native one).
* Added the BOX86_SAFEMMAP env. var.
* Reworked Dynarec's memory manager.
* Added a few opcodes.
* Improve elfloader to not force PltResolver all the time (fixing SuperHexagon and maybe other)
* Reworked Exet and Cancel Thread mecanism.
* Added wrapped libldap_r and liblber library (used by wine)
* Reworked Dynarec block handling, and remove the "AddMark" mecanism that wasn't efficient enough
* Added TokiTori 2+ detection and runtime patch on the Raspberry Pi platform
* Fixes on elfloader with TLS object.
v0.1.6
======
* Changes in Dynarec to make flags optimizations before CALL and RET opcode less aggressive.
* Added a Vulkan wrapper.
* Improved wrapping of SDL_mixer/ SDL2_mixer libraries.
* Improved wrapping of some GTK structures.
* Added a quick and dirty wrapping of GTK3 (based on current GTK2).
* Improved the signal handling, should be more stable now (the signal handler from syscall still need some works).
* Added the RK3399 profile, and some hints to build 32bits box86 on 64bits OS.
* Fixed some wrapped printf formating not handled correctly.
* Fixed some buserror with the new LOCK mecanism handling.
* A few more Dynarec opcodes added.
* If winedbg is tried to be launched, exit without launching it (it doesn't work anyways).
v0.1.4
======
* Change in Dynarec's memory handling, to simplify it (and hopefully optimized it).
* Even more opcodes added.
* And some more Dynarec opcodes.
* Fixed some issue were PltResolver was injected but should not be.
* Fixed many Dynarec and non dynarec opcodes.
* Improved Signal handling.
* Added a few more wrapped libraries (like curl).
* Gallium9 is now wrapped (thx @icecream95).
* Fixed and simplied many wrapped functions (especialy the one where a callback is involved).
* Fixed Dynarec "freeing" a Dynablock sometimes causing a corruption of the heap (generally happens in case of JIT code).
* Optimized the way LOCK prefix work when using Dynarec on ARM.
* improvements to the ARM opcode Printer (for dumping Dynarec blocks) improvement (thx @rajdakin).
v0.1.2
======
* The Dynarec now handle JIT code
* Added support for Unity games (not perfect yet).
* Added support for Wine (not perfect yet). You need an x86 build of Wine to use it.
* Added support for Steam (not perfect yet). Note that Steam have limited functionalities on 32bits (only mini-mode is available).
* More wrapped libs
* Added support for the "PltResolver". This makes the order of libraries less important and many symbols are now resolved at runtime.
* Added an option to build Box86 as a library (to wrap dynamic library).
* Better Signal handling (not perfect yet).
* More opcodes added, more opcode fixes.
* More Dynarec opcodes.
* Added support for FS:, and creating custom selector (needed by Wine).
* There is now 1 x86emu_t structure per thread (simplifying/optimising many callback handling).
* Box86 now has a logo!
* Added options handling (only version and help for now). Now it's much usefull exept for version printing.
v0.1.0
=======
* Dynarec!!! Only for ARM (note that Dynarec doesn't support JITed code for now).
* Added real support for getcontext/set/context/makecontext/swapcontext.
* Preliminary signal handling.
* Fixes to SDL(1/2) Image and SDL1 Mixer, and to SDL1.2 RWops usage.
* Fixed numerous issues in opcodes (both interpretor and dynarec). FTL works fine now, among many others.
* Added wrapped GTK support (still ongoing, many libraries involved).
* Make loading of libraries more configurable.
* If a wrapped native library is not found, try to use an emulated one.
* Added an env. var. to force the use of emulated libraries for certain libraries.
* Added an env. var. to precise which libGL to use.
* Added Install / Uninstall target (using systemd binfmt).
* Added more hardware targets (RPis, GameShell...).
* Wrapped more libraries (including FreeType, smpeg, ncurses, sndfile...).
v0.0.4
=======
* Improved the initialisation of dependent libraries. More things work now.
* Added a lot of wrapped functions.
* Added a few wrapped libraries (like libz or some other x11 related library).
* For trace enabled build, Trace can be enabled only after a certain amount of opcodes (still, a debugger would be better).
* Some fixes in a few opcodes, and implemented x87 rounding (SuperMeatBoy behaves better now).
* FTL 1.6.9 still has corrupted music, but older 1.5.13 seems fine (different set of libraries).
v0.0.2
=======
* A full commercial games runs fine on the Pandora platform: Airline Tycoon Deluxe.
* Implemented all planned subparts of Box86 except JIT support.
* CPU Emulation is at roughly 75%. This includes x87 and SSE/SSE2. MMX is barely implemented (but barely used anyway).
* x87 emulation is simplified, no real x87 State handling (but should not be mandatory, as the native libm library is used)
* No Signal handling yet
* ELF Loader is crude and probably full of bugs. Also, the initialisation of libraries are defered after all symbols are resolved for now.
* Wrapped libraries include libc, libm, rt, pthread, libdl, dllinux, libasound, GL, GLU, SDL1/mixer/image, SDL2/mixer/image/smpeg, OpenAL/ALUT, libz, libpng16, vorbisfile, x11/xrandr/xxf86vm.
* Most wrapped libraries are still partially implemented ( the SDL1 & GL libraries should be complete).
* Implemented specific mecanism for SDL(1/2) RWops, to be able to used them both in Native and x86 world.
* WorldOfGoo works, but is painfully slow on the Pandora platform (there is too much double math, and lack of JIT).
* FTL works, but sound is broken (issue with thread? asound? or CPU core?)
* Limbo launches but crashes before main menu.
+5 -5
View File
@@ -12,7 +12,7 @@ Compiling
`mkdir build; cd build; cmake .. -DGAMESHELL=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
#### for RaspberryPI
#### for Raspberry Pi
_a build for model 2, 3 and 4 can be done. Model 1 and 0 cannot (at least not with Dynarec, as they lack NEON support)_
@@ -25,11 +25,11 @@ sudo make install
sudo systemctl restart systemd-binfmt
```
_For Pi4. Change to RPI2 or RPI3 for other models._
_For Pi4. Change to RPI2 or RPI3 for other models. Change to RPI4ARM64 for compiling on arm64. (armhf multiarch or chroot required alongside armhf gcc. Install it with 'sudo apt install gcc-arm-linux-gnueabihf'.)_
#### for ODROID
`mkdir build; cd build; cmake .. -DODROID=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
`mkdir build; cd build; cmake .. -DODROID=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j$(nproc)`
#### for RK3399
@@ -39,11 +39,11 @@ As most RK3399 device run AARCH64 OS, you'll need an `armhf` multiarch environme
#### for Other ARM Linux platforms
`mkdir build; cd build; cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
`mkdir build; cd build; cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j$(nproc)`
#### for x86 Linux
`mkdir build; cd build; cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
`mkdir build; cd build; cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j$(nproc)`
#### use ccmake
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2018-2019 Sebastien Chevalier ("ptitSeb")
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
+30 -28
View File
@@ -1,34 +1,41 @@
# box86
![Official logo](Box86Logo.png "Official Logo")
![Official logo](img/Box86Logo.png "Official Logo")
Linux Userspace x86 Emulator with a twist
Box86 lets you run x86 Linux programs (such as games) on non-x86 Linux, like ARM (host system needs to be 32bit little-endian).
----
You *NEED* a 32-bit subsystem to run and build Box86. Box86 is useless on 64-bit only systems. Also, you *NEED* a 32-bit toolchain to build Box86. A toolchain that only support 64-bit will not compile Box86, and you'll get errors (typically on aarch64, you get "-marm" not recognized, and you'll need a multiarch or chroot environnement).
Compiling/Installation
----
> Compilation instructions can be found [here](COMPILE.md)
> Instructions for installing Wine for Box86 can be found [here](X86WINE.md)
Because Box86 uses the native versions of some "system" libraries, like libc, libm, SDL, and OpenGL, it's easy to integrate and use, and performance can be surprisingly high in some cases.
Box86 lets you run x86 Linux programs (such as games) on non-x86 Linux systems, like ARM (host system needs to be 32bit little-endian).
Most x86 Games need OpenGL, so on ARM platforms a solution like [gl4es](https://github.com/ptitSeb/gl4es) is usually necessary(most ARM platforms only support OpenGL ES and/or their OpenGL implementation is dodgy (see OpenGL on Android)) .
You *NEED* a 32-bit subsystem to run and build Box86. Box86 is useless on 64-bit only systems. Also, you *NEED* a 32-bit toolchain to build Box86. A toolchain that only supports 64-bit will not compile Box86, and you'll get errors (typically on aarch64, you get "-marm" not recognized, and you'll need a multiarch or chroot environnement).
Because Box86 uses the native versions of some "system" libraries, like libc, libm, SDL, and OpenGL, it's easy to integrate and use with most applications, and performance can be surprisingly high in some cases.
Most x86 Games need OpenGL, so on ARM platforms an solution like [gl4es](https://github.com/ptitSeb/gl4es) is usually necessary. (Most ARM platforms only support OpenGL ES and/or their OpenGL implementation is dodgy (see OpenGL on Android).)
Box86 now integrates a DynaRec (dynamic recompiler) for the ARM platform, providing a speed boost between 5 to 10 times faster than only using the interpreter.
Many games already work, for example: WorldOfGoo, Airline Tycoon Deluxe, and FTL. Many of the GameMaker Linux games also run fine (there a long list, among them are UNDERTALE, A Risk of Rain, and Cook Server Delicious)
Many games already work without much tweaking, for example: WorldOfGoo, Airline Tycoon Deluxe, and FTL. Many of the GameMaker Linux games also run fine. (there's a long list, among them are UNDERTALE, A Risk of Rain, and Cook Serve Delicious)
If you are serious about developing Box86, you should install ccache and activate its support in the cmake project (use ccmake for example)
If you are serious about developing Box86, you should install ccache and build Box86 with it. (Use ccmake for example.)
To enable TRACE (i.e. dumping to stdout all individual x86 instructions executed, with dump of registers), you'll also need [Zydis library](https://github.com/zyantific/zydis) available on your system.
Some x86 internal opcodes use parts of "Realmode X86 Emulator Library", see [x86primop.c](src/x86primop.c) for copyright details
Some x86 internal opcodes use parts of "Realmode X86 Emulator Library", see [x86primop.c](../src/emu/x86primop.c) for copyright details
Here are 6 videos, the first 2 of "Airline Tycoon Deluxe" and "Heretic 2" running on a gigahertz OpenPandora (the second one use the dynarec), and the next 2 of "Bit.Trip.Runner" and "Neverwinter Night" running on an ODroid XU4 (without dynarec), and the last 2 on a Pi4: Shovel Knight (video from @ITotalJustice) and Freedom Planet (video from @djazz), also without dynarec.
Here's 6 videos, the first 2 videos are videos of "Airline Tycoon Deluxe" and "Heretic 2" running on a GigaHertz OpenPandora (the second one is using the dynarec), and the next 2 videos are videos of of "Bit.Trip.Runner" and "Neverwinter Night" running on an ODroid XU4 (without dynarec), and the last 2 videos are on on a Pi4: Shovel Knight (video from @ITotalJustice) and Freedom Planet (video from @djazz), also without dynarec.
[![Play on Youtube](https://img.youtube.com/vi/bLt0hMoFDLk/3.jpg)](https://www.youtube.com/watch?v=bLt0hMoFDLk) [![Play on Youtube](https://img.youtube.com/vi/MM7kWYts7IA/3.jpg)](https://www.youtube.com/watch?v=MM7kWYts7IA) [![Play on Youtube](https://img.youtube.com/vi/8hr71S029Hg/1.jpg)](https://www.youtube.com/watch?v=8hr71S029Hg) [![Play on Youtube](https://img.youtube.com/vi/B4YN37z3-ws/1.jpg)](https://www.youtube.com/watch?v=B4YN37z3-ws) [![Play on Youtube](https://img.youtube.com/vi/xk8Q30mxqPg/1.jpg)](https://www.youtube.com/watch?v=xk8Q30mxqPg) [![Play on Youtube](https://img.youtube.com/vi/_QMRMVvYrqU/1.jpg)](https://www.youtube.com/watch?v=_QMRMVvYrqU)
You can find many more Box86 video on [PI Lab Channel](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) [![PI Lab Channel](https://yt3.ggpht.com/a/AATXAJyMeWrgCjs78gr6To6yX4KtDPUCS7hsbX1rRA=s100-c-k-c0xffffffff-no-rj-mo)](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g).
You can find many more Box86 video on Youtube in the [Pi Labs Channel](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) or [The Byteman Channel](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA)
Compatibility list is there: https://github.com/ptitSeb/box86-compatibility-list/issues
<img src="Box86Icon.png" width="96" height="96">
<img src="img/Box86Icon.png" width="96" height="96">
Logo and Icon made by @grayduck, thanks!
@@ -39,21 +46,14 @@ Note that this project is not to be mistaken with [86box](https://github.com/86B
Discord
----
If you want to discuss(or have any problems) about box86, there is a Discord friendly server there: [PI Lab Discord](https://discord.gg/Fh8sjmu)
----
Compiling
----
Compilation instructions can be found [here](COMPILE.md)
If you want to discuss (or have any problems) about box86, feel free to join the [Pi Labs Discord Server](https://discord.gg/Fh8sjmu)!
----
Usage
----
There are a few environment variables to control the behaviour of Box86.
There are a few environment variables to control the behaviour of Box86.
See [here](USAGE.md) for all environment variables and what they do.
@@ -90,11 +90,14 @@ TL;DR: Not all Unity games work and can require a high OpenGL profile, but the s
Notes about Steam
----
Linux Steam's can run now with box86. But it's still a bit unstable, and not everything works. First problem is steam crashing after the Sign in window, if you encounter this issue, you may need to add libappindicator. Installing the package on debian `sudo apt install libappindicator1`.
Once open, Steam will only work on "Small Mode" and in "Big Picture", not in the regular "Large Mode"(This is because some steam component used in the browser view are only 64 bits now.). So go in the "View" menu and switch to Small view, else the list will stay empty.
Final words, to avoid the "libc.so.6 is absent" message, you can use `STEAMOS=1` and `STEAM_RUNTIME=1` as environment variables.
(Steam for Windows installs fine but doesn't work yet)
Some Steam games (most Source engine games, like "Portal" or "Half-Life 2") use libtcmalloc. Box86 will detect it and will try to LD_PRELOAD it, for better compatibility. While it should work without the aformentionned feature, it is safer to add it to your system if you intend to play those game (something like `sudo apt install libtcmalloc-minimal4` to install it on Debian and Debian's deriatives)
Linux Steam's can run now with box86. But it's still a bit unstable, and not everything works:
- First problem is Steam crashing after the sign-in window, if you encounter this issue, you may need to add libappindicator. To install it on Debian, run `sudo apt install libappindicator1`.
- If you select to "Remember password", Steam is crashing on subsequent starts, unless you have libnm intalled. To install it on Debian, run `sudo apt install libnm0`.
- Once open, Steam will only work on "Small Mode" and in "Big Picture", not in the regular "Large Mode". This is because some Steam components used in the browser view are only 64-bit now. So go in the "View" menu and switch to "Small view", else the list will stay empty. Alternatively, Steam can be started in small mode directly by using `+open steam://open/minigameslist` command line arguments.
- To avoid the "libc.so.6 is absent" message, you can use `STEAMOS=1` and `STEAM_RUNTIME=1` as environment variables.
- Some Steam games (most Source engine games, like "Portal" or "Half-Life 2") use libtcmalloc. Box86 will detect it and will try to LD_PRELOAD it, for better compatibility. While it should work without the aformentionned feature, it is safer to add it to your system if you intend to play those game. To install it on Debian, run `sudo apt install libtcmalloc-minimal4`.
Steam for Windows installs fine but doesn't work yet.
----
@@ -102,11 +105,10 @@ Notes about Wine
----
Wine is now partly supported. Wine integrated program all runs, and some windows programs and games now runs fine. Don't forget most Windows games use Direct3D, this may require a complete OpenGL driver and as high profile as possible (and gl4es with ES2 backend have issue with Wine for now). Also, vulkan is not wrapped on box86, so vk3d is not usable yet, even if supported by the hardware.
Note: if you plan to use box86 with Wine on Raspberry Pi 3 or earlier, those models use a default OS that have a kernel with a 2/2 Split (meaning 2G of space for user program, and 2G of space for the Kernel). This is not compatible with Wine programs that needs to access memory > 2Gb address. So you'll need to reconfigure your kernel for a 3G/1G split. Use your favorite search engine for instructions on how to do that.
Note: if you plan to use box86 with Wine on Raspberry Pi 3 or earlier, those models use a default OS that have a kernel with a 2/2 Split (meaning 2G of space for user program, and 2G of space for the Kernel). This is not compatible with Wine programs that needs to access memory > 2Gb address. So you'll need to reconfigure your kernel for a 3G/1G split.
----
Final words
----
(If you use Box86 in your project, please don't forget to mention Box86)
(If you use Box86 in your project, please don't forget to mention Box86!)
Executable
+161
View File
@@ -0,0 +1,161 @@
Usage
----
There are many environment variables to control Box86 behaviour.
#### BOX86_LOG
Controls the Verbosity level of the logs
* 0: NONE : No message (except some fatal error). (Default.)
* 1: INFO : Show some minimum log (Example: librairies not found)
* 2: DEBUG : Details a lot of stuff (Example: relocations or functions called).
* 3: DUMP : All DEBUG plus DUMP of all ELF Info.
#### BOX86_NOBANNER
Disables Box86 printing its version and build
* 0 : Enable printing its banner. (Default.)
* 1 : Disable printing its banner.
#### BOX86_LD_LIBRARY_PATH
Path to look for x86 libraries. Default is current folder and `lib` in current folder.
Also, `/usr/lib/i386-linux-gnu` and `/lib/i386-linux-gnu` are added if they exist.
#### BOX86_PATH
Path to look for x86 executable. Default is current folder and `bin` in current folder.
#### BOX86_DLSYM_ERROR
Enables/Disables the logging of `dlsym` errors.
* 0 : Don't log `dlsym` errors. (Default.)
* 1 : Log dlsym errors.
#### BOX86_TRACE_FILE
Send all log and trace to a file instead of `stdout`
Also, if name contains `%pid` then this is replaced by the actual PID of box86 instance
#### BOX86_TRACE
Only on build with trace enabled. Trace allow the logging of all instruction executed, along with register dump
* 0 : No trace. (Default.)
* 1 : Trace enabled. Trace start after the initialisation of all depending libraries is done.
* symbolname : Trace only `symbolname` (trace is disable if the symbol is not found).
* 0xXXXXXXX-0xYYYYYYY : Trace only between the 2 addresses.
#### BOX86_TRACE_INIT
Use BOX86_TRACE_INIT instead of BOX_TRACE to start trace before the initialisation of libraries and the running program
* 0 : No trace. (Default.)
* 1 : Trace enabled. The trace start with the initialisation of all depending libraries is done.
#### BOX86_TRACE_START
Only on builds with trace enabled.
* NNNNNNN : Start trace only after NNNNNNNN opcode execute (number is an `uint64_t`).
#### BOX86_TRACE_XMM
Only on builds with trace enabled.
* 0 : The XMM (i.e. SSE/SSE2) register will not be logged with the general and x86 registers. (Default.)
* 1 : Dump the XMM registers.
#### BOX86_LOAD_ADDR
Try to load at 0xXXXXXX main binary (if binary is a PIE)
* 0xXXXXXXXX : The load address . (Only active on PIE programs.)
#### BOX86_NOSIGSEGV
Disable handling of SigSEGV. (Very useful for debugging.)
* 0 : Let the x86 program set sighandler for SEGV (Default.)
* 1 : Disable the handling of SigSEGV.
#### BOX86_NOSIGILL
Disable handling of SigILL (to ease debugging mainly).
* 0 : Let x86 program set sighandler for Illegal Instruction
* 1 : Disables the handling of SigILL
#### BOX86_X11COLOR16
PANDORA only: Try converting X11 color from 32 bits to 16 bits (to avoid light green on light cyan windows).
* 0 : Don't touch X11 colors. (Default.)
* 1 : Change colors arguments in XSetForeground, XSetBackground and XCreateGC.
#### BOX86_X11THREADS
Call XInitThreads when loading X11. (This is mostly for old Loki games with the Loki_Compat library.)
* 0 : Don't force call XInitThreads. (Default.)
* 1 : Call XInitThreads as soon as libX11 is loaded.
#### BOX86_X11GLX
Force libX11's GLX extension to be present.
* 0 : Do not force libX11's GLX extension to be present.
* 1 : GLX will always be present when using XQueryExtension. (Default.)
#### BOX86_DYNAREC_DUMP
Enables/disables Box86's Dynarec's dump.
* 0 : Disable Dynarec's blocks dump. (Default.)
* 1 : Enable Dynarec's blocks dump.
* 2 : Enable Dynarec's blocks dump with some colors.
#### BOX86_DYNAREC_LOG
Set the level of DynaRec's logs.
* 0 : NONE : No Logs for DynaRec. (Default.)
* 1 :INFO : Minimum Dynarec Logs (only unimplemented OpCode).
* 2 : DEBUG : Debug Logs for Dynarec (with details on block created / executed).
* 3 : VERBOSE : All of the above plus more.
#### BOX86_DYNAREC
Enables/Disables Box86's Dynarec.
* 0 : Disables Dynarec.
* 1 : Enable Dynarec. (Default.)
#### BOX86_DYNAREC_TRACE
Enables/Disables trace for generated code.
* 0 : Disable trace for generated code. (Default.)
* 1 : Enable trace for generated code (like regular Trace, this will slow down the program a lot and generate huge logs).
#### BOX86_NODYNAREC
Forbid dynablock creation in the interval specified (helpfull for debugging behaviour difference between Dynarec and Interpretor)
* 0xXXXXXXXX-0xYYYYYYYY : define the interval where dynablock cannot start (inclusive-exclusive)
#### BOX86_LIBGL
* libXXXX set the name for libGL (defaults to libGL.so.1).
* /PATH/TO/libGLXXX : Sets the name and path for libGL
You can also use SDL_VIDEO_GL_DRIVER
#### BOX86_LD_PRELOAD
* XXXX[:YYYYY] force loading XXXX (and YYYY...) libraries with the binary
PreLoaded libs can be emulated or native, and are treated the same way as if they were comming from the binary
#### BOX86_EMULATED_LIBS
* XXXX[:YYYYY] force lib XXXX (and YYYY...) to be emulated (and not wrapped)
Some games uses an old version of some libraries, with an ABI incompatible with native version.
Note that LittleInferno for example is auto detected, and libvorbis.so.0 is automatical added to emulated libs, and same for Don't Starve (and Together / Server variant) that use an old SDL2 too
#### BOX86_ALLOWMISSINGLIBS
Allow Box86 to continue even if a library is missing.
* 0 : Box86 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.
#### BOX86_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
#### BOX86_NOGTK
Disables the loading of wrapped GTK libraries.
* 0 : Load wrapped GTK libraries if found. (Default.)
* 1 : Disables loading wrapped GTK libraries (can be used with Steam, along with STEAM_RUNTIME=1 to use the i386 version of GTK).
#### BOX86_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.)
#### BOX86_FIX_64BIT_INODES
Fix/Don't fix 64bit inodes
* 0 : Don't fix 64bit inodes. (Default.)
* 1 : Fix 64bit inodes. Helps when running on Filesystems with 64bit inodes. Is useful when a program uses API functions which doesn't support it and the program doesn't use inodes information.
#### BOX86_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_box86signalhandler` in is stack)
then probably need to `finish` 1 or 2 functions (inside `usleep(..)`) and then you'll be in `my_box86signalhandler`,
just before the printf of the Segfault message. Then simply
`set waiting=0` to exit the infinite loop.
* 2 : Launch `gdbserver` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process, and go in an endless loop, waiting.
Use `gdb /PATH/TO/box86` and then `target remote 127.0.0.1:1234` to connect to the gdbserver (or use actual IP if not on the machine). After that, the procedure is the same as with ` BOX86_JITGDB=1`.
This mode can be usefullwhen programs redirect all console output to a file (like Unity3D Games)
+143
View File
@@ -0,0 +1,143 @@
# Installing Wine (and winetricks)
Using Wine with Box86 allows (x86) Windows programs to run on ARM Linux computers (x64 is not yet implemented).
See installation steps below (in the [Examples](#examples) section).
_TwisterOS users, take note: Wine, winetricks, and Box86 are pre-installed in TwisterOS. TwisterOS users do not have to install anything._
Box86 actually needs `wine-i386` to be installed **manually** on ARM devices. Even though `wine-armhf` is available in many repo's on ARM devices (ie using _apt-get_ will attempt to install `wine-armhf` by default), `wine-armhf` will not work with Box86. Note that manual installation is required since using `multiarch` will result in your ARM device thinking it needs to install lots of i386 dependencies to make `wine-i386` work. The "twist" in Box86 is that Box86 "wraps" many Windows and Wine i386 libraries (`.so` or `.dll` files) so that they will work with your ARM device's libraries. Also note that wrapping libraries is an ongoing process throughout Box86 development and that some programs may not run properly until all of their i386 library dependencies are wrapped.
Installation files for Wine can be found in the [WineHQ repository](https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/), the [TwisterOS FAQ](https://twisteros.com/faq.html) page, or the [PlayOnLinux website repository](https://www.playonlinux.com/wine/). Box86 requires the "i386" (x86) versions of Wine install files (even though we are installing it on an ARM processor). Box86 "wraps" many of Wine's core Linux i386 libraries so that their calls are interpretable by Linux ARM libraries. Below are examples of how to install Wine from each of those places.
_Raspberry Pi users: Wine requires a 3G/1G split memory kernel. Raspberry Pi OS for the Pi 4 has a 3G/1G split kernel, but **the Pi 3 and earlier models have a 2G/2G kernel by default and will need you to install a custom-compiled 3G/1G kernel to get Wine to work.**
## Overview
The general procedure for installing Wine for Box86 is to...
- Download all the install files (.deb, .zip, or even .pol files) for the version of Wine you wish to install
- Unzip or dpkg the install files into one folder
- Move that folder to the directory that you wish Wine to run from (in TwisterOS, this is `~/wine/` by default)
- Go to `/usr/local/bin` and make symlinks or scripts that will point to your main wine binaries (`wine`, `winecfg`, and `wineserver`).
- Boot wine to create a new wineprefix (`wine wineboot`).
- Download winetricks (which is simply a very complicated bash script), make it executable, then copy it to `/usr/local/bin`.
## Examples
_These examples were all tested on Raspberry Pi 4. Note the similarities between the different install methods._
### Installing wine-devel, wine-stable, or wine-staging for Raspberry Pi OS Buster from WineHQ deb files
_Links from the [WineHQ repo](https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/)_
```
# Backup any old wine installations
sudo mv ~/wine ~/wine-old
sudo mv ~/.wine ~/.wine-old
sudo mv /usr/local/bin/wine /usr/local/bin/wine-old
sudo mv /usr/local/bin/wineboot /usr/local/bin/wineboot-old
sudo mv /usr/local/bin/winecfg /usr/local/bin/winecfg-old
sudo mv /usr/local/bin/wineserver /usr/local/bin/wineserver-old
# Download, extract wine, and install wine
# (Replace the links/versions below with links/versions from the WineHQ site for the version of wine you wish to install. Note that we need the i386 version for Box86 even though we're installing it on our ARM processor.)
# (Pick an i386 version of wine-devel, wine-staging, or wine-stable)
cd ~/Downloads
wget https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/wine-devel-i386_5.21~buster_i386.deb # NOTE: Replace this link with the version you want
wget https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/wine-devel_5.21~buster_i386.deb # NOTE: Also replace this link with the version you want
dpkg-deb -xv wine-devel-i386_5.21~buster_i386.deb wine-installer # NOTE: Make sure these dpkg command matches the filename of the deb package you just downloaded
dpkg-deb -xv wine-devel_5.21~buster_i386.deb wine-installer
mv ~/Downloads/wine-installer/opt/wine* ~/wine
rm wine*.deb # clean up
rm -rf wine-installer # clean up
# Install shortcuts (make 32bit launcher & symlinks. Credits: grayduck, Botspot)
echo -e '#!/bin/bash\nsetarch linux32 -L '"$HOME/wine/bin/wine "'"$@"' | sudo tee -a /usr/local/bin/wine >/dev/null # Create a script to launch wine programs as 32bit only
#sudo ln -s ~/wine/bin/wine /usr/local/bin/wine # You could aslo just make a symlink, but box86 only works for 32bit apps at the moment
sudo ln -s ~/wine/bin/wineboot /usr/local/bin/wineboot
sudo ln -s ~/wine/bin/winecfg /usr/local/bin/winecfg
sudo ln -s ~/wine/bin/wineserver /usr/local/bin/wineserver
sudo chmod +x /usr/local/bin/wine /usr/local/bin/wineboot /usr/local/bin/winecfg /usr/local/bin/wineserver
# These packages are needed for running wine-staging on RPi 4 (Credits: chills340)
sudo apt install libstb0 -y
cd ~/Downloads
wget -r -l1 -np -nd -A "libfaudio0_*~bpo10+1_i386.deb" http://ftp.us.debian.org/debian/pool/main/f/faudio/ # Download libfaudio i386 no matter its version number
dpkg-deb -xv libfaudio0_*~bpo10+1_i386.deb libfaudio
sudo cp -TRv libfaudio/usr/ /usr/
rm libfaudio0_*~bpo10+1_i386.deb # clean up
rm -rf libfaudio # clean up
# Boot wine (make fresh wineprefix in ~/.wine )
wine wineboot
```
### Installing Wine for Raspberry Pi OS from the Twister OS FAQ page
_Links from the [TwisterOS FAQ](https://twisteros.com/faq.html)_
```
# Backup any old wine installations
sudo mv ~/wine ~/wine-old
sudo mv ~/.wine ~/.wine-old
sudo mv /usr/local/bin/wine /usr/local/bin/wine-old
sudo mv /usr/local/bin/wineboot /usr/local/bin/wineboot-old
sudo mv /usr/local/bin/winecfg /usr/local/bin/winecfg-old
sudo mv /usr/local/bin/wineserver /usr/local/bin/wineserver-old
# Download, extract wine, and install wine (last I checked, the Twister OS FAQ page had Wine 5.13-devel)
wget https://twisteros.com/wine.tgz -O ~/wine.tgz
tar -xzvf ~/wine.tgz
rm ~/wine.tgz # clean up
# Install shortcuts (make launcher & symlinks. Credits: grayduck, Botspot)
echo -e '#!/bin/bash\nsetarch linux32 -L '"$HOME/wine/bin/wine "'"$@"' | sudo tee -a /usr/local/bin/wine >/dev/null # Create a script to launch wine programs as 32bit only
#sudo ln -s ~/wine/bin/wine /usr/local/bin/wine # You could aslo just make a symlink, but box86 only works for 32bit apps at the moment
sudo ln -s ~/wine/bin/wineboot /usr/local/bin/wineboot
sudo ln -s ~/wine/bin/winecfg /usr/local/bin/winecfg
sudo ln -s ~/wine/bin/wineserver /usr/local/bin/wineserver
sudo chmod +x /usr/local/bin/wine /usr/local/bin/wineboot /usr/local/bin/winecfg /usr/local/bin/wineserver
# Boot wine (make fresh wineprefix in ~/.wine )
wine wineboot
```
## Installing winetricks
Winetricks is a script which makes it easier to install & configure any desired Windows core system software packages which may be dependencies for certain Windows programs.
```
# Backup old winetricks
sudo mv /usr/local/bin/winetricks /usr/local/bin/winetricks-old
# Download
cd ~/Downloads
wget https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks
# Install
sudo chmod +x winetricks
sudo mv winetricks /usr/local/bin/
# winetricks needs this installed
sudo apt-get install cabextract -y
```
If you have a desktop menu itm for wintricks, you may need to edit it to add the nobanner env var. Do so by edition `/usr/share/applications/winetricks.desktop` with your favorite text editor (not that you'll need `sudo` to save the file) and change from `Exec=winetricks --gui` to `Exec=env BOX86_NOBANNER=1 winetricks --gui`
## Example commands
Here is an example of how we should run a winetricks command with box86:
`BOX86_NOBANNER=1 winetricks -q corefonts vcrun2010 dotnet20sp1`
_This command will silently install three packages in series: Windows core fonts, VC++ 2010 Runtimes, and .NET 2.0 SP1. `-q` is the "install silent/quiet" command._
Whenever we run winetricks, we must suppress Box86's banner by typing `BOX86_NOBANNER=1` to prevent winetricks from crashing. Invoking Box86's logging features (with `BOX86_LOG=1` or similar) will also cause winetricks to crash. (If Box86 logging is necessary though, we can patch winetricks to avoid these crashes - see the *Troubleshooting* section) # future work.
For a list of all the different Windows packages & libraries that winetricks can help you install, run `winetricks list-all`
## Other notes
### Wineprefixes (and Wine initialization)
The first time Wine is run (`wine wineboot`), it will create a fresh wineprefix for you (by default, located in the hidden folder `~/.wine`). Think of a wineprefix as Wine's virtual 'harddrive' where it installs software and saves settings. Wineprefixes are portable and deletable.
If you at any point corrupt something inside your default wineprefix, you can start "fresh" by deleting your `~/.wine` directory (with the `rm -rf ~/.wine` command) and boot wine again to create a new default wineprefix.
### Transplanting wineprefixes (side-loading)
When you first run or boot Wine (`wine wineboot`), Wine will create a new user environment within which to install Windows software. This user environment is called a "wineprefix" (or "wine bottle") and is located (by default) in `~/.wine` (note that Linux folders with a `.` in front of them are "hidden" folders). For more Wine documentation, see [WineHQ](https://www.winehq.org/documentation).
If software isn't installing in Wine with Box86, but is installing for you in Wine on a regular x86 Linux computer, you can copy a wineprefix from your x86 Linux computer to the device you're running Box86 on. This is most easily done by tarring the `~/.wine` folder on your x86 Linux computer (`tar -cvf winebottle.tar ~/.wine`), transferring the tar file to your device, then un-tarring the tar file (`tar -xf winebottle.tar`) on your device running Box86 & Wine. Tarring the wineprefix preserves any symlinks that are inside it.
### Swapping out different versions of Wine
Some versions of Wine work better with certain software. It is best to install a version of Wine that is known to work with the software you would like to run. There are three main development branches of Wine you can pick from, referred to as wine-stable, wine-devel, and wine-staging. _Note that the wine-staging branch requires extra installation steps on Raspberry Pi._
Your entire Wine installation can reside within a single folder on your Linux computer. TwisterOS assumes that your Wine installation is located inside the `~/wine/` directory. The actual directory where you put your `wine` folder doesn't matter as long as you have symlinks within the `/usr/local/bin/` directory which point to the `wine` folder so that Linux can find Wine when you type `wine` into the terminal).
You can change which version of Wine you are running simply by renaming your old `wine` and `.wine` folders to something else, then putting a new `wine` folder (containing your new version of Wine) in its place. Running `wine wineboot` again will make a fresh wineprefix with your new version of Wine. You can check which version of Wine you're running with the `wine --version` command.
+1
View File
@@ -0,0 +1 @@
theme: jekyll-theme-hacker
File renamed without changes.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

+13 -12
View File
@@ -5,6 +5,13 @@ import re
import sys
from math import ceil
"""
Generates src/dynarec/arm_printer.c
===
See src/dynarec/arm_instructions.txt (the input file) for the syntax documentation.
"""
# Helper class to avoid displaying '\x1b[' on errors
class string(str):
def __repr__(self):
@@ -172,13 +179,6 @@ def main(root, ver, __debug_forceAllDebugging=False):
- specifics is an array of arrays the same length as positions that contains a tuple (mask, correctBit)
that is at position positions[current_pos]
"""
if len(positions) != len(specifics):
fail(
AssertionError,
"generate_bin_tests requires the same length for positions ({}) and specifics ({})!".format(
len(positions), len(specifics)
)
)
if specifics == []:
append("if ((opcode & " + arr2hex(mask) + ") == " + arr2hex(correctBits) + ") {\n")
@@ -194,8 +194,9 @@ def main(root, ver, __debug_forceAllDebugging=False):
if any(map(lambda s: len(s) != l, specifics)):
fail(
AssertionError,
"generate_bin_tests requires the same length for positions ({}) and specifics ({})!".format(
len(positions), len(specifics)
"generate_bin_tests requires the same length for positions ({}) and each element "
"of the specifics array ({})!".format(
len(positions), [len(s) for s in specifics]
)
)
@@ -290,7 +291,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
# Custom ifs
# Also, requires only a single '='
if eq != "=":
fail(ValueError, "Too many '=' switches (!@ modifier)")
fail(ValueError, "Too many '=' switches (@@ modifier)")
# Extract the statements
statements = []
@@ -1653,7 +1654,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
# No C variable since we're invalidating!
# Now print the invalidation, numerote if debugging
# Now print the invalidation, number if debugging
if numberInvalids:
append("strcpy(ret, \"??? #" + str(invalidationCount) + "\");\n} else ")
invalidationCount = invalidationCount + 1
@@ -1963,12 +1964,12 @@ const char* arm_print(uint32_t opcode) {
"""}
for f in files_header:
# Save the string for the next iteration, writing was successful
with open(os.path.join(root, "src", "dynarec", f), 'w') as file:
file.write(header.format(version = ver))
file.write(files_header[f])
file.write(output)
file.write(files_guard[f])
# Save the string for the next iteration, writing was successful
with open(os.path.join(root, "src", "dynarec", "last_run.txt"), 'w') as file:
file.write('\n'.join(insts))
+301 -73
View File
@@ -3,6 +3,59 @@
import os
import sys
"""
Generates all files in src/wrapped/generated
===
TL;DR: Automagically creates type definitions (/.F.+/ functions/typedefs...).
All '//%' in the headers are used by the script.
Reads each lines of each "_private.h" headers (plus wrappedd3dadapter9_gen.h as a special case).
For each of them:
- If if starts with a #ifdef, #else, #ifndef, #endif, it memorizes which definition is required
- If it starts with a "GO", it will do multiple things:
- It memorizes the type used by the function (second macro argument)
- It memorizes the type it is mapped to, if needed (eg, iFEv is mapped to iFE: the second argument is dropped)
- It checks if the type given (both original and )
- If the signature contains a 'E', it will memorize the original function's signature:
- If it is the special file case, or if the line contains "//%%", it stops there.
- Otherwise, if it starts with "GOS":
- It will search for the special marker "//%".
That special marker is used to detect the following step:
- If the marker is followed by a registered structure ID (see later), it transforms the assembly function signature
into the original signature (eg, transforms pFEp into XFv if //%X was used)
- If the marker is followed by a '{', it will not attempt to alter the given signature, and instead use the
signature between '{' and '}'
- Otherwise, if the line contains '//%{', like before it will use the signature given and not the original one.
- Finally, if it still didn't stop, it will use the assembly signature (without the emulator).
- If the line starts with a '//%'
`gbl` contains the first list, `redirects` the second, `mytypedefs` the third.
`mystructs` and `mystructs_vals` constains data about the structures.
After sorting the data, it generates:
wrapper.c
---------
(Private) type definitions (/.F.+_t/)
Function definitions (/.F.+/ functions, that actually execute the function given as argument)
isSimpleWrapper definition
wrapper.h
---------
Generic "wrapper_t" type definition
Function declarations (/.F.+/ functions)
*types.h
--------
Local types definition, for the original signatures (eg, XFv for the earlier example)
The SUPER() macro definition, used to generate and initialize the `*_my_t` library structure
(TODO: also automate this declaration/definition? It would require more metadata,
and may break sometime in the future due to the system changing...)
"""
# Free values:
# AB F H J QR T XYZab gh jk mno qrst xyz
values = ['E', 'e', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'V', 'O', 'S', '2', 'P', 'G', 'N', 'M']
def splitchar(s):
try:
@@ -38,15 +91,26 @@ def main(root, defines, files, ver):
global values
# Initialize variables: gbl for all values, redirects for redirections
gbl = {}
redirects = {}
# mytypedefs is a list of all functions per "*FE*" types per filename, mystructs of structures per filename
gbl = {}
redirects = {}
mytypedefs = {}
mystructs = {}
mystructs_vals = {}
# First read the files inside the headers
for filepath in files:
# TODO: remove the special case...
for filepath in files + [os.path.join(root, "src", "wrapped", "wrappedd3dadapter9_gen.h")]:
filename = filepath.split("/")[-1]
dependants = []
with open(filepath, 'r') as file:
for line in file:
def fail(s, causedby=None):
if causedby:
raise NotImplementedError(s + " ({0}:{1})".format(filename, line[:-1])) from causedby
else:
raise NotImplementedError(s + " ({0}:{1})".format(filename, line[:-1]))
ln = line.strip()
# If the line is a `#' line (#ifdef LD80BITS/#ifndef LD80BITS/header)
if ln.startswith("#"):
@@ -58,6 +122,8 @@ def main(root, defines, files, ver):
continue #if !(defined(GO) && defined(GOM)...)
elif preproc_cmd.startswith("error"):
continue #error meh!
elif preproc_cmd.startswith("include"):
continue #inherit other library
elif preproc_cmd.startswith("endif"):
if dependants != []:
dependants.pop()
@@ -72,28 +138,36 @@ def main(root, defines, files, ver):
elif preproc_cmd.startswith("else"):
dependants[-1] = invert(dependants[-1])
else:
raise NotImplementedError("Unknown preprocessor directive: {0} ({1}:{2})".format(
preproc_cmd.split(" ")[0], filename, line[:-1]
))
fail("Unknown preprocessor directive: {0}".format(preproc_cmd.split(" ")[0]))
except KeyError as k:
raise NotImplementedError("Unknown key: {0} ({1}:{2})".format(
k.args[0], filename, line[:-1]
), k)
fail("Unknown key: {0}".format(k.args[0]), k)
# If the line is a `GO...' line (GO/GOM/GO2/...)...
elif ln.startswith("GO"):
# ... then look at the second parameter of the line
gotype = ln.split("(")[0].strip()
funname = ln.split(",")[0].split("(")[1].strip()
ln = ln.split(",")[1].split(")")[0].strip()
if ln[1] not in ["F"]:
raise NotImplementedError("Bad middle letter {0} ({1}:{2})".format(ln[1], filename, line[:-1]))
if len(ln) < 3:
fail("Type {0} too short".format(ln))
if "E" in ln:
if ("E" in ln[:2]) or ("E" in ln[3:]):
fail("emu64_t* not as the first parameter")
if len(ln) < 4:
fail("Type {0} too short".format(ln))
if ln[0] not in values:
fail("Invalid return type {0}".format(ln[0]))
if ln[1] != "F":
fail("Bad middle letter {0}".format(ln[1]))
if any(c not in values for c in ln[2:]) or (('v' in ln[2:]) and (len(ln) > 3)):
old = ln
# This needs more work
acceptables = ['v', '0', '1'] + values
if any(c not in acceptables for c in ln[2:]):
raise NotImplementedError("{0} ({1}:{2})".format(ln[2:], filename, line[:-1]))
fail("Invalid type {0}".format(ln[2:]))
# Ok, this is acceptable: there is 0, 1 and/or void
ln = (ln
ln = ln[:2] + (ln[2:]
.replace("v", "") # void -> nothing
.replace("0", "p") # 0 -> pointer
.replace("1", "i")) # 1 -> integer
@@ -103,6 +177,111 @@ def main(root, defines, files, ver):
gbl.setdefault(" && ".join(dependants), [])
if ln not in gbl[" && ".join(dependants)]:
gbl[" && ".join(dependants)].append(ln)
if filename == "wrappedd3dadapter9_gen.h":
pass # Special case...
elif ln[2] == 'E':
if "//%%" in line:
# Do not dlsym functions containing "//%%" as metadata
pass
elif gotype == "GOS":
# Scan the rest of the line to extract the return structure ID
if filename[:-10] not in mystructs:
fail("No structure info in the file")
if "//%" not in line:
fail("Invalid GOS (missing structure ID info)")
if ln[0] != 'p':
fail("Invalid GOS return type ('{0}' and not 'p')".format(ln[0]))
#if (ln[2] != 'p') and ((ln[2] != 'E') or (ln[3] != 'p')): -> only allow pFEp for now
# fail("Invalid GOS first parameter ('{0}' and not 'p' or 'Ep')".format(ln[2:4]))
if (ln[2] != 'E') or (ln[3] != 'p'):
fail("Invalid GOS first parameter ('{0}' and not 'Ep')".format(ln[2:4]))
sid = line.split("//%")[1].split(" ")[0].strip()
if sid[0] == '{':
# Change type completely, not just the return type...
if sid[-1] != '}':
fail("Invalid type (EOL or space met, expected '}')")
if len(sid) < 5:
fail("Invalid type (Type {0} too short)".format(sid[1:-1]))
if sid[2] != "F":
fail("Invalid type (Bad middle letter {0})".format(sid[2]))
inval_char = lambda c:\
(c not in mystructs[filename[:-10]]) and (c not in acceptables) \
or (c == 'E') or (c == 'e')
if inval_char(sid[1]):
fail("Invalid type (Invalid return type {0})".format(sid[1]))
if any(map(inval_char, sid[3:-1])):
fail("Invalid type (Invalid type {0})".format(sid[3:-1]))
mytypedefs.setdefault(filename[:-10], {})
mytypedefs[filename[:-10]].setdefault(sid[1:-1], [])
mytypedefs[filename[:-10]][sid[1:-1]].append((0, funname))
else:
if len(sid) != 1:
fail("Invalid structure ID {0} (length is too big)".format(sid))
if sid not in mystructs[filename[:-10]]:
fail("Invalid structure ID {0} (unknown ID)".format(sid))
mytypedefs.setdefault(filename[:-10], {})
mytypedefs[filename[:-10]].setdefault(sid + "F" + ln[4:], [])
mytypedefs[filename[:-10]][sid + "F" + ln[4:]].append((1, funname))
elif "//%{" in line:
# Change type completely...
# ...Maybe?
if filename[:-10] not in mystructs:
fail("No structure info in the file")
newtype = line.split("//%")[1].split(" ")[0].strip()
if newtype[-1] != '}':
fail("Invalid type (EOL or space met, expected '}')")
if len(newtype) < 5:
fail("Invalid type (Type {0} too short)".format(newtype[1:-1]))
if newtype[2] != "F":
fail("Invalid type (Bad middle letter {0})".format(newtype[2]))
inval_char = lambda c:\
(c not in mystructs[filename[:-10]]) and (c not in acceptables) \
or (c == 'E') or (c == 'e')
if inval_char(newtype[1]):
fail("Invalid type (Invalid return type {0})".format(newtype[1]))
if any(map(inval_char, newtype[3:-1])):
fail("Invalid type (Invalid type {0})".format(newtype[3:-1]))
mytypedefs.setdefault(filename[:-10], {})
mytypedefs[filename[:-10]].setdefault(newtype[1:-1], [])
mytypedefs[filename[:-10]][newtype[1:-1]].append((2, funname))
else:
# filename isn't stored with the '_private.h' part
if not filename.endswith('_private.h'):
fail("??? {0}".format(filename))
if len(ln) > 3:
ln = ln[:2] + ln[3:]
else:
ln = ln[:2] + "v"
mytypedefs.setdefault(filename[:-10], {})
mytypedefs[filename[:-10]].setdefault(ln, [])
mytypedefs[filename[:-10]][ln].append((3, funname))
elif ln.startswith("//%S"):
# Extract a structure ID-name pair
data = [s for s in map(lambda s: s.strip(), ln.split(" ")) if s != ""]
if len(data) != 3:
fail("Too much data ({0})".format(len(data)))
if not filename.endswith('_private.h'):
fail("??? {0}".format(filename))
if (data[0] != "//%S") or (len(data[1]) != 1):
fail("Invalid structure data {0} {1}".format(data[0], data[1]))
if data[1] in values:
fail("{0} cannot be used as a structure type".format(data[1]))
mystructs.setdefault(filename[:-10], {})
if data[1] in mystructs[filename[:-10]]:
fail("Duplicate structure ID {0} ({1}/{2})".format(data[1], mystructs[filename[:-10]], data[2]))
mystructs[filename[:-10]][data[1]] = data[2]
mystructs_vals.setdefault(filename[:-10], [])
mystructs_vals[filename[:-10]].append(data[1])
if ("" not in gbl) or ("" not in redirects):
print("\033[1;31mThere is suspiciously not many types...\033[m")
print("Check the CMakeLists.txt file. If you are SURE there is nothing wrong"
" (as a random example, `set()` resets the variable...), then comment out the following return.")
print("(Also, the program WILL crash later if you proceed.)")
return 2 # Check what you did, not proceeding
gbl_vals = {}
for k in gbl:
@@ -182,8 +361,17 @@ def main(root, defines, files, ver):
gbl[k].sort(key=lambda v: splitchar(v))
values = values + ['0', '1']
for k in redirects:
redirects[k].sort(key=lambda v: splitchar(v[0]) + [0] + splitchar(v[1]))
redirects[k].sort(key=lambda v: splitchar(v[0]) + [-1] + splitchar(v[1]))
values = values[:-2]
mytypedefs_vals = {}
for fn in mytypedefs:
if fn in mystructs:
values = values + list(mystructs[fn].keys())
mytypedefs_vals[fn] = sorted(mytypedefs[fn].keys(), key=lambda v: splitchar(v))
if fn in mystructs:
values = values[:-len(mystructs[fn])]
for v in mytypedefs_vals[fn]:
mytypedefs[fn][v].sort()
# Check if there was any new functions
functions_list = ""
@@ -193,6 +381,15 @@ def main(root, defines, files, ver):
for k in ["()"] + redirects_idxs:
for v in redirects[k]:
functions_list = functions_list + "#" + k + " " + v[0] + " -> " + v[1] + "\n"
for fn in sorted(mystructs.keys()):
for t in mystructs_vals[fn]:
# Structure Definition
functions_list = functions_list + fn + "/Sd" + t + mystructs[fn][t] + "\n"
for fn in sorted(mytypedefs.keys()):
for t in mytypedefs_vals[fn]:
# Structure Usage
for tnum, f in mytypedefs[fn][t]:
functions_list = functions_list + fn + "/Su" + t + str(tnum) + f + "\n"
# functions_list is a unique string, compare it with the last run
try:
@@ -203,16 +400,16 @@ def main(root, defines, files, ver):
# Mark as OK for CMake
with open(os.path.join(root, "src", "wrapped", "generated", "functions_list.txt"), 'w') as file:
file.write(functions_list)
#return 0
return 0
except IOError:
# The file does not exist yet, first run
pass
# Now the files rebuilding part
# File headers and guards
files_headers = {
# Files header and guard
files_header = {
"wrapper.c": """/*****************************************************************
* File automatically generated by rebuild_wrappers.py (v%s)
* File automatically generated by rebuild_wrappers.py (v{version})
*****************************************************************/
#include <stdio.h>
#include <stdlib.h>
@@ -224,23 +421,23 @@ def main(root, defines, files, ver):
#include "regs.h"
#include "x86emu.h"
typedef union ui64_s {
typedef union ui64_s {lbr}
int64_t i;
uint64_t u;
uint32_t d[2];
} ui64_t;
{rbr} ui64_t;
typedef struct _2uint_struct_s {
typedef struct _2uint_struct_s {lbr}
uint32_t a;
uint32_t b;
} _2uint_struct_t;
{rbr} _2uint_struct_t;
extern void* my__IO_2_1_stderr_;
extern void* my__IO_2_1_stdin_ ;
extern void* my__IO_2_1_stdout_;
static void* io_convert(void* v)
{
{lbr}
if(!v)
return v;
if(v==my__IO_2_1_stderr_)
@@ -250,31 +447,31 @@ static void* io_convert(void* v)
if(v==my__IO_2_1_stdout_)
return stdout;
return v;
}
{rbr}
typedef struct my_GValue_s
{
{lbr}
int g_type;
union {
union {lbr}
int v_int;
int64_t v_int64;
uint64_t v_uint64;
float v_float;
double v_double;
void* v_pointer;
} data[2];
} my_GValue_t;
{rbr} data[2];
{rbr} my_GValue_t;
static void alignGValue(my_GValue_t* v, void* value)
{
{lbr}
v->g_type = *(int*)value;
memcpy(v->data, value+4, 2*sizeof(double));
}
{rbr}
static void unalignGValue(void* value, my_GValue_t* v)
{
{lbr}
*(int*)value = v->g_type;
memcpy(value+4, v->data, 2*sizeof(double));
}
{rbr}
void* VulkanFromx86(void* src, void** save);
void VulkanTox86(void* src, void* save);
@@ -282,9 +479,10 @@ void VulkanTox86(void* src, void* save);
#define ST0val ST0.d
int of_convert(int);
""",
"wrapper.h": """/*****************************************************************
* File automatically generated by rebuild_wrappers.py (v%s)
* File automatically generated by rebuild_wrappers.py (v{version})
*****************************************************************/
#ifndef __WRAPPER_H_
#define __WRAPPER_H_
@@ -315,57 +513,49 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
// N = ... automatically sending 1 arg
// M = ... automatically sending 2 args
""",
"fntypes.h": """/*****************************************************************
* File automatically generated by rebuild_wrappers.py (v{version})
*****************************************************************/
#ifndef __{filename}TYPES_H_
#define __{filename}TYPES_H_
#ifndef LIBNAME
#error You should only #include this file inside a wrapped*.c file
#endif
#ifndef ADDED_FUNCTIONS
#define ADDED_FUNCTIONS()
#endif
"""
}
files_guards = {"wrapper.c": """""",
files_guard = {"wrapper.c": """""",
"wrapper.h": """
#endif //__WRAPPER_H_
#endif // __WRAPPER_H_
""",
"fntypes.h": """
#endif // __{filename}TYPES_H_
"""
}
# Rewrite the wrapper.h file:
with open(os.path.join(root, "src", "wrapped", "generated", "wrapper.h"), 'w') as file:
file.write(files_headers["wrapper.h"] % ver)
for v in gbl["()"]:
file.write("void " + v + "(x86emu_t *emu, uintptr_t fnc);\n")
for k in gbl_idxs:
file.write("\n#if " + k + "\n")
for v in gbl[k]:
file.write("void " + v + "(x86emu_t *emu, uintptr_t fnc);\n")
file.write("#endif\n")
file.write("\n")
for v in redirects["()"]:
file.write("void " + v[0] + "(x86emu_t *emu, uintptr_t fnc);\n")
for k in redirects_idxs:
file.write("\n#if " + k + "\n")
for v in redirects[k]:
file.write("void " + v[0] + "(x86emu_t *emu, uintptr_t fnc);\n")
file.write("#endif\n")
file.write(files_guards["wrapper.h"])
# E e v c w i I C W u U f d D K l L p V O S 2 P G N M
tdtypes = ["x86emu_t*", "x86emu_t**", "void", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t", "float", "double", "long double", "double", "intptr_t", "uintptr_t", "void*", "void*", "int32_t", "void*", "_2uint_struct_t", "void*", "void*", "...", "..."]
if len(values) != len(tdtypes):
raise NotImplementedError("len(values) = {lenval} != len(tdtypes) = {lentypes}".format(lenval=len(values), lentypes=len(tdtypes)))
def generate_typedefs(arr, file):
for v in arr:
file.write("typedef " + tdtypes[values.index(v[0])] + " (*" + v + "_t)"
+ "(" + ', '.join(tdtypes[values.index(t)] for t in v[2:]) + ");\n")
# Rewrite the wrapper.c file:
with open(os.path.join(root, "src", "wrapped", "generated", "wrapper.c"), 'w') as file:
file.write(files_headers["wrapper.c"] % ver)
file.write(files_header["wrapper.c"].format(lbr="{", rbr="}", version=ver))
# First part: typedefs
for v in gbl["()"]:
# E e v c w i I C W u U f d D K l L p V O S 2 P G N M
types = ["x86emu_t*", "x86emu_t**", "void", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t", "float", "double", "long double", "double", "intptr_t", "uintptr_t", "void*", "void*", "int32_t", "void*", "_2uint_struct_t", "void*", "void*", "...", "..."]
if len(values) != len(types):
raise NotImplementedError("len(values) = {lenval} != len(types) = {lentypes}".format(lenval=len(values), lentypes=len(types)))
file.write("typedef " + types[values.index(v[0])] + " (*" + v + "_t)"
+ "(" + ', '.join(types[values.index(t)] for t in v[2:]) + ");\n")
generate_typedefs(gbl["()"], file)
for k in gbl_idxs:
file.write("\n#if " + k + "\n")
for v in gbl[k]:
# E e v c w i I C W u U f d D K l L p V O S 2 P G N M
types = ["x86emu_t*", "x86emu_t**", "void", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t", "float", "double", "long double", "double", "intptr_t", "uintptr_t", "void*", "void*", "int32_t", "void*", "_2uint_struct_t", "void*", "void*", "...", "..."]
if len(values) != len(types):
raise NotImplementedError("len(values) = {lenval} != len(types) = {lentypes}".format(lenval=len(values), lentypes=len(types)))
file.write("typedef " + types[values.index(v[0])] + " (*" + v + "_t)"
+ "(" + ', '.join(types[values.index(t)] for t in v[2:]) + ");\n")
generate_typedefs(gbl[k], file)
file.write("#endif\n")
file.write("\n")
@@ -387,7 +577,7 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
"*(uint64_t*)(R_ESP + {p}), ", # U
"*(float*)(R_ESP + {p}), ", # f
"*(double*)(R_ESP + {p}), ", # d
"*(long double*)(R_ESP + {p}), ", # D
"LD2localLD((void*)(R_ESP + {p})), ", # D
"FromLD((void*)(R_ESP + {p})), ", # K
"*(intptr_t*)(R_ESP + {p}), ", # l
"*(uintptr_t*)(R_ESP + {p}), ", # L
@@ -493,7 +683,45 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
function_writer(file, v[0], v[1] + "_t", v[0][0], v[0][2:])
file.write("#endif\n")
file.write(files_guards["wrapper.c"])
file.write(files_guard["wrapper.c"].format(lbr="{", rbr="}", version=ver))
# Rewrite the wrapper.h file:
with open(os.path.join(root, "src", "wrapped", "generated", "wrapper.h"), 'w') as file:
file.write(files_header["wrapper.h"].format(lbr="{", rbr="}", version=ver))
for v in gbl["()"]:
file.write("void " + v + "(x86emu_t *emu, uintptr_t fnc);\n")
for k in gbl_idxs:
file.write("\n#if " + k + "\n")
for v in gbl[k]:
file.write("void " + v + "(x86emu_t *emu, uintptr_t fnc);\n")
file.write("#endif\n")
file.write("\n")
for v in redirects["()"]:
file.write("void " + v[0] + "(x86emu_t *emu, uintptr_t fnc);\n")
for k in redirects_idxs:
file.write("\n#if " + k + "\n")
for v in redirects[k]:
file.write("void " + v[0] + "(x86emu_t *emu, uintptr_t fnc);\n")
file.write("#endif\n")
file.write(files_guard["wrapper.h"].format(lbr="{", rbr="}", version=ver))
for fn in mytypedefs:
with open(os.path.join(root, "src", "wrapped", "generated", fn + "types.h"), 'w') as file:
file.write(files_header["fntypes.h"].format(lbr="{", rbr="}", version=ver, filename=fn))
if fn in mystructs:
values = values + mystructs_vals[fn]
tdtypes = tdtypes + [mystructs[fn][k] for k in mystructs_vals[fn]]
generate_typedefs(mytypedefs_vals[fn], file)
if fn in mystructs:
values = values[:-len(mystructs_vals[fn])]
tdtypes = tdtypes[:-len(mystructs_vals[fn])]
file.write("\n#define SUPER() ADDED_FUNCTIONS()")
for v in mytypedefs_vals[fn]:
for t, f in mytypedefs[fn][v]:
assert(t in [0, 1, 2, 3])
file.write(" \\\n\tGO({0}, {1}_t)".format(f, v))
file.write("\n")
file.write(files_guard["fntypes.h"].format(lbr="{", rbr="}", version=ver, filename=fn))
# Save the string for the next iteration, writing was successful
with open(os.path.join(root, "src", "wrapped", "generated", "functions_list.txt"), 'w') as file:
+7 -1
View File
@@ -32,17 +32,23 @@ 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 )
# now compare the output with the reference
execute_process(
COMMAND ${CMAKE_COMMAND} -E compare_files ${TEST_OUTPUT} ${TEST_REFERENCE}
COMMAND "${CMAKE_COMMAND}" -E compare_files "${TEST_OUTPUT}" "${TEST_REFERENCE}"
RESULT_VARIABLE TEST_RESULT
)
# 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 )
+80 -112
View File
@@ -27,71 +27,6 @@
#endif
#ifdef DYNAREC
// Remove the Write flag from an adress range, so DB can be executed
// no log, as it can be executed inside a signal handler
void protectDB(uintptr_t addr, uintptr_t size)
{
uintptr_t idx = (addr>>DYNAMAP_SHIFT);
uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
uint32_t prot;
do {
prot=arm_lock_read_d(&my_context->memprot[i]);
if(!prot)
prot = PROT_READ | PROT_WRITE; // comes from malloc & co, so should not be able to execute
} while(arm_lock_write_d(&my_context->memprot[i], prot|PROT_DYNAREC));
if(!(prot&PROT_DYNAREC))
mprotect((void*)(i<<DYNAMAP_SHIFT), 1<<DYNAMAP_SHIFT, prot&~PROT_WRITE);
}
}
// 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, uintptr_t size)
{
uintptr_t idx = (addr>>DYNAMAP_SHIFT);
uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
uint32_t prot;
do {
prot=arm_lock_read_d(&my_context->memprot[i]);
} while(arm_lock_write_d(&my_context->memprot[i], prot&~PROT_DYNAREC));
if(prot&PROT_DYNAREC) {
mprotect((void*)(i<<DYNAMAP_SHIFT), 1<<DYNAMAP_SHIFT, prot&~PROT_DYNAREC);
cleanDBFromAddressRange((i<<DYNAMAP_SHIFT), 1<<DYNAMAP_SHIFT, 0);
}
}
}
#endif
void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
{
const uintptr_t idx = (addr>>DYNAMAP_SHIFT);
const uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
#ifdef DYNAREC
uint32_t dyn;
do {
dyn=arm_lock_read_d(&my_context->memprot[i])&PROT_DYNAREC;
} while(arm_lock_write_d(&my_context->memprot[i], prot|dyn));
if(dyn && (prot&PROT_WRITE)) // need to remove the write protection from this block
mprotect((void*)(i<<DYNAMAP_SHIFT), 1<<DYNAMAP_SHIFT, prot&~PROT_WRITE);
#else
uint32_t dyn=(my_context->memprot[i]&PROT_DYNAREC);
if(dyn && (prot&PROT_WRITE)) // need to remove the write protection from this block
mprotect((void*)(i<<DYNAMAP_SHIFT), 1<<DYNAMAP_SHIFT, prot&~PROT_WRITE);
my_context->memprot[i] = prot|dyn;
#endif
}
}
uint32_t getProtection(uintptr_t addr)
{
const uintptr_t idx = (addr>>DYNAMAP_SHIFT);
return my_context->memprot[idx];
}
EXPORTDYN
void initAllHelpers(box86context_t* context)
@@ -102,10 +37,6 @@ void initAllHelpers(box86context_t* context)
my_context = context;
init_pthread_helper();
init_signal_helper(context);
#ifdef DYNAREC
if(box86_dynarec)
DynablockEmuMarker(context);
#endif
inited = 1;
}
@@ -145,6 +76,76 @@ void free_tlsdatasize(void* p)
free(p);
}
int unlockMutex()
{
int ret = unlockCustommemMutex();
int i;
#define GO(A, B) \
i = checkUnlockMutex(&A); \
if(i) { \
ret|=(1<<B); \
}
GO(my_context->mutex_once, 5)
GO(my_context->mutex_once2, 6)
GO(my_context->mutex_trace, 7)
#ifdef DYNAREC
GO(my_context->mutex_dyndump, 8)
#else
GO(my_context->mutex_lock, 8)
#endif
GO(my_context->mutex_tls, 9)
GO(my_context->mutex_thread, 10)
#undef GO
return ret;
}
void relockMutex(int locks)
{
relockCustommemMutex(locks);
#define GO(A, B) \
if(locks&(1<<B)) \
pthread_mutex_lock(&A); \
GO(my_context->mutex_once, 5)
GO(my_context->mutex_once2, 6)
GO(my_context->mutex_trace, 7)
#ifdef DYNAREC
GO(my_context->mutex_dyndump, 8)
#else
GO(my_context->mutex_lock, 8)
#endif
GO(my_context->mutex_tls, 9)
GO(my_context->mutex_thread, 10)
#undef GO
}
static void init_mutexes(box86context_t* context)
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
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
pthread_mutex_init(&context->mutex_dyndump, &attr);
#endif
pthread_mutex_init(&context->mutex_tls, &attr);
pthread_mutex_init(&context->mutex_thread, &attr);
pthread_mutexattr_destroy(&attr);
}
static void atfork_child_box64context(void)
{
// (re)init mutex if it was lock before the fork
init_mutexes(my_context);
}
EXPORTDYN
box86context_t *NewBox86Context(int argc)
{
@@ -166,8 +167,6 @@ box86context_t *NewBox86Context(int argc)
init_custommem_helper(context);
context->memprot = (uint32_t*)calloc(DYNAMAP_SIZE, sizeof(uint32_t));
context->maplib = NewLibrarian(context, 1);
context->local_maplib = NewLibrarian(context, 1);
context->system = NewBridge();
@@ -183,22 +182,15 @@ box86context_t *NewBox86Context(int argc)
context->argc = argc;
context->argv = (char**)calloc(context->argc+1, sizeof(char*));
pthread_mutex_init(&context->mutex_once, NULL);
pthread_mutex_init(&context->mutex_once2, NULL);
pthread_mutex_init(&context->mutex_trace, NULL);
#ifndef DYNAREC
pthread_mutex_init(&context->mutex_lock, NULL);
#else
pthread_mutex_init(&context->mutex_dyndump, NULL);
#endif
pthread_mutex_init(&context->mutex_tls, NULL);
pthread_mutex_init(&context->mutex_thread, NULL);
init_mutexes(context);
pthread_atfork(NULL, NULL, atfork_child_box64context);
pthread_key_create(&context->tlskey, free_tlsdatasize);
InitFTSMap(context);
for (int i=0; i<4; ++i) context->canary[i] = 1 + getrand(255);
context->canary[getrand(4)] = 0;
context->canary[/*getrand(4)*/0] = 0;
printf_log(LOG_DEBUG, "Setting up canary (for Stack protector) at GS:0x14, value:%08X\n", *(uint32_t*)context->canary);
initAllHelpers(context);
@@ -221,6 +213,11 @@ void FreeBox86Context(box86context_t** context)
box86context_t* ctx = *context; // local copy to do the cleanning
if(ctx->local_maplib)
FreeLibrarian(&ctx->local_maplib, NULL);
if(ctx->maplib)
FreeLibrarian(&ctx->maplib, NULL);
for(int i=0; i<ctx->elfsize; ++i) {
FreeElfHeader(&ctx->elfs[i]);
}
@@ -228,11 +225,6 @@ void FreeBox86Context(box86context_t** context)
FreeFTSMap(ctx);
if(ctx->maplib)
FreeLibrarian(&ctx->maplib);
if(ctx->local_maplib)
FreeLibrarian(&ctx->local_maplib);
FreeCollection(&ctx->box86_path);
FreeCollection(&ctx->box86_ld_lib);
FreeCollection(&ctx->box86_emulated_libs);
@@ -273,7 +265,7 @@ void FreeBox86Context(box86context_t** context)
FreeDLPrivate(&ctx->dlprivate);
free(ctx->stack);
// free(ctx->stack); // don't free the stack, it's owned by main emu!
free(ctx->fullpath);
free(ctx->box86path);
@@ -310,8 +302,6 @@ void FreeBox86Context(box86context_t** context)
#endif
pthread_mutex_destroy(&ctx->mutex_tls);
pthread_mutex_destroy(&ctx->mutex_thread);
free(ctx->memprot);
ctx->memprot = NULL;
free_neededlib(&ctx->neededlibs);
@@ -351,25 +341,3 @@ int AddTLSPartition(box86context_t* context, int tlssize) {
return -context->tlssize; // negative offset
}
void add_neededlib(needed_libs_t* needed, library_t* lib)
{
if(!needed)
return;
if(needed->size == needed->cap) {
needed->cap += 8;
needed->libs = (library_t**)realloc(needed->libs, needed->cap*sizeof(library_t*));
}
needed->libs[needed->size++] = lib;
}
void free_neededlib(needed_libs_t* needed)
{
if(!needed)
return;
needed->cap = 0;
needed->size = 0;
if(needed->libs)
free(needed->libs);
needed->libs = NULL;
}
+1 -1
View File
@@ -3,6 +3,6 @@
#define BOX86_MAJOR 0
#define BOX86_MINOR 2
#define BOX86_REVISION 0
#define BOX86_REVISION 2
#endif //__BOX86_VERSION_H_
+283 -39
View File
@@ -21,20 +21,28 @@
#include "signals.h"
#include <sys/mman.h>
#include "custommem.h"
#include "threads.h"
#ifdef DYNAREC
#include "dynablock.h"
#include "dynarec/arm_lock_helper.h"
#include "khash.h"
#define USE_MMAP
// init inside dynablocks.c
KHASH_MAP_INIT_INT(dynablocks, dynablock_t*)
static dynablocklist_t** dynmap; // 4G of memory mapped by 4K block
static dynablocklist_t* dynmap[DYNAMAP_SIZE]; // 4G of memory mapped by 4K block
static pthread_mutex_t mutex_mmap;
static mmaplist_t *mmaplist;
static int mmapsize;
static kh_dynablocks_t *dblist_oversized; // store the list of oversized dynablocks (normal sized are inside mmaplist)
static uintptr_t *box86_jumptable[JMPTABL_SIZE];
static uintptr_t box86_jmptbl_default[1<<JMPTABL_SHIFT];
#endif
#define MEMPROT_SHIFT 12
#define MEMPROT_SIZE (1<<(32-MEMPROT_SHIFT))
static uint8_t memprot[MEMPROT_SIZE] = {0}; // protection flags by 4K block
static int inited = 0;
typedef struct blocklist_s {
void* block;
@@ -44,7 +52,7 @@ typedef struct blocklist_s {
#define MMAPSIZE (256*1024) // allocate 256kb sized blocks
static pthread_mutex_t mutex_blocks = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t mutex_blocks;
static int n_blocks = 0; // number of blocks for custom malloc
static blocklist_t* p_blocks = NULL; // actual blocks for custom malloc
@@ -61,14 +69,14 @@ typedef struct blockmark_s {
} blockmark_t;
// get first subblock free in block, stating at start (from block). return NULL if no block, else first subblock free (mark included), filling size
// get first subblock free in block. Return NULL if no block, else first subblock free (mark included), filling size
static void* getFirstBlock(void* block, int maxsize, int* size)
{
// get start of block
blockmark_t *m = (blockmark_t*)block;
while(m->next.x32) { // while there is a subblock
if(!m->next.fill && m->next.size>=maxsize+sizeof(blockmark_t)) {
*size = m->next.size;
*size = m->next.size-sizeof(blockmark_t);
return m;
}
m = (blockmark_t*)((uintptr_t)m + m->next.size);
@@ -80,17 +88,17 @@ static void* getFirstBlock(void* block, int maxsize, int* size)
static int getMaxFreeBlock(void* block, size_t block_size)
{
// get start of block
blockmark_t *m = (blockmark_t*)((uintptr_t)block+block_size-sizeof(blockmark_t)); // styart with the end
blockmark_t *m = (blockmark_t*)((uintptr_t)block+block_size-sizeof(blockmark_t)); // start with the end
int maxsize = 0;
while(m->prev.x32) { // while there is a subblock
if(!m->prev.fill && m->prev.size>maxsize) {
maxsize = m->prev.size;
if((uintptr_t)block+maxsize>(uintptr_t)m)
return maxsize; // no block large enough left...
return (maxsize>=sizeof(blockmark_t))?(maxsize-sizeof(blockmark_t)):0; // no block large enough left...
}
m = (blockmark_t*)((uintptr_t)m - m->prev.size);
}
return maxsize;
return (maxsize>=sizeof(blockmark_t))?(maxsize-sizeof(blockmark_t)):0;
}
static void* allocBlock(void* block, void *sub, int size)
@@ -196,7 +204,12 @@ void* customMalloc(size_t size)
size_t allocsize = MMAPSIZE;
if(size+2*sizeof(blockmark_t)>allocsize)
allocsize = size+2*sizeof(blockmark_t);
#ifdef USE_MMAP
void* p = mmap(NULL, allocsize, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
memset(p, 0, allocsize);
#else
void* p = calloc(1, allocsize);
#endif
p_blocks[i].block = p;
p_blocks[i].size = allocsize;
// setup marks
@@ -276,6 +289,7 @@ typedef struct mmaplist_s {
int maxfree;
size_t size;
kh_dynablocks_t* dblist;
uint8_t* helper;
} mmaplist_t;
uintptr_t FindFreeDynarecMap(dynablock_t* db, int size)
@@ -297,8 +311,10 @@ uintptr_t FindFreeDynarecMap(dynablock_t* db, int size)
}
khint_t k;
int r;
k = kh_put(dynablocks, blocks, (uintptr_t)db, &r);
k = kh_put(dynablocks, blocks, (uintptr_t)ret, &r);
kh_value(blocks, k) = db;
for(int j=0; j<size; ++j)
mmaplist[i].helper[(uintptr_t)ret-(uintptr_t)mmaplist[i].block+j] = (j<256)?j:255;
return ret;
}
}
@@ -311,6 +327,7 @@ uintptr_t AddNewDynarecMap(dynablock_t* db, int size)
int i = mmapsize++; // yeah, useful post incrementation
dynarec_log(LOG_DEBUG, "Ask for DynaRec Block Alloc #%d\n", mmapsize);
mmaplist = (mmaplist_t*)realloc(mmaplist, mmapsize*sizeof(mmaplist_t));
#ifndef USE_MMAP
void *p = NULL;
if(posix_memalign(&p, box86_pagesize, MMAPSIZE)) {
dynarec_log(LOG_INFO, "Cannot create memory map of %d byte for dynarec block #%d\n", MMAPSIZE, i);
@@ -318,10 +335,19 @@ uintptr_t AddNewDynarecMap(dynablock_t* db, int size)
return 0;
}
mprotect(p, MMAPSIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
updateProtection((uintptr_t)p, MMAPSIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
#else
void* p = mmap(NULL, MMAPSIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if(p==(void*)-1) {
dynarec_log(LOG_INFO, "Cannot create memory map of %d byte for dynarec block #%d\n", MMAPSIZE, i);
--mmapsize;
return 0;
}
#endif
setProtection((uintptr_t)p, MMAPSIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
mmaplist[i].block = p;
mmaplist[i].size = MMAPSIZE;
mmaplist[i].helper = (uint8_t*)calloc(1, MMAPSIZE);
// setup marks
blockmark_t* m = (blockmark_t*)p;
m->prev.x32 = 0;
@@ -338,8 +364,10 @@ uintptr_t AddNewDynarecMap(dynablock_t* db, int size)
kh_resize(dynablocks, blocks, 64);
khint_t k;
int ret;
k = kh_put(dynablocks, blocks, (uintptr_t)db, &ret);
k = kh_put(dynablocks, blocks, (uintptr_t)sub, &ret);
kh_value(blocks, k) = db;
for(int j=0; j<size; ++j)
mmaplist[i].helper[(uintptr_t)sub-(uintptr_t)mmaplist[i].block + j] = (j<256)?j:255;
return sub;
}
@@ -355,9 +383,11 @@ void ActuallyFreeDynarecMap(dynablock_t* db, uintptr_t addr, int size)
mmaplist[i].maxfree = getMaxFreeBlock(mmaplist[i].block, mmaplist[i].size);
kh_dynablocks_t *blocks = mmaplist[i].dblist;
if(blocks) {
khint_t k = kh_get(dynablocks, blocks, (uintptr_t)db);
khint_t k = kh_get(dynablocks, blocks, (uintptr_t)sub);
if(k!=kh_end(blocks))
kh_del(dynablocks, blocks, k);
for(int j=0; j<size; ++j)
mmaplist[i].helper[(uintptr_t)sub-(uintptr_t)mmaplist[i].block+j] = 0;
}
return;
}
@@ -371,8 +401,18 @@ dynablock_t* FindDynablockFromNativeAddress(void* addr)
// look in actual list
for(int i=0; i<mmapsize; ++i) {
if ((uintptr_t)addr>=(uintptr_t)mmaplist[i].block
&& ((uintptr_t)addr<(uintptr_t)mmaplist[i].block+mmaplist[i].size))
return FindDynablockDynablocklist(addr, mmaplist[i].dblist);
&& ((uintptr_t)addr<(uintptr_t)mmaplist[i].block+mmaplist[i].size)) {
if(!mmaplist[i].helper)
return FindDynablockDynablocklist(addr, mmaplist[i].dblist);
else {
uintptr_t p = (uintptr_t)addr - (uintptr_t)mmaplist[i].block;
while(mmaplist[i].helper[p]) p -= mmaplist[i].helper[p];
khint_t k = kh_get(dynablocks, mmaplist[i].dblist, (uintptr_t)mmaplist[i].block + p);
if(k!=kh_end(mmaplist[i].dblist))
return kh_value(mmaplist[i].dblist, k);
return NULL;
}
}
}
// look in oversized
return FindDynablockDynablocklist(addr, dblist_oversized);
@@ -383,13 +423,22 @@ uintptr_t AllocDynarecMap(dynablock_t* db, int size)
if(!size)
return 0;
if(size>MMAPSIZE-2*sizeof(blockmark_t)) {
#ifndef USE_MMAP
pthread_mutex_lock(&mutex_mmap);
void *p = NULL;
if(posix_memalign(&p, box86_pagesize, size)) {
dynarec_log(LOG_INFO, "Cannot create dynamic map of %d bytes\n", size);
return 0;
}
mprotect(p, size, PROT_READ | PROT_WRITE | PROT_EXEC);
updateProtection((uintptr_t)p, size, PROT_READ | PROT_WRITE | PROT_EXEC);
#else
void* p = mmap(NULL, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
if(p==(void*)-1) {
dynarec_log(LOG_INFO, "Cannot create dynamic map of %d bytes\n", size);
return 0;
}
#endif
setProtection((uintptr_t)p, size, PROT_READ | PROT_WRITE | PROT_EXEC);
kh_dynablocks_t *blocks = dblist_oversized;
if(!blocks) {
blocks = dblist_oversized = kh_init(dynablocks);
@@ -397,16 +446,13 @@ uintptr_t AllocDynarecMap(dynablock_t* db, int size)
}
khint_t k;
int ret;
k = kh_put(dynablocks, blocks, (uintptr_t)db, &ret);
k = kh_put(dynablocks, blocks, (uintptr_t)p, &ret);
kh_value(blocks, k) = db;
pthread_mutex_unlock(&mutex_mmap);
return (uintptr_t)p;
}
if(pthread_mutex_trylock(&mutex_mmap)) {
sched_yield(); // give it a chance
if(pthread_mutex_trylock(&mutex_mmap))
return 0; // cannot lock, baillout
}
pthread_mutex_lock(&mutex_mmap);
uintptr_t ret = FindFreeDynarecMap(db, size);
if(!ret)
@@ -419,14 +465,22 @@ uintptr_t AllocDynarecMap(dynablock_t* db, int size)
void FreeDynarecMap(dynablock_t* db, uintptr_t addr, uint32_t size)
{
if(size>MMAPSIZE) {
if(!addr || !size)
return;
if(size>MMAPSIZE-2*sizeof(blockmark_t)) {
pthread_mutex_lock(&mutex_mmap);
#ifndef USE_MMAP
free((void*)addr);
#else
munmap((void*)addr, size);
#endif
kh_dynablocks_t *blocks = dblist_oversized;
if(blocks) {
khint_t k = kh_get(dynablocks, blocks, (uintptr_t)db);
khint_t k = kh_get(dynablocks, blocks, addr);
if(k!=kh_end(blocks))
kh_del(dynablocks, blocks, k);
}
pthread_mutex_unlock(&mutex_mmap);
return;
}
pthread_mutex_lock(&mutex_mmap);
@@ -441,14 +495,16 @@ dynablocklist_t* getDB(uintptr_t idx)
// each dynmap is 64k of size
void addDBFromAddressRange(uintptr_t addr, uintptr_t size, int nolinker)
void addDBFromAddressRange(uintptr_t addr, uintptr_t size)
{
dynarec_log(LOG_DEBUG, "addDBFromAddressRange %p -> %p\n", (void*)addr, (void*)(addr+size-1));
uintptr_t idx = (addr>>DYNAMAP_SHIFT);
uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
if(!dynmap[i]) {
dynmap[i] = NewDynablockList(i<<DYNAMAP_SHIFT, 1<<DYNAMAP_SHIFT, nolinker, 0);
dynablocklist_t* p = NewDynablockList(i<<DYNAMAP_SHIFT, 1<<DYNAMAP_SHIFT, 0);
if(arm_lock_storeifnull(&dynmap[i], p)!=p)
FreeDynablockList(&p);
}
}
}
@@ -456,47 +512,227 @@ void addDBFromAddressRange(uintptr_t addr, uintptr_t size, int nolinker)
void cleanDBFromAddressRange(uintptr_t addr, uintptr_t size, int destroy)
{
dynarec_log(LOG_DEBUG, "cleanDBFromAddressRange %p -> %p %s\n", (void*)addr, (void*)(addr+size-1), destroy?"destroy":"mark");
uintptr_t idx = (addr>box86_dynarec_largest && !destroy)?((addr-box86_dynarec_largest)>>DYNAMAP_SHIFT):(addr>>DYNAMAP_SHIFT);
uintptr_t idx = (addr>>DYNAMAP_SHIFT);
uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
dynablocklist_t* dblist = dynmap[i];
if(dblist) {
uintptr_t startdb = StartDynablockList(dblist);
uintptr_t enddb = EndDynablockList(dblist);
uintptr_t startaddr = addr;
if(startaddr<startdb) startaddr = startdb;
uintptr_t endaddr = addr + size - 1;
if(endaddr>enddb) endaddr = enddb;
if(destroy)
FreeRangeDynablock(dblist, startaddr, endaddr-startaddr+1);
FreeRangeDynablock(dblist, addr, size);
else
MarkRangeDynablock(dblist, startaddr, endaddr-startaddr+1);
MarkRangeDynablock(dblist, addr, size);
}
}
}
#ifdef ARM
void arm_next(void);
#endif
void addJumpTableIfDefault(void* addr, void* jmp)
{
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
if(box86_jumptable[idx] == box86_jmptbl_default) {
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)arm_next;
if(arm_lock_storeifref(&box86_jumptable[idx], tbl, box86_jmptbl_default)!=tbl)
free(tbl);
}
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
arm_lock_storeifref(&box86_jumptable[idx][off], jmp, arm_next);
}
void setJumpTableDefault(void* addr)
{
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
if(box86_jumptable[idx] == box86_jmptbl_default) {
return;
}
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
box86_jumptable[idx][off] = (uintptr_t)arm_next;
}
int isJumpTableDefault(void* addr)
{
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
if(box86_jumptable[idx] == box86_jmptbl_default) {
return 1;
}
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
return (box86_jumptable[idx][off]==(uintptr_t)arm_next)?1:0;
}
uintptr_t getJumpTable()
{
return (uintptr_t)box86_jumptable;
}
uintptr_t getJumpTableAddress(uintptr_t addr)
{
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
if(box86_jumptable[idx] == box86_jmptbl_default) {
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)arm_next;
if(arm_lock_storeifref(&box86_jumptable[idx], tbl, box86_jmptbl_default)!=tbl)
free(tbl);
}
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
return (uintptr_t)&box86_jumptable[idx][off];
}
// Remove the Write flag from an adress range, so DB can be executed
// no log, as it can be executed inside a signal handler
void protectDB(uintptr_t addr, uintptr_t size)
{
dynarec_log(LOG_DEBUG, "protectDB %p -> %p\n", (void*)addr, (void*)(addr+size-1));
uintptr_t idx = (addr>>MEMPROT_SHIFT);
uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
uint32_t prot = memprot[i];
if(!prot)
prot = PROT_READ | PROT_WRITE; // comes from malloc & co, so should not be able to execute
memprot[i] = prot|PROT_DYNAREC;
if(!(prot&PROT_DYNAREC))
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_WRITE);
}
}
// 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, uintptr_t size)
{
dynarec_log(LOG_DEBUG, "unprotectDB %p -> %p\n", (void*)addr, (void*)(addr+size-1));
uintptr_t idx = (addr>>MEMPROT_SHIFT);
uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
uint32_t prot = memprot[i];
memprot[i] = prot&~PROT_DYNAREC;
if(prot&PROT_DYNAREC) {
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_DYNAREC);
cleanDBFromAddressRange((i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, 0);
}
}
}
#endif
void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
{
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
uint32_t dyn=(memprot[i]&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] = prot|dyn;
}
}
void setProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
{
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
memprot[i] = prot;
}
}
uint32_t getProtection(uintptr_t addr)
{
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
uint32_t ret = memprot[idx];
return ret;
}
int unlockCustommemMutex()
{
int ret = 0;
int i = 0;
#define GO(A, B) \
i = checkUnlockMutex(&A); \
if(i) { \
ret|=(1<<B); \
}
GO(mutex_blocks, 0)
#ifdef DYNAREC
GO(mutex_mmap, 1)
#endif
#undef GO
return ret;
}
void relockCustommemMutex(int locks)
{
#define GO(A, B) \
if(locks&(1<<B)) \
pthread_mutex_lock(&A); \
GO(mutex_blocks, 0)
#ifdef DYNAREC
GO(mutex_mmap, 1)
#endif
#undef GO
}
static void init_mutexes(void)
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
pthread_mutex_init(&mutex_blocks, &attr);
#ifdef DYNAREC
pthread_mutex_init(&mutex_mmap, &attr);
#endif
pthread_mutexattr_destroy(&attr);
}
static void atfork_child_custommem(void)
{
// (re))init mutex if it was lock before the fork
init_mutexes();
}
void init_custommem_helper(box86context_t* ctx)
{
#ifdef DYNAREC
if(dynmap) // already initialized
if(inited) // already initialized
return;
pthread_mutex_init(&mutex_mmap, NULL);
dynmap = (dynablocklist_t**)calloc(DYNAMAP_SIZE, sizeof(dynablocklist_t*));
inited = 1;
init_mutexes();
#ifdef DYNAREC
#ifdef ARM
for(int i=0; i<(1<<JMPTABL_SHIFT); ++i)
box86_jmptbl_default[i] = (uintptr_t)arm_next;
for(int i=0; i<JMPTABL_SIZE; ++i)
box86_jumptable[i] = box86_jmptbl_default;
#else
#error Unsupported architecture!
#endif
#endif
pthread_atfork(NULL, NULL, atfork_child_custommem);
}
void fini_custommem_helper(box86context_t *ctx)
{
if(!inited)
return;
inited = 0;
#ifdef DYNAREC
dynarec_log(LOG_DEBUG, "Free global Dynarecblocks\n");
for (int i=0; i<mmapsize; ++i) {
if(mmaplist[i].block)
#ifdef USE_MMAP
munmap(mmaplist[i].block, mmaplist[i].size);
#else
free(mmaplist[i].block);
#endif
if(mmaplist[i].dblist) {
kh_destroy(dynablocks, mmaplist[i].dblist);
mmaplist[i].dblist = NULL;
}
if(mmaplist[i].helper) {
free(mmaplist[i].helper);
mmaplist[i].helper = NULL;
}
}
if(dblist_oversized) {
kh_destroy(dynablocks, dblist_oversized);
@@ -518,13 +754,21 @@ void fini_custommem_helper(box86context_t *ctx)
FreeRangeDynablock(dblist, startaddr, endaddr-startaddr+1);
}
}
for (uintptr_t i=idx; i<=end; ++i)
if(dynmap[i])
FreeDynablockList(&dynmap[i]);
pthread_mutex_destroy(&mutex_mmap);
free(mmaplist);
free(dynmap);
dynmap = NULL;
for (int i=0; i<DYNAMAP_SIZE; ++i)
if(box86_jumptable[i]!=box86_jmptbl_default)
free(box86_jumptable[i]);
#endif
for(int i=0; i<n_blocks; ++i)
#ifdef USE_MMAP
munmap(p_blocks[i].block, p_blocks[i].size);
#else
free(p_blocks[i].block);
#endif
free(p_blocks);
pthread_mutex_destroy(&mutex_blocks);
}
+31 -11
View File
@@ -78,13 +78,17 @@ Op is 20-27
// movt dst, #imm16
#define MOVT(dst, imm16) EMIT(0xe3400000 | ((dst) << 12) | (((imm16) & 0xf000) << 4) | brIMM((imm16) & 0x0fff) )
// pseudo insruction: mov reg, #imm with imm a 32bits value
#define MOV32(dst, imm32) \
MOVW(dst, ((uint32_t)imm32)&0xffff); \
if (((uint32_t)(imm32))>>16) { \
MOVT(dst, (((uint32_t)imm32)>>16)); }
#define MOV32(dst, imm32) \
if((~(uint32_t)(imm32))<0x100) { \
MVN_IMM8(dst, ~(uint32_t)(imm32), 0); \
} else { \
MOVW(dst, ((uint32_t)imm32)&0xffff); \
if (((uint32_t)(imm32))>>16) { \
MOVT(dst, (((uint32_t)imm32)>>16));} \
}
// pseudo insruction: mov reg, #imm with imm a 32bits value, fixed size
#define MOV32_(dst, imm32) \
MOVW(dst, ((uint32_t)(imm32))&0xffff); \
#define MOV32_(dst, imm32) \
MOVW(dst, ((uint32_t)(imm32))&0xffff); \
MOVT(dst, (((uint32_t)(imm32))>>16))
// movw.cond dst, #imm16
#define MOVW_COND(cond, dst, imm16) EMIT(cond | 0x03000000 | ((dst) << 12) | (((imm16) & 0xf000) << 4) | brIMM((imm16) & 0x0fff) )
@@ -97,6 +101,8 @@ Op is 20-27
#define MOV_REG_LSL_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (0<<5) | ((imm5)<<7))
// mov dst, src lsr imm5
#define MOV_REG_LSR_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (1<<5) | ((imm5)<<7))
// mov.cond dst, src lsr imm5
#define MOV_REG_LSR_IMM5_COND(cond, dst, src, imm5) EMIT(cond | 0x01a00000 | ((dst) << 12) | (src) | (0<<4) | (1<<5) | ((imm5)<<7))
// mov dst, src asr imm5
#define MOV_REG_ASR_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (2<<5) | ((imm5)<<7))
// mov dst, src ror imm5
@@ -110,8 +116,14 @@ Op is 20-27
// mov.s dst, src ror imm5
#define MOVS_REG_ROR_IMM5(dst, src, imm5) EMIT(0xe1b00000 | ((dst) << 12) | (src) | (0<<4) | (3<<5) | ((imm5)<<7))
// mov.s dst, src lsl rs
#define MOVS_REG_LSL_REG(dst, src, rs) EMIT(0xe1b00000 | ((dst) << 12) | (src) | (1<<4) | (0<<5) | ((rs)<<8))
// mov.s dst, src lsr rs
#define MOVS_REG_LSR_REG(dst, src, rs) EMIT(0xe1b00000 | ((dst) << 12) | (src) | (1<<4) | (1<<5) | ((rs)<<8))
// mov dst, src lsl rs
#define MOV_REG_LSL_REG(dst, src, rs) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (1<<4) | (0<<5) | ((rs)<<8))
// mov.cond dst, src lsl rs
#define MOV_REG_LSL_REG_COND(cond, dst, src, rs) EMIT(cond | 0x01a00000 | ((dst) << 12) | (src) | (1<<4) | (0<<5) | ((rs)<<8))
// mov dst, src lsr rs
#define MOV_REG_LSR_REG(dst, src, rs) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (1<<4) | (1<<5) | ((rs)<<8))
// mov dst, src asr rs
@@ -247,7 +259,7 @@ Op is 20-27
// orr.s dst, src1, #imm8
#define ORRS_IMM8(dst, src, imm8, rot) \
EMIT(0xe3900000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
// orr.cond dst, src1, #imm8
// orr.cond dst, src1, #imm8 ror rot*2
#define ORR_IMM8_COND(cond, dst, src, imm8, rot) \
EMIT((cond) | 0x03800000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
// orr dst, src1, src2, lsl rs
@@ -266,6 +278,9 @@ Op is 20-27
EMIT(0xe2200000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
#define XORS_IMM8(dst, src, imm8) \
EMIT(0xe2300000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
// xor dst, src, #(imm8 ror rot*2)
#define XOR_IMM8_ROR(dst, src, imm8, rot) \
EMIT(0xe2200000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
// xor.cond dst, src, #(imm8)
#define XOR_IMM8_COND(cond, dst, src, imm8) \
EMIT(cond | 0x02200000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
@@ -275,10 +290,13 @@ Op is 20-27
// xor dst, src1, src2, lsl #imm
#define XOR_REG_LSR_IMM8(dst, src1, src2, imm8) \
EMIT(0xe0200000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm8, src2) )
// xor.cond dst, src1, src2, lsl #imm
#define XOR_REG_LSR_IMM8_COND(cond, dst, src1, src2, imm8) \
EMIT(cond | 0x00200000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm8, src2) )
// bic dst, src1, src2, lsl #imm
#define BIC_REG_LSL_IMM5(dst, src1, src2, imm5) \
EMIT(0xe1c00000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
// bic dst, src, IMM8
// bic dst, src, IMM8 ror rot*2
#define BIC_IMM8(dst, src, imm8, rot) \
EMIT(0xe3c00000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
// bic.cond dst, src, IMM8
@@ -294,8 +312,8 @@ Op is 20-27
#define MVN_REG_LSL_IMM5(dst, rm, imm5) \
EMIT(0xe1e00000 | ((dst) << 12) | (0 << 16) | brLSL(imm5, rm) )
// mvn dst, src, IMM8
#define MVN_IMM8(dst, src, imm8, rot) \
EMIT(0xe3e00000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
#define MVN_IMM8(dst, imm8, rot) \
EMIT(0xe3e00000 | ((dst) << 12) | (rot)<<8 | ((imm8)&0xff) )
// mvn dst, src1, src2, lsr #imm
#define MVN_REG_LSR_IMM8(dst, rm, imm8) \
EMIT(0xe1e00000 | ((dst) << 12) | (0 << 16) | brLSR(imm8, rm) )
@@ -460,7 +478,9 @@ Op is 20-27
#define BFC_COND(cond, rd, lsb, width) EMIT(cond | (0b0111110<<21) | (((lsb)+(width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b001<<4) | 0b1111)
// REV: Reverse byte of a 32bits word
#define REV(rd, rm) EMIT(c__ | (0b01101<<23) | (0<<22) | (0b11<<20) | (0b1111<<16) | ((rd)<<12) | (0b1111<<8) | (0b0011<<4) | (rm))
#define REV(rd, rm) EMIT(c__ | (0b01101<<23) | (0<<22) | (0b11<<20) | (0b1111<<16) | ((rd)<<12) | (0b1111<<8) | (0b0011<<4) | (rm))
// REV16: Reverse byte of a 16bits word
#define REV16(rd, rm) EMIT(c__ | (0b01101<<23) | (0<<22) | (0b11<<20) | (0b1111<<16) | ((rd)<<12) | (0b1111<<8) | (0b1011<<4) | (rm))
#define SSAT_gen(cond, sat_imm, Rd, imm5, sh, Rn) (cond | 0b0110101<<21 | (sat_imm)<<16 | (Rd)<<12 | (imm5)<<7 | (sh)<<6 | 0b01<<4 | (Rn))
// Signed Staturate Rn to 2^(staturate_to-1) into Rd. Optionnaly shift left Rn before saturate
+2 -2
View File
@@ -12,7 +12,7 @@ arm_epilog:
//pop {r0}
stm r0, {r4-r12,r14} // put back reg value in emu, including EIP (so r14 must be EIP now)
//restore all used register
//vpop {d8-d15}
vpop {d8-d15}
pop {r4-r11, pc}
//end, return...
//bx lr
@@ -21,7 +21,7 @@ arm_epilog:
.global arm_epilog_fast
arm_epilog_fast:
//restore all used register
//vpop {d8-d15}
vpop {d8-d15}
pop {r4-r11, pc}
//end, return...
//bx lr
+2
View File
@@ -396,6 +396,7 @@ ARM_ cond 0 0 0 1 0 0 1 0 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) 0 0 1
ARM_ cond/=1110 0 0 0 1 0 0 1 0 imm12 0 1 1 1 imm4 BKPT #<imm16>
ARMS cond 0 0 0 1 0 0 1 1 Rn (0) (0) (0) (0) imm5 type 0 Rm TEQ<c> <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 1 0 1 0 0 Rn Rt (0) (0) (0) (0) 1 0 0 1 Rm SWPB<c> <Rt>, <Rm>, [<Rn>]
ARM_ cond 0 0 0 1 0 1 1 0 (1) (1) (1) (1) Rd (1) (1) (1) (1) 0 0 0 1 Rm CLZ<c> <Rd>, <Rm>
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 0 1 1 imm4L STRH<c> <Rt>, [<Rn>, #+/-<imm8>]{!}
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 1 0 1 imm4L LDRD<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm8>]{!}
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 1 1 1 imm4L STRD<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm8>]{!}
@@ -482,6 +483,7 @@ ARMs cond 0 1 1 0 1 1 1 sat_imm Rd imm5 sh 0 1 Rn USAT<c> <Rd>, #<imm>, <Rn>{, <
ARM_ cond 0 1 1 0 1 1 1 0 sat_imm Rd (1) (1) (1) (1) 0 0 1 1 Rn USAT16<c> <Rd>, #<imm>, <Rn>
ARM_ cond 0 1 1 0 1 1 1 0 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm UXTB<c> <Rd>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 1 1 0 Rn Rd rotate (0) (0) 0 1 1 1 Rm UXTAB<c> <Rd>, <Rn>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 1 1 1 (1) (1) (1) (1) Rd (1) (1) (1) (1) 0 0 1 1 Rm RBIT<c> <Rd>, <Rm>
ARM_ cond 0 1 1 0 1 1 1 1 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm UXTH<c> <Rd>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 1 1 1 (1) (1) (1) (1) Rd (1) (1) (1) (1) 1 0 1 1 Rm REVSH<c> <Rd>, <Rm>
ARM_ cond 0 1 1 0 1 1 1 1 Rn Rd rotate (0) (0) 0 1 1 1 Rm UXTAH<c> <Rd>, <Rn>, <Rm>{, <rotation>}
+22 -3
View File
@@ -1,5 +1,5 @@
//arm lock helper
//there is 2 part: read and write
// arm lock helper
// there is 2 part: read and write
// write return 0 on success, 1 on fail (value has been changed)
.text
@@ -15,6 +15,7 @@
.global arm_lock_write_dd
.global arm_lock_xchg
.global arm_lock_storeifnull
.global arm_lock_storeifref
arm_lock_read_b:
@@ -81,9 +82,27 @@ arm_lock_storeifnull:
// r0 needs to be aligned
ldrex r2, [r0]
cmp r2, #0
moveq r2, r1
bne arm_lock_storeifnull_exit
mov r2, r1
strex r3, r2, [r0]
cmp r3, #1
beq arm_lock_storeifnull
arm_lock_storeifnull_exit:
mov r0, r2
bx lr
arm_lock_storeifref:
push {r4}
arm_lock_storeifref_loop:
// address is r0, value is r1, r1 store to r0 only if [r0] is r2. return new [r0] value (so r1 or old value)
ldrex r3, [r0]
cmp r3, r2
bne arm_lock_storeifref_exit
mov r3, r1
strex r4, r3, [r0]
cmp r4, #1
beq arm_lock_storeifref_loop
arm_lock_storeifref_exit:
mov r0, r3
pop {r4}
bx lr
+6 -3
View File
@@ -22,10 +22,13 @@ extern void arm_lock_read_dd(uint32_t* a, uint32_t* b, void* addr);
// STREX of ADDR, return 0 if ok, 1 if not
extern int arm_lock_write_dd(uint32_t a, uint32_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 arm_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* arm_lock_storeifnull(void*p, void* val);
// Atomically store value to [p] only if [p] is NULL. Return new [p] value (so val or old)
extern void* arm_lock_storeifnull(void* p, void* val);
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
extern void* arm_lock_storeifref(void* p, void* val, void* ref);
#endif //__ARM_LOCK_HELPER__H__
@@ -6,24 +6,8 @@
.text
.align 4
.extern UpdateLinkTable
.extern LinkNext
.global arm_linker
arm_linker:
// emu is r0
stm r0, {r4-r12,r14} // put back reg value in emu, including EIP (easier debugging, and safer)
// table offset is r1
// IP address is r14
push {r0, r1, r12, r14}
mov r2, r14
// call the function
bl UpdateLinkTable
// return offset is jump address
mov r3, r0
pop {r0, r1, r12, r14}
bx r3
.global arm_next
arm_next:
// emu is r0
+12
View File
@@ -3605,6 +3605,12 @@ const char* arm_print(uint32_t opcode) {
int rm = (opcode >> 0) & 0xF;
sprintf(ret, "SWPB%s %s, %s, [%s]", cond, regname[rt], regname[rm], regname[rn]);
} else if ((opcode & 0x0FF000F0) == 0x01600010) {
const char* cond = conds[(opcode >> 28) & 0xF];
int rd = (opcode >> 12) & 0xF;
int rm = (opcode >> 0) & 0xF;
sprintf(ret, "CLZ%s %s, %s", cond, regname[rd], regname[rm]);
} else if ((opcode & 0x0F5000F0) == 0x014000B0) {
const char* cond = conds[(opcode >> 28) & 0xF];
int rt = (opcode >> 12) & 0xF;
@@ -4288,6 +4294,12 @@ const char* arm_print(uint32_t opcode) {
}
sprintf(ret, "UXTAB%s %s, %s, %s%s}", cond, regname[rd], regname[rn], regname[rm], tmprot);
} else if ((opcode & 0x0FF000F0) == 0x06F00030) {
const char* cond = conds[(opcode >> 28) & 0xF];
int rd = (opcode >> 12) & 0xF;
int rm = (opcode >> 0) & 0xF;
sprintf(ret, "RBIT%s %s, %s", cond, regname[rd], regname[rm]);
} else if ((opcode & 0x0FFF00F0) == 0x06FF0070) {
const char* cond = conds[(opcode >> 28) & 0xF];
int rd = (opcode >> 12) & 0xF;
+1 -1
View File
@@ -10,7 +10,7 @@
arm_prolog:
//save all used register
push {r4-r11, lr}
//vpush {d8-d15}
vpush {d8-d15}
//setup emu -> register
//push {r0}
ldm r0, {r4-r12} // all 8 register in direct access, plus flags, no EIP (so r14 can be used as scratch)
-19
View File
@@ -1,19 +0,0 @@
//arm try to update linker table for dynarec
//and address of table to as 1st parameter
//jump addres as second and ip as third
// don't retry if failed to write...
.text
.align 4
.global arm_tableupdate
arm_tableupdate:
// jump address is r0 and IP address is r1
// table offset is r2
push {r4, r5}
ldrexd r4, r5, [r2]
strexd r3, r0, r1, [r2]
pop {r4, r5}
mov r0, r3
bx lr
+62 -101
View File
@@ -38,7 +38,7 @@ uint32_t X31_hash_code(void* addr, int len)
return (uint32_t)h;
}
dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int nolinker, int direct)
dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct)
{
if(!textsz) {
printf_log(LOG_NONE, "Error, creating a NULL sized Dynablock\n");
@@ -47,18 +47,18 @@ dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int nolinker, int
dynablocklist_t* ret = (dynablocklist_t*)calloc(1, sizeof(dynablocklist_t));
ret->text = text;
ret->textsz = textsz;
ret->nolinker = nolinker;
if(direct && textsz) {
ret->direct = (dynablock_t**)calloc(textsz, sizeof(dynablock_t*));
if(!ret->direct) {printf_log(LOG_NONE, "Warning, fail to create direct block for dynablock @%p\n", (void*)text);}
}
dynarec_log(LOG_DEBUG, "New Dynablocklist %p, from %p->%p\n", ret, (void*)text, (void*)(text+textsz));
return ret;
}
void FreeDynablock(dynablock_t* db)
{
if(db) {
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x86=%p:%p father=%p, tablesz=%d, with %d son(s) already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size, db->father, db->tablesz, db->sons_size, db->gone);
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x86=%p:%p father=%p, with %d son(s) already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size, db->father, db->sons_size, db->gone);
if(db->gone)
return; // already in the process of deletion!
db->done = 0;
@@ -71,6 +71,8 @@ void FreeDynablock(dynablock_t* db)
if(addr>=startdb && addr<enddb)
db->parent->direct[addr-startdb] = NULL;
}
// remove jumptable
setJumpTableDefault(db->x86_addr);
// remove and free the sons
for (int i=0; i<db->sons_size; ++i) {
dynablock_t *son = (dynablock_t*)arm_lock_xchg(&db->sons[i], 0);
@@ -82,7 +84,6 @@ void FreeDynablock(dynablock_t* db)
FreeDynarecMap(db, (uintptr_t)db->block, db->size);
}
free(db->sons);
free(db->table);
free(db->instsize);
free(db);
}
@@ -94,7 +95,7 @@ void FreeDynablockList(dynablocklist_t** dynablocks)
return;
if(!*dynablocks)
return;
dynarec_log(LOG_DEBUG, "Free Direct Blocks %p from Dynablocklist nolinker=%d\n", (*dynablocks)->direct, (*dynablocks)->nolinker);
dynarec_log(LOG_DEBUG, "Free Dynablocklist %p, with Direct Blocks %p\n", *dynablocks, (*dynablocks)->direct);
if((*dynablocks)->direct) {
for (int i=0; i<(*dynablocks)->textsz; ++i) {
if((*dynablocks)->direct[i] && !(*dynablocks)->direct[i]->father)
@@ -113,53 +114,12 @@ void MarkDynablock(dynablock_t* db)
if(db) {
if(db->father)
db = db->father; // mark only father
if(db->nolinker)
db->need_test = 1; // test only blocks that can be marked (and so deleted)
}
}
void ProtectDynablock(dynablock_t* db)
{
if(db) {
if(db->father)
return; // protect only father, child(ren) will be automatically
protectDB((uintptr_t)db->x86_addr, db->x86_size);
}
}
void MarkDynablockList(dynablocklist_t** dynablocks)
{
if(!dynablocks)
return;
if(!*dynablocks)
return;
if(!(*dynablocks)->nolinker)
return;
dynarec_log(LOG_DEBUG, "Marked Blocks from Dynablocklist nolinker=%d %p:0x%x\n", (*dynablocks)->nolinker, (void*)(*dynablocks)->text, (*dynablocks)->textsz);
dynablock_t* db;
if((*dynablocks)->direct) {
for (int i=0; i<(*dynablocks)->textsz; ++i) {
db = (*dynablocks)->direct[i];
if(db)
MarkDynablock(db);
}
}
}
void ProtectDynablockList(dynablocklist_t** dynablocks)
{
if(!dynablocks)
return;
if(!*dynablocks)
return;
dynarec_log(LOG_DEBUG, "Protect Blocks from Dynablocklist nolinker=%d %p:0x%x\n", (*dynablocks)->nolinker, (void*)(*dynablocks)->text, (*dynablocks)->textsz);
dynablock_t* db;
if((*dynablocks)->direct) {
for (int i=0; i<(*dynablocks)->textsz; ++i) {
db = (*dynablocks)->direct[i];
if(db)
ProtectDynablock(db);
}
if(db->need_test)
return; // already done
db->need_test = 1; // test only blocks that can be marked (and so deleted)
setJumpTableDefault(db->x86_addr);
for(int i=0; i<db->sons_size; ++i)
setJumpTableDefault(db->sons[i]->x86_addr);
}
}
@@ -187,12 +147,11 @@ void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t
{
if(!dynablocks)
return;
if(!dynablocks->nolinker || !dynablocks->direct)
if(!dynablocks->direct)
return;
uintptr_t startdb = dynablocks->text;
uintptr_t enddb = startdb + dynablocks->textsz -1;
int maxsz = dynablocks->maxsz;
uintptr_t start = addr - maxsz;
uintptr_t start = addr;
uintptr_t end = addr+size-1;
if(start<startdb)
start = startdb;
@@ -206,22 +165,6 @@ void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t
MarkDynablock(db);
}
void ProtectDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
{
if(!dynablocks)
return;
uintptr_t startdb = dynablocks->text;
uintptr_t enddb = startdb + dynablocks->textsz;
uintptr_t start = addr;
uintptr_t end = addr+size;
if(start<startdb)
start = startdb;
if(end>enddb)
end = enddb;
if(end>startdb && start<enddb)
protectDB(start, end-start); //no +1; as end/enddb is exclusive and not inclusive
}
void FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
{
if(!dynablocks)
@@ -266,13 +209,13 @@ void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t s
{
if(!dynablocks)
return;
if(!dynablocks->nolinker)
return;
if(dynablocks->direct) {
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(int idx=(addr-dynablocks->maxsz)>>DYNAMAP_SHIFT; idx<addr>>DYNAMAP_SHIFT; ++idx)
MarkDirectDynablock(getDB(idx), addr, size);
for(int idx=(new_addr)>>DYNAMAP_SHIFT; idx<(addr>>DYNAMAP_SHIFT); ++idx)
MarkDirectDynablock(getDB(idx), new_addr, new_size);
}
}
@@ -282,8 +225,8 @@ dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks)
return NULL;
dynablock_t* db;
kh_foreach_value(dynablocks, db,
uintptr_t s = (uintptr_t)db->block;
uintptr_t e = (uintptr_t)db->block+db->size;
const uintptr_t s = (uintptr_t)db->block;
const uintptr_t e = (uintptr_t)db->block+db->size;
if((uintptr_t)addr>=s && (uintptr_t)addr<e)
return db->father?db->father:db;
)
@@ -324,13 +267,17 @@ dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* c
if (!*created)
return block;
if(!dynablocks->direct)
dynablocks->direct = (dynablock_t**)calloc(dynablocks->textsz, sizeof(dynablock_t*));
if(!dynablocks->direct) {
dynablock_t** p = (dynablock_t**)calloc(dynablocks->textsz, sizeof(dynablock_t*));
if(arm_lock_storeifnull(&dynablocks->direct, p)!=p)
free(p); // someone already create the direct array, too late...
}
// create and add new block
dynarec_log(LOG_DUMP, "Ask for DynaRec Block creation @%p\n", (void*)addr);
block = (dynablock_t*)calloc(1, sizeof(dynablock_t));
block->parent = dynablocks;
dynablock_t* tmp = (dynablock_t*)arm_lock_storeifnull(&dynablocks->direct[addr-dynablocks->text], block);
if(tmp != block) {
// a block appeard!
@@ -339,8 +286,6 @@ dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* c
return tmp;
}
block->parent = dynablocks;
*created = 1;
return block;
}
@@ -378,23 +323,31 @@ static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t
if(!created)
return block; // existing block...
#if 0
if(box86_dynarec_dump)
pthread_mutex_lock(&my_context->mutex_dyndump);
#endif
// fill the block
block->x86_addr = (void*)addr;
if(!FillBlock(block, filladdr)) {
void* old = (void*)arm_lock_xchg(&dynablocks->direct[addr-dynablocks->text], 0);
if(old!=block) {// put it back in place, strange things are happening here!
dynarec_log(LOG_NONE, "Warning, a wild block appeared at %p: %p\n", (void*)addr, old);
arm_lock_xchg(&dynablocks->direct[addr-dynablocks->text], (uintptr_t)old);
pthread_mutex_lock(&my_context->mutex_dyndump);
void* ret = FillBlock(block, filladdr);
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*)arm_lock_storeifref(&dynablocks->direct[addr-dynablocks->text], 0, block);
if(old!=block && old) { // put it back in place, strange things are happening here!
dynarec_log(LOG_INFO, "Warning, a wild block appeared at %p: %p\n", (void*)addr, old);
// Doing nothing else, the block has not been written
}
free(block);
block = NULL;
}
#if 0
if(box86_dynarec_dump)
pthread_mutex_unlock(&my_context->mutex_dyndump);
#endif
// check size
if(block) {
if(block && block->x86_size) {
int blocksz = block->x86_size;
if(dynablocks->maxsz<blocksz) {
dynablocks->maxsz = blocksz;
@@ -405,9 +358,11 @@ static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t
dblist->maxsz = blocksz;
}
}
if(block->parent->nolinker)
protectDB((uintptr_t)block->x86_addr, block->x86_size);
protectDB((uintptr_t)block->x86_addr, block->x86_size);
// fill-in jumptable
addJumpTableIfDefault(block->x86_addr, block->block);
for(int i=0; i<block->sons_size; ++i)
addJumpTableIfDefault(block->sons[i]->x86_addr, block->sons[i]->block);
}
dynarec_log(LOG_DEBUG, " --- DynaRec Block %s @%p:%p (%p, 0x%x bytes, with %d son(s))\n", created?"created":"recycled", (void*)addr, (void*)(addr+((block)?block->x86_size:0)), (block)?block->block:0, (block)?block->size:0, (block)?block->sons_size:0);
@@ -418,11 +373,11 @@ static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t** current)
{
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, *current);
if(db && (db->need_test || (db->father && db->father->need_test))) {
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 = father->nolinker?X31_hash_code(father->x86_addr, father->x86_size):0;
uint32_t hash = X31_hash_code(father->x86_addr, father->x86_size);
if(hash!=father->hash) {
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) with %d son(s)\n", father, father->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->sons_size);
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->sons_size, (void*)addr);
// no more current if it gets invalidated too
if(*current && father->x86_addr>=(*current)->x86_addr && (father->x86_addr+father->x86_size)<(*current)->x86_addr)
*current = NULL;
@@ -432,8 +387,11 @@ dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t**
db = internalDBGetBlock(emu, addr, addr, create, *current);
} else {
father->need_test = 0;
if(father->nolinker)
protectDB((uintptr_t)father->x86_addr, father->x86_size);
protectDB((uintptr_t)father->x86_addr, father->x86_size);
// fill back jumptable
addJumpTableIfDefault(father->x86_addr, father->block);
for(int i=0; i<father->sons_size; ++i)
addJumpTableIfDefault(father->sons[i]->x86_addr, father->sons[i]->block);
}
}
return db;
@@ -444,19 +402,22 @@ dynablock_t* DBAlternateBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr)
dynarec_log(LOG_DEBUG, "Creating AlternateBlock at %p for %p\n", (void*)addr, (void*)filladdr);
int create = 1;
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, NULL);
if(db && (db->need_test || (db->father && db->father->need_test))) {
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 = father->nolinker?X31_hash_code(father->x86_addr, father->x86_size):0;
uint32_t hash = X31_hash_code(father->x86_addr, father->x86_size);
if(hash!=father->hash) {
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) with %d son(s)\n", father, father->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->sons_size);
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->sons_size, (void*)addr);
// Free father, it's now invalid!
FreeDynablock(father);
// start again... (will create a new block)
db = internalDBGetBlock(emu, addr, filladdr, create, NULL);
} else {
father->need_test = 0;
if(father->nolinker)
protectDB((uintptr_t)father->x86_addr, father->x86_size);
protectDB((uintptr_t)father->x86_addr, father->x86_size);
// fill back jumptable
addJumpTableIfDefault(father->x86_addr, father->block);
for(int i=0; i<father->sons_size; ++i)
addJumpTableIfDefault(father->sons[i]->x86_addr, father->sons[i]->block);
}
}
return db;
+1 -4
View File
@@ -15,12 +15,10 @@ typedef struct dynablock_s {
void* x86_addr;
uintptr_t x86_size;
uint32_t hash;
uintptr_t* table;
int tablesz;
uint8_t need_test;
uint8_t done;
uint8_t gone;
uint8_t nolinker;
uint8_t dummy;
int isize;
dynablock_t** sons; // sons (kind-of dummy dynablock...)
int sons_size;
@@ -32,7 +30,6 @@ typedef struct dynablocklist_s {
uintptr_t text;
int textsz;
int maxsz; // maxblock size (for this block or previous block)
int nolinker; // in case this dynablock can be deleted
dynablock_t** direct; // direct mapping (waste of space, so the array is created at first write)
} dynablocklist_t;
+38 -69
View File
@@ -25,73 +25,30 @@
void arm_prolog(x86emu_t* emu, void* addr) EXPORTDYN;
void arm_epilog() EXPORTDYN;
void arm_epilog_fast() EXPORTDYN;
void arm_linker() EXPORTDYN;
int arm_tableupdate(void* jump, uintptr_t addr, void** table) EXPORTDYN;
#endif
void tableupdate(void* jumpto, uintptr_t ref, void** table)
{
#ifdef ARM
if(arm_tableupdate(jumpto, ref, table))
#endif
{
table[0] = jumpto;
table[1] = (void*)ref;
}
}
void resettable(void** table)
{
void* p = table[1];
#ifdef ARM
tableupdate(arm_linker, (uintptr_t)p, table);
#endif
//table[2] = own_dynablock // unchanged
table[3] = NULL; // removed "linked" information
}
#ifdef DYNAREC
void* UpdateLinkTable(x86emu_t* emu, void** table, uintptr_t addr)
#ifdef HAVE_TRACE
uintptr_t getX86Address(dynablock_t* db, uintptr_t arm_addr);
#endif
void* LinkNext(x86emu_t* emu, uintptr_t addr, void* x2)
{
dynablock_t* current = (dynablock_t*)table[2];
if(current->father)
current = current->father;
void * jblock;
dynablock_t* block = DBGetBlock(emu, addr, 1, &current);
if(!current) { // current has been invalidated, stop running it...
//dynarec_log(LOG_DEBUG, "--- Current invalidated while linking.\n");
return arm_epilog_fast;
#ifdef HAVE_TRACE
if(!addr) {
x2-=8; // actual PC is 2 instructions ahead
dynablock_t* db = FindDynablockFromNativeAddress(x2);
printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x86addr=%p)\n", x2, db, db?(void*)getX86Address(db, (uintptr_t)x2):NULL);
}
if(!block) {
// no block, let link table as is...
//tableupdate(arm_epilog, addr, table);
return arm_epilog_fast;
}
if(!block->done) {
// not finished yet... leave linker
//tableupdate(arm_linker, addr, table);
return arm_epilog_fast;
}
if(!(jblock=block->block)) {
// null block, but done: go to epilog, no linker here
tableupdate(arm_epilog, addr, table);
return arm_epilog_fast;
}
//dynablock_t *father = block->father?block->father:block;
if(!block->parent->nolinker) {
//dynarec_log(LOG_DEBUG, "--- Linking %p/%p to %p (table=%p[%p/%p/%p/%p])\n", block, block->block, current, table, table[0], table[1], table[2], table[3]);
// only update block if linker is allowed
tableupdate(jblock, addr, table);
}
return jblock;
}
void* LinkNext(x86emu_t* emu, uintptr_t addr)
{
#endif
dynablock_t* current = NULL;
void * jblock;
dynablock_t* block = DBGetBlock(emu, addr, 1, &current);
if(!block) {
// no block, let link table as is...
#ifdef HAVE_TRACE
dynablock_t* db = FindDynablockFromNativeAddress(x2);
printf_log(LOG_INFO, "Warning, jumping to a no-block address from %p (db=%p, x86addr=%p)\n", x2, db, db?(void*)getX86Address(db, (uintptr_t)x2):NULL);
#endif
//tableupdate(arm_epilog, addr, table);
return arm_epilog;
}
@@ -120,9 +77,12 @@ void DynaCall(x86emu_t* emu, uintptr_t addr)
ejb->emu = emu;
ejb->jmpbuf_ok = 1;
jmpbuf_reset = 1;
if(setjmp((struct __jmp_buf_tag*)ejb->jmpbuf)) {
printf_log(LOG_DEBUG, "Setjmp DynaCall, fs=0x%x\n", ejb->emu->segs[_FS]);
int a;
if((a=sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))) {
printf_log(LOG_DEBUG, "Setjmp DynaCall %d, fs=0x%x\n", a, ejb->emu->segs[_FS]);
addr = R_EIP; // not sure if it should still be inside DynaCall!
if(a==2)
Run(emu, 1); // "single step" next instruction that is doing auto-smc
}
}
}
@@ -145,14 +105,14 @@ void DynaCall(x86emu_t* emu, uintptr_t addr)
dynablock_t* current = NULL;
while(!emu->quit) {
block = DBGetBlock(emu, R_EIP, 1, &current);
current = (block && !block->parent->nolinker)?block:NULL;
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, "Calling Interpretor @%p, emu=%p\n", (void*)R_EIP, emu);
dynarec_log(LOG_DEBUG, "%04d|Calling Interpretor @%p, emu=%p\n", GetTID(), (void*)R_EIP, emu);
Run(emu, 1);
} else {
dynarec_log(LOG_DEBUG, "Calling DynaRec Block @%p (%p) of %d x86 instructions (nolinker=%d, father=%p) emu=%p\n", (void*)R_EIP, block->block, block->isize ,block->parent->nolinker, block->father, emu);
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x86 instructions (father=%p) emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize ,block->father, emu);
CHECK_FLAGS(emu);
// block is here, let's run it!
#ifdef ARM
@@ -169,7 +129,7 @@ void DynaCall(x86emu_t* emu, uintptr_t addr)
ejb->emu = emu;
ejb->jmpbuf_ok = 1;
jmpbuf_reset = 1;
if(setjmp((struct __jmp_buf_tag*)ejb->jmpbuf)) {
if(sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1)) {
printf_log(LOG_DEBUG, "Setjmp inner DynaCall, fs=0x%x\n", ejb->emu->segs[_FS]);
addr = R_EIP;
}
@@ -199,15 +159,24 @@ int DynaRun(x86emu_t* emu)
{
// prepare setjump for signal handling
emu_jmpbuf_t *ejb = NULL;
#ifdef DYNAREC
int jmpbuf_reset = 1;
#endif
if(emu->type == EMUTYPE_MAIN) {
ejb = GetJmpBuf();
if(!ejb->jmpbuf_ok) {
ejb->emu = emu;
ejb->jmpbuf_ok = 1;
int a;
#ifdef DYNAREC
jmpbuf_reset = 1;
if(setjmp((struct __jmp_buf_tag*)ejb->jmpbuf))
printf_log(LOG_DEBUG, "Setjmp DynaRun, fs=0x%x\n", ejb->emu->segs[_FS]);
#endif
if((a=sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))) {
printf_log(LOG_DEBUG, "Setjmp DynaRun %d, fs=0x%x\n", a, ejb->emu->segs[_FS]);
if(a==2)
Run(emu, 1); // "single step" next instruction that is doing auto-smc
}
}
}
#ifdef DYNAREC
@@ -220,14 +189,14 @@ int DynaRun(x86emu_t* emu)
dynablock_t* current = NULL;
while(!emu->quit) {
block = DBGetBlock(emu, R_EIP, 1, &current);
current = (block && !block->parent->nolinker)?block:NULL;
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, "Running Interpretor @%p, emu=%p\n", (void*)R_EIP, emu);
dynarec_log(LOG_DEBUG, "%04d|Running Interpretor @%p, emu=%p\n", GetTID(), (void*)R_EIP, emu);
Run(emu, 1);
} else {
dynarec_log(LOG_DEBUG, "Running DynaRec Block @%p (%p) of %d x86 insts (nolinker=%d, father=%p) emu=%p\n", (void*)R_EIP, block->block, block->isize, block->parent->nolinker, block->father, emu);
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x86 insts (father=%p) emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize, block->father, emu);
// block is here, let's run it!
#ifdef ARM
arm_prolog(emu, block->block);
@@ -243,7 +212,7 @@ int DynaRun(x86emu_t* emu)
ejb->emu = emu;
ejb->jmpbuf_ok = 1;
jmpbuf_reset = 1;
if(setjmp((struct __jmp_buf_tag*)ejb->jmpbuf))
if(sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))
printf_log(LOG_DEBUG, "Setjmp inner DynaRun, fs=0x%x\n", ejb->emu->segs[_FS]);
}
}
+31 -21
View File
@@ -305,17 +305,26 @@ instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x86_size,
return insts;
}
void arm_pass0(dynarec_arm_t* dyn, uintptr_t addr);
void arm_pass1(dynarec_arm_t* dyn, uintptr_t addr);
void arm_pass2(dynarec_arm_t* dyn, uintptr_t addr);
void arm_pass3(dynarec_arm_t* dyn, uintptr_t addr);
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* FillBlock(dynablock_t* block, uintptr_t addr) {
dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
if(addr>=box86_nodynarec_start && addr<box86_nodynarec_end) {
dynarec_log(LOG_DEBUG, "Asked to fill a block in fobidden zone\n");
return NULL;
}
if(!isJumpTableDefault((void*)addr)) {
dynarec_log(LOG_DEBUG, "Asked to fill a block at %p, but JumpTable is not default\n", (void*)addr);
return NULL;
}
// init the helper
dynarec_arm_t helper = {0};
helper.nolinker = box86_dynarec_linker?(block->parent->nolinker):1;
helper.start = addr;
arm_pass0(&helper, addr);
uintptr_t start = addr;
uintptr_t end = arm_pass0(&helper, addr);
if(!helper.size) {
dynarec_log(LOG_DEBUG, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
block->done = 1;
@@ -324,11 +333,12 @@ void* FillBlock(dynablock_t* block, uintptr_t addr) {
}
helper.cap = helper.size+3; // needs epilog handling
helper.insts = (instruction_arm_t*)calloc(helper.cap, sizeof(instruction_arm_t));
// already protect the block and compute hash signature
protectDB(addr, end-addr+1);
uint32_t hash = X31_hash_code((void*)addr, end-addr+1);
// pass 1, addresses, x86 jump addresses, flags
arm_pass1(&helper, addr);
// calculate barriers
uintptr_t start = helper.insts[0].x86.addr;
uintptr_t end = helper.insts[helper.size].x86.addr+helper.insts[helper.size].x86.size;
for(int i=0; i<helper.size; ++i)
if(helper.insts[i].x86.jmp) {
uintptr_t j = helper.insts[i].x86.jmp;
@@ -366,16 +376,13 @@ void* FillBlock(dynablock_t* block, uintptr_t addr) {
}
helper.block = p;
helper.arm_start = (uintptr_t)p;
helper.tablesz = helper.tablei;
if(helper.tablesz)
helper.table = (uintptr_t*)calloc(helper.tablesz, sizeof(uintptr_t));
if(helper.sons_size) {
helper.sons_x86 = (uintptr_t*)calloc(helper.sons_size, sizeof(uintptr_t));
helper.sons_arm = (void**)calloc(helper.sons_size, sizeof(void*));
}
// pass 3, emit (log emit arm opcode)
if(box86_dynarec_dump) {
dynarec_log(LOG_NONE, "%sEmitting %d bytes for %d x86 bytes", (box86_dynarec_dump>1)?"\e[01;36m":"", helper.arm_size, helper.isize);
dynarec_log(LOG_NONE, "%s%04d|Emitting %d bytes for %d x86 bytes", (box86_dynarec_dump>1)?"\e[01;36m":"", GetTID(), helper.arm_size, helper.isize);
printFunctionAddr(helper.start, " => ");
dynarec_log(LOG_NONE, "%s\n", (box86_dynarec_dump>1)?"\e[m":"");
}
@@ -409,20 +416,23 @@ void* FillBlock(dynablock_t* block, uintptr_t addr) {
// ok, free the helper now
free(helper.insts);
free(helper.next);
block->table = helper.table;
block->tablesz = helper.tablesz;
for (int i=0; i<helper.tablesz/4; ++i)
block->table[i*4+2] = (uintptr_t)block;
block->size = sz;
block->isize = helper.size;
block->block = p;
block->nolinker = helper.nolinker;
block->need_test = 0;
//block->x86_addr = (void*)start;
block->x86_size = end-start;
block->x86_size = end-start+1;
if(box86_dynarec_largest<block->x86_size)
box86_dynarec_largest = block->x86_size;
block->hash = (helper.nolinker)?X31_hash_code(block->x86_addr, block->x86_size):0;
block->hash = X31_hash_code(block->x86_addr, block->x86_size);
// Check if something changed, to abbort if it as
if(block->hash != hash) {
dynarec_log(LOG_INFO, "Warning, a block changed while beeing processed hash(%p:%d)=%x/%x\n", block->x86_addr, block->x86_size, block->hash, hash);
free(helper.sons_x86);
free(helper.sons_arm);
FreeDynarecMap(block, (uintptr_t)p, sz);
return NULL;
}
// fill sons if any
dynablock_t** sons = NULL;
int sons_size = 0;
@@ -431,10 +441,10 @@ void* FillBlock(dynablock_t* block, uintptr_t addr) {
for (int i=0; i<helper.sons_size; ++i) {
int created = 1;
dynablock_t *son = AddNewDynablock(block->parent, helper.sons_x86[i], &created);
if(created || !son->parent) { // avoid breaking a working block! also, block could be outside this parent...
if(created) { // avoid breaking a working block!
son->block = helper.sons_arm[i];
son->x86_addr = (void*)helper.sons_x86[i];
son->x86_size = end-helper.sons_x86[i];
son->x86_size = end-helper.sons_x86[i]+1;
if(!son->x86_size) {printf_log(LOG_NONE, "Warning, son with null x86 size! (@%p / ARM=%p)", son->x86_addr, son->block);}
son->father = block;
son->done = 1;
+63 -88
View File
@@ -112,7 +112,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETEB(x1);
GETGB(x2);
emit_or8(dyn, ninst, x1, x2, x14, x3, (wb1 && (wback==x3))?1:0);
emit_or8(dyn, ninst, x1, x2, x14, x2);
EBBACK;
break;
case 0x09:
@@ -130,7 +130,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETEB(x2);
GETGB(x1);
emit_or8(dyn, ninst, x1, x2, x3, x14, 0);
emit_or8(dyn, ninst, x1, x2, x3, x14);
GBBACK;
break;
case 0x0B:
@@ -290,7 +290,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETEB(x1);
GETGB(x2);
emit_and8(dyn, ninst, x1, x2, x14, x3, (wb1 && (wback==x3))?1:0);
emit_and8(dyn, ninst, x1, x2, x14, x2);
EBBACK;
break;
case 0x21:
@@ -308,7 +308,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETEB(x2);
GETGB(x1);
emit_and8(dyn, ninst, x1, x2, x3, x14, 0);
emit_and8(dyn, ninst, x1, x2, x3, x14);
GBBACK;
break;
case 0x23:
@@ -412,7 +412,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETEB(x1);
GETGB(x2);
emit_xor8(dyn, ninst, x1, x2, x14, x3, (wb1 && (wback==x3))?1:0);
emit_xor8(dyn, ninst, x1, x2, x14, x2);
EBBACK;
break;
case 0x31:
@@ -430,7 +430,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETEB(x2);
GETGB(x1);
emit_xor8(dyn, ninst, x1, x2, x3, x14, 0);
emit_xor8(dyn, ninst, x1, x2, x3, x14);
GBBACK;
break;
case 0x33:
@@ -696,7 +696,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
/* out of the block */ \
i32 = dyn->insts[ninst+1].address-(dyn->arm_size+8); \
Bcond(NO, i32); \
jump_to_linker(dyn, addr+i8, 0, ninst); \
jump_to_next(dyn, addr+i8, 0, ninst); \
} else { \
/* inside the block */ \
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
@@ -767,34 +767,28 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 0x7C:
INST_NAME("JL ib");
GO( UBFX(x2, xFlags, F_SF, 1);
UBFX(x1, xFlags, F_OF, 1);
CMPS_REG_LSL_IMM5(x1, x2, 0)
GO( XOR_REG_LSL_IMM5(x1, xFlags, xFlags, F_OF-F_SF);
TSTS_IMM8_ROR(x1, 0b10, 0x0b)
, cEQ, cNE, X_SF|X_OF)
break;
case 0x7D:
INST_NAME("JGE ib");
GO( UBFX(x2, xFlags, F_SF, 1);
UBFX(x1, xFlags, F_OF, 1);
CMPS_REG_LSL_IMM5(x1, x2, 0)
GO( XOR_REG_LSL_IMM5(x1, xFlags, xFlags, F_OF-F_SF);
TSTS_IMM8_ROR(x1, 0b10, 0x0b)
, cNE, cEQ, X_SF|X_OF)
break;
case 0x7E:
INST_NAME("JLE ib");
GO( UBFX(x2, xFlags, F_SF, 1);
UBFX(x1, xFlags, F_OF, 1);
XOR_REG_LSL_IMM5(x1, x1, x2, 0);
UBFX(x2, xFlags, F_ZF, 1);
ORRS_REG_LSL_IMM5(x2, x1, x2, 0);
GO( XOR_REG_LSL_IMM5(x1, xFlags, xFlags, F_OF-F_SF);
ORR_REG_LSL_IMM5(x1, x1, xFlags, F_OF-F_ZF);
TSTS_IMM8_ROR(x1, 0b10, 0x0b)
, cEQ, cNE, X_SF|X_OF|X_ZF)
break;
case 0x7F:
INST_NAME("JG ib");
GO( UBFX(x2, xFlags, F_SF, 1);
UBFX(x1, xFlags, F_OF, 1);
XOR_REG_LSL_IMM5(x1, x1, x2, 0);
UBFX(x2, xFlags, F_ZF, 1);
ORRS_REG_LSL_IMM5(x2, x1, x2, 0);
GO( XOR_REG_LSL_IMM5(x1, xFlags, xFlags, F_OF-F_SF);
ORR_REG_LSL_IMM5(x1, x1, xFlags, F_OF-F_ZF);
TSTS_IMM8_ROR(x1, 0b10, 0x0b)
, cNE, cEQ, X_SF|X_OF|X_ZF)
break;
#undef GO
@@ -944,21 +938,12 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
if(opcode==0x81) {INST_NAME("CMP Ed, Id");} else {INST_NAME("CMP Ed, Ib");}
SETFLAGS(X_ALL, SF_SET);
GETEDH(x1);
if(opcode==0x81 /*&& fmod_smc_start && ip>=fmod_smc_start && ip<=fmod_smc_end*/) {
//In libfmod from Unreal, there can be some SMC here, so getching the address instead of using a constant...
// there are some other cases too, so it's safer to use the generic one
MOV32(x2, addr);
addr+=4;
LDR_IMM9(x2, x2, 0);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
if(i32) {
MOV32(x2, i32);
emit_cmp32(dyn, ninst, ed, x2, x3, x14);
} else {
if(opcode==0x81) i32 = F32S; else i32 = F8S;
if(i32) {
MOV32(x2, i32);
emit_cmp32(dyn, ninst, ed, x2, x3, x14);
} else {
emit_cmp32_0(dyn, ninst, ed, x3, x14);
}
emit_cmp32_0(dyn, ninst, ed, x3, x14);
}
break;
}
@@ -1120,7 +1105,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
if((nextop&0xC0)==0xC0) { // reg <= reg? that's an invalid operation
DEFAULT;
} else { // mem <= reg
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, gd, &fixedaddress, 0, 0);
if(gd!=ed) { // it's sometimes used as a 3 bytes NOP
MOV_REG(gd, ed);
}
@@ -1228,7 +1213,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
BFI(xEAX, x2, 0, 8);
break;
case 0xA1:
INST_NAME("MOV, EAX, Od");
INST_NAME("MOV EAX, Od");
u32 = F32;
MOV32(x2, u32);
LDR_IMM9(xEAX, x2, 0);
@@ -1490,7 +1475,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 4:
case 6:
INST_NAME("SHL Ed, Ib");
SETFLAGS(X_CF|X_ZF|X_PF|X_SF|X_OF, SF_SUBSET);
SETFLAGS(X_ALL, SF_SET); // some flags are left undefined
GETED;
u8 = (F8)&0x1f;
emit_shl32c(dyn, ninst, ed, u8, x3, x14);
@@ -1498,7 +1483,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 5:
INST_NAME("SHR Ed, Ib");
SETFLAGS(X_CF|X_ZF|X_PF|X_SF|X_OF, SF_SUBSET);
SETFLAGS(X_ALL, SF_SET); // some flags are left undefined
GETED;
u8 = (F8)&0x1f;
emit_shr32c(dyn, ninst, ed, u8, x3, x14);
@@ -1508,7 +1493,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 7:
INST_NAME("SAR Ed, Ib");
SETFLAGS(X_CF|X_ZF|X_PF|X_SF, SF_SUBSET);
SETFLAGS(X_ALL, SF_SET); // some flags are left undefined
GETED;
u8 = (F8)&0x1f;
emit_sar32c(dyn, ninst, ed, u8, x3, x14);
@@ -1516,12 +1501,8 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
WBACK;
}
break;
default:
INST_NAME("GRP3 Ed, Ib");
DEFAULT;
}
break;
case 0xC2:
INST_NAME("RETN");
//SETFLAGS(X_ALL, SF_SET); // Hack, set all flags (to an unknown state...)
@@ -1796,21 +1777,21 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 4:
case 6:
INST_NAME("SHL Ed, 1");
SETFLAGS(X_CF|X_ZF|X_PF|X_SF|X_OF, SF_SUBSET);
SETFLAGS(X_ALL, SF_SET); // some flags are left undefined
GETED;
emit_shl32c(dyn, ninst, ed, 1, x3, x14);
WBACK;
break;
case 5:
INST_NAME("SHR Ed, 1");
SETFLAGS(X_CF|X_ZF|X_PF|X_SF|X_OF, SF_SUBSET);
SETFLAGS(X_ALL, SF_SET); // some flags are left undefined
GETED;
emit_shr32c(dyn, ninst, ed, 1, x3, x14);
WBACK;
break;
case 7:
INST_NAME("SAR Ed, 1");
SETFLAGS(X_CF|X_ZF|X_PF|X_SF, SF_SUBSET);
SETFLAGS(X_ALL, SF_SET); // some flags are left undefined
GETED;
emit_sar32c(dyn, ninst, ed, 1, x3, x14);
WBACK;
@@ -1827,7 +1808,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
TSTS_REG_LSL_IMM5(x3, x3, 0);
B_MARK2(cEQ);
RSB_IMM8(x3, x3, 0x20);
GETEDW(x14, x2);
GETED;
MOV_REG_ROR_REG(ed, ed, x3);
WBACK;
UFLAG_IF { // calculate flags directly
@@ -1848,7 +1829,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
AND_IMM8(x3, xECX, 0x1f);
TSTS_REG_LSL_IMM5(x3, x3, 0);
B_MARK2(cEQ);
GETEDW(x14, x2);
GETED;
MOV_REG_ROR_REG(ed, ed, x3);
WBACK;
UFLAG_IF { // calculate flags directly
@@ -1867,7 +1848,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 2:
INST_NAME("RCL Ed, CL");
READFLAGS(X_CF);
SETFLAGS(X_OF|X_CF, SF_SET);
SETFLAGS(X_OF|X_CF, SF_SUBSET);
AND_IMM8(x2, xECX, 0x1f);
GETEDW(x14, x1);
CALL_(rcl32, ed, (1<<x14));
@@ -1876,7 +1857,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 3:
INST_NAME("RCR Ed, CL");
READFLAGS(X_CF);
SETFLAGS(X_OF|X_CF, SF_SET);
SETFLAGS(X_OF|X_CF, SF_SUBSET);
AND_IMM8(x2, xECX, 0x1f);
GETEDW(x14, x1);
CALL_(rcr32, ed, (1<<x14));
@@ -1885,25 +1866,19 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 4:
case 6:
INST_NAME("SHL Ed, CL");
SETFLAGS(X_ALL, SF_PENDING);
SETFLAGS(X_ALL, SF_SET); // some flags are left undefined
AND_IMM8(x3, xECX, 0x1f);
GETED;
UFLAG_OP12(ed, x3);
MOV_REG_LSL_REG(ed, ed, x3);
emit_shl32(dyn, ninst, ed, x3, x3, x14);
WBACK;
UFLAG_RES(ed);
UFLAG_DF(x3, d_shl32);
break;
case 5:
INST_NAME("SHR Ed, CL");
SETFLAGS(X_ALL, SF_PENDING);
SETFLAGS(X_ALL, SF_SET); // some flags are left undefined
AND_IMM8(x3, xECX, 0x1f);
GETED;
UFLAG_OP12(ed, x3);
MOV_REG_LSR_REG(ed, ed, x3);
emit_shr32(dyn, ninst, ed, x3, x3, x14);
WBACK;
UFLAG_RES(ed);
UFLAG_DF(x3, d_shr32);
break;
case 7:
INST_NAME("SAR Ed, CL");
@@ -1982,7 +1957,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
/* out of the block */ \
i32 = dyn->insts[ninst+1].address-(dyn->arm_size+8); \
Bcond(NO, i32); \
jump_to_linker(dyn, addr+i8, 0, ninst); \
jump_to_next(dyn, addr+i8, 0, ninst); \
} else { \
/* inside the block */ \
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
@@ -2026,11 +2001,11 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
i32 = F32S;
if(addr+i32==0) {
#if STEP == 3
printf_log(LOG_NONE, "Warning, CALL to 0x0 at %p (%p)\n", (void*)addr, (void*)(addr-1));
printf_log(LOG_INFO, "Warning, CALL to 0x0 at %p (%p)\n", (void*)addr, (void*)(addr-1));
#endif
}
#if STEP == 0
if ((i32==0) && ((PK(0)>=0x58) && (PK(0)<=0x5F)))
if (i32==0)
tmp = 1;
else if (((addr+i32)>0x10000) && (PK(i32+0)==0x8B) && (((PK(i32+1))&0xC7)==0x04) && (PK(i32+2)==0x24) && (PK(i32+3)==0xC3))
tmp = 2;
@@ -2039,7 +2014,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
else
tmp = 0;
#elif STEP < 2
if ((i32==0) && ((PK(0)>=0x58) && (PK(0)<=0x5F)))
if (i32==0)
tmp = dyn->insts[ninst].pass2choice = 1;
else if (((addr+i32)>0x10000) && (PK(i32+0)==0x8B) && (((PK(i32+1))&0xC7)==0x04) && (PK(i32+2)==0x24) && (PK(i32+3)==0xC3))
tmp = dyn->insts[ninst].pass2choice = 2;
@@ -2053,13 +2028,12 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
switch(tmp) {
case 1:
//SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
MESSAGE(LOG_DUMP, "Hack for Call 0, Pop reg\n");
u8 = F8;
gd = xEAX+(u8&7);
MOV32(gd, addr-1);
MESSAGE(LOG_DUMP, "Hack for Call 0\n");
MOV32(xEIP, addr);
PUSH1(xEIP);
break;
case 2:
SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
//SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state
MESSAGE(LOG_DUMP, "Hack for Call x86.get_pc_thunk.reg\n");
u8 = PK(i32+1);
gd = xEAX+((u8&0x38)>>3);
@@ -2074,7 +2048,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
MESSAGE(LOG_DUMP, "Native Call to %s (retn=%d)\n", GetNativeName(GetNativeFnc(dyn->insts[ninst].natcall-1)), dyn->insts[ninst].retn);
// calling a native function
x87_forget(dyn, ninst, x3, x14, 0);
MOV32(x14, dyn->insts[ninst].natcall); // read the 0xCC already
MOV32(xEIP, dyn->insts[ninst].natcall); // read the 0xCC already
STM(xEmu, (1<<xEAX)|(1<<xEBX)|(1<<xECX)|(1<<xEDX)|(1<<xESI)|(1<<xEDI)|(1<<xESP)|(1<<xEBP)|(1<<xEIP)|(1<<xFlags));
CALL_S(x86Int3, -1, 0);
LDM(xEmu, (1<<xEAX)|(1<<xEBX)|(1<<xECX)|(1<<xEDX)|(1<<xESI)|(1<<xEDI)|(1<<xESP)|(1<<xEBP)|(1<<xEIP)|(1<<xFlags));
@@ -2103,22 +2077,18 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
// regular call
BARRIER(1);
BARRIER_NEXT(1);
if(!dyn->nolinker && (!dyn->insts || ninst!=dyn->size-1)) {
PASS2(cstack_push(dyn, ninst, addr, dyn->insts[ninst+1].address, x1, x2);)
//cstatck_push put addr in x2, don't need to put it again
} else {
PASS2(cstack_push(dyn, ninst, 0, 0, x1, x2);)
if(!dyn->insts || ninst==dyn->size-1) {
*need_epilog = 0;
*ok = 0;
MOV32(x2, addr);
}
MOV32(x2, addr);
PUSH1(x2);
if(addr+i32==0) { // self modifying code maybe? so use indirect address fetching
MOV32(x14, addr-4);
LDR_IMM9(x14, x14, 0);
jump_to_next(dyn, 0, x14, ninst);
} else
jump_to_linker(dyn, addr+i32, 0, ninst);
jump_to_next(dyn, addr+i32, 0, ninst);
break;
}
break;
@@ -2136,7 +2106,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
if(dyn->insts) {
PASS2IF(dyn->insts[ninst].x86.jmp_insts==-1, 1) {
// out of the block
jump_to_linker(dyn, addr+i32, 0, ninst);
jump_to_next(dyn, addr+i32, 0, ninst);
} else {
// inside the block
tmp = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8);
@@ -2240,6 +2210,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0x7D:
case 0x7E:
case 0x7F:
case 0x80:
case 0x9C:
case 0xE8:
case 0xE9:
@@ -2445,9 +2416,16 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 2:
INST_NAME("NOT Eb");
GETEB(x1);
MVN_REG_LSL_IMM5(x1, x1, 0);
EBBACK;
if((nextop&0xC0)==0xC0) {
wback = (nextop&7);
wb2 = (wback>>2);
wback = xEAX+(wback&3);
XOR_IMM8_ROR(wback, wback, 0xff, wb2?12:0);
} else {
GETEB(x1);
MVN_REG_LSL_IMM5(x1, x1, 0);
EBBACK;
}
break;
case 3:
INST_NAME("NEG Eb");
@@ -2639,14 +2617,11 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
GETEDH(xEIP);
BARRIER(1);
BARRIER_NEXT(1);
if(!dyn->nolinker && (!dyn->insts || ninst!=dyn->size-1)) {
PASS2(cstack_push(dyn, ninst, addr, dyn->insts[ninst+1].address, x1, x2);)
} else {
PASS2(cstack_push(dyn, ninst, 0, 0, x1, x2);)
if(!dyn->insts || ninst==dyn->size-1) {
*need_epilog = 0;
*ok = 0;
MOV32(x2, addr);
}
MOV32(x2, addr);
PUSH1(x2);
jump_to_next(dyn, 0, ed, ninst);
break;
+89 -117
View File
@@ -37,10 +37,10 @@
}
#define GETGM(a) \
gd = (nextop&0x38)>>3; \
a = mmx_get_reg(dyn, ninst, x1, gd)
a = mmx_get_reg(dyn, ninst, x1, x2, x3, gd)
#define GETEM(a) \
if((nextop&0xC0)==0xC0) { \
a = mmx_get_reg(dyn, ninst, x1, nextop&7); \
a = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7); \
} else { \
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0); \
a = fpu_get_scratch_double(dyn); \
@@ -210,7 +210,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
VST1_32(v0+1, ed); // better to use VST1 than VSTR_64, to avoid NEON->VFPU transfert I assume
VST1_64(v0+1, ed); // better to use VST1 than VSTR_64, to avoid NEON->VFPU transfert I assume
} else {
VMOVfrV_D(x2, x3, v0+1);
@@ -284,7 +284,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
if((nextop&0xC0)==0xC0) {
v1 = mmx_get_reg(dyn, ninst, x1, nextop&7);
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
v1 = fpu_get_scratch_double(dyn);
@@ -309,7 +309,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
INST_NAME("CVTTPS2PI Gm, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = mmx_get_reg_empty(dyn, ninst, x1, gd);
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
if((nextop&0xC0)==0xC0) {
v1 = sse_get_reg(dyn, ninst, x1, nextop&7);
} else {
@@ -323,7 +323,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
INST_NAME("CVTPS2PI Gm, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = mmx_get_reg_empty(dyn, ninst, x1, gd);
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
if((nextop&0xC0)==0xC0) {
v1 = sse_get_reg(dyn, ninst, x1, nextop&7);
} else {
@@ -341,7 +341,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
d0 = v0;
else
d0 = fpu_get_scratch_double(dyn);
u8 = x87_setround(dyn, ninst, x1, x2, x14);
u8 = sse_setround(dyn, ninst, x1, x2, x14);
VCVTR_S32_F32(d0*2, d1*2);
VCVTR_S32_F32(d0*2+1, d1*2+1);
if(v0>=16) {
@@ -507,34 +507,28 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 0x4C:
INST_NAME("CMOVL Gd, Ed");
GO( UBFX(x2, xFlags, F_SF, 1);
UBFX(x1, xFlags, F_OF, 1);
CMPS_REG_LSL_IMM5(x1, x2, 0)
GO( XOR_REG_LSL_IMM5(x1, xFlags, xFlags, F_OF-F_SF);
TSTS_IMM8_ROR(x1, 0b10, 0x0b)
, cEQ, cNE, X_SF|X_OF)
break;
case 0x4D:
INST_NAME("CMOVGE Gd, Ed");
GO( UBFX(x2, xFlags, F_SF, 1);
UBFX(x1, xFlags, F_OF, 1);
CMPS_REG_LSL_IMM5(x1, x2, 0)
GO( XOR_REG_LSL_IMM5(x1, xFlags, xFlags, F_OF-F_SF);
TSTS_IMM8_ROR(x1, 0b10, 0x0b)
, cNE, cEQ, X_SF|X_OF)
break;
case 0x4E:
INST_NAME("CMOVLE Gd, Ed");
GO( UBFX(x2, xFlags, F_SF, 1);
UBFX(x1, xFlags, F_OF, 1);
XOR_REG_LSL_IMM5(x1, x1, x2, 0);
UBFX(x2, xFlags, F_ZF, 1);
ORRS_REG_LSL_IMM5(x2, x1, x2, 0);
GO( XOR_REG_LSL_IMM5(x1, xFlags, xFlags, F_OF-F_SF);
ORR_REG_LSL_IMM5(x1, x1, xFlags, F_OF-F_ZF);
TSTS_IMM8_ROR(x1, 0b10, 0x0b)
, cEQ, cNE, X_SF|X_OF|X_ZF)
break;
case 0x4F:
INST_NAME("CMOVG Gd, Ed");
GO( UBFX(x2, xFlags, F_SF, 1);
UBFX(x1, xFlags, F_OF, 1);
XOR_REG_LSL_IMM5(x1, x1, x2, 0);
UBFX(x2, xFlags, F_ZF, 1);
ORRS_REG_LSL_IMM5(x2, x1, x2, 0);
GO( XOR_REG_LSL_IMM5(x1, xFlags, xFlags, F_OF-F_SF);
ORR_REG_LSL_IMM5(x1, x1, xFlags, F_OF-F_ZF);
TSTS_IMM8_ROR(x1, 0b10, 0x0b)
, cNE, cEQ, X_SF|X_OF|X_ZF)
break;
#undef GO
@@ -806,7 +800,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
GETGM(d0);
q0 = fpu_get_scratch_quad(dyn);
if((nextop&0xC0)==0xC0) {
d1 = mmx_get_reg(dyn, ninst, x1, nextop&7);
d1 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7);
VMOVD(q0+1, d1);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
@@ -867,7 +861,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETED;
gd = (nextop&0x38)>>3;
v0 = mmx_get_reg_empty(dyn, ninst, x3, gd);
v0 = mmx_get_reg_empty(dyn, ninst, x2, x3, x14, gd);
VEOR(v0, v0, v0);
VMOVtoDx_32(v0, 0, ed);
break;
@@ -876,11 +870,11 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
gd = (nextop&0x38)>>3;
if((nextop&0xC0)==0xC0) {
v1 = mmx_get_reg(dyn, ninst, x1, nextop&7);
v0 = mmx_get_reg_empty(dyn, ninst, x1, gd);
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7);
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
VMOVD(v0, v1);
} else {
v0 = mmx_get_reg_empty(dyn, ninst, x1, gd);
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
VLD1_64(v0, ed);
}
@@ -890,10 +884,10 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
gd = (nextop&0x38)>>3;
i32 = -1;
v0 = mmx_get_reg(dyn, ninst, x1, gd);
v0 = mmx_get_reg(dyn, ninst, x1, x2, x3, gd);
if((nextop&0xC0)==0xC0) {
u8 = F8;
v1 = mmx_get_reg(dyn, ninst, x1, nextop&7);
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7);
// use stack as temporary storage
SUB_IMM8(xSP, xSP, 4);
if(v1==v0) {
@@ -937,7 +931,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 2:
INST_NAME("PSRLW Em, Ib");
if((nextop&0xC0)==0xC0) {
d0 = mmx_get_reg(dyn, ninst, x1, nextop&7);
d0 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
d0 = fpu_get_scratch_quad(dyn);
@@ -958,7 +952,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 4:
INST_NAME("PSRAW Em, Ib");
if((nextop&0xC0)==0xC0) {
d0 = mmx_get_reg(dyn, ninst, x1, nextop&7);
d0 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
d0 = fpu_get_scratch_quad(dyn);
@@ -975,7 +969,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 6:
INST_NAME("PSLLW Em, Ib");
if((nextop&0xC0)==0xC0) {
d0 = mmx_get_reg(dyn, ninst, x1, nextop&7);
d0 = mmx_get_reg(dyn, ninst, x1, x2, x3, nextop&7);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
d0 = fpu_get_scratch_quad(dyn);
@@ -1091,8 +1085,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0x77:
INST_NAME("EMMS");
// empty MMX, FPU now usable
/*emu->top = 0;
emu->fpu_stack = 0;*/ //TODO: Check if something is needed here?
mmx_purgecache(dyn, ninst, x1);
break;
case 0x7E:
@@ -1113,7 +1106,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETGM(v0);
if((nextop&0xC0)==0xC0) {
v1 = mmx_get_reg_empty(dyn, ninst, x1, nextop&7);
v1 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, nextop&7);
VMOVD(v1, v0);
} else {
parity = getedparity(dyn, ninst, addr, nextop, 3);
@@ -1140,7 +1133,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
/* out of the block */ \
i32 = dyn->insts[ninst+1].address-(dyn->arm_size+8); \
Bcond(NO, i32); \
jump_to_linker(dyn, addr+i32_, 0, ninst); \
jump_to_next(dyn, addr+i32_, 0, ninst); \
} else { \
/* inside the block */ \
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
@@ -1210,34 +1203,28 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 0x8C:
INST_NAME("JL id");
GO( UBFX(x2, xFlags, F_SF, 1);
UBFX(x1, xFlags, F_OF, 1);
CMPS_REG_LSL_IMM5(x1, x2, 0)
GO( XOR_REG_LSL_IMM5(x1, xFlags, xFlags, F_OF-F_SF);
TSTS_IMM8_ROR(x1, 0b10, 0x0b)
, cEQ, cNE, X_SF|X_OF)
break;
case 0x8D:
INST_NAME("JGE id");
GO( UBFX(x2, xFlags, F_SF, 1);
UBFX(x1, xFlags, F_OF, 1);
CMPS_REG_LSL_IMM5(x1, x2, 0)
GO( XOR_REG_LSL_IMM5(x1, xFlags, xFlags, F_OF-F_SF);
TSTS_IMM8_ROR(x1, 0b10, 0x0b)
, cNE, cEQ, X_SF|X_OF)
break;
case 0x8E:
INST_NAME("JLE id");
GO( UBFX(x2, xFlags, F_SF, 1);
UBFX(x1, xFlags, F_OF, 1);
XOR_REG_LSL_IMM5(x1, x1, x2, 0);
UBFX(x2, xFlags, F_ZF, 1);
ORRS_REG_LSL_IMM5(x2, x1, x2, 0);
GO( XOR_REG_LSL_IMM5(x1, xFlags, xFlags, F_OF-F_SF);
ORR_REG_LSL_IMM5(x1, x1, xFlags, F_OF-F_ZF);
TSTS_IMM8_ROR(x1, 0b10, 0x0b)
, cEQ, cNE, X_SF|X_OF|X_ZF)
break;
case 0x8F:
INST_NAME("JG id");
GO( UBFX(x2, xFlags, F_SF, 1);
UBFX(x1, xFlags, F_OF, 1);
XOR_REG_LSL_IMM5(x1, x1, x2, 0);
UBFX(x2, xFlags, F_ZF, 1);
ORRS_REG_LSL_IMM5(x2, x1, x2, 0);
GO( XOR_REG_LSL_IMM5(x1, xFlags, xFlags, F_OF-F_SF);
ORR_REG_LSL_IMM5(x1, x1, xFlags, F_OF-F_ZF);
TSTS_IMM8_ROR(x1, 0b10, 0x0b)
, cNE, cEQ, X_SF|X_OF|X_ZF)
break;
#undef GO
@@ -1319,34 +1306,28 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 0x9C:
INST_NAME("SETL Eb");
GO( UBFX(x2, xFlags, F_SF, 1);
UBFX(x1, xFlags, F_OF, 1);
CMPS_REG_LSL_IMM5(x1, x2, 0)
GO( XOR_REG_LSL_IMM5(x1, xFlags, xFlags, F_OF-F_SF);
TSTS_IMM8_ROR(x1, 0b10, 0x0b)
, cEQ, cNE, X_SF|X_OF)
break;
case 0x9D:
INST_NAME("SETGE Eb");
GO( UBFX(x2, xFlags, F_SF, 1);
UBFX(x1, xFlags, F_OF, 1);
CMPS_REG_LSL_IMM5(x1, x2, 0)
GO( XOR_REG_LSL_IMM5(x1, xFlags, xFlags, F_OF-F_SF);
TSTS_IMM8_ROR(x1, 0b10, 0x0b)
, cNE, cEQ, X_SF|X_OF)
break;
case 0x9E:
INST_NAME("SETLE Eb");
GO( UBFX(x2, xFlags, F_SF, 1);
UBFX(x1, xFlags, F_OF, 1);
XOR_REG_LSL_IMM5(x1, x1, x2, 0);
UBFX(x2, xFlags, F_ZF, 1);
ORRS_REG_LSL_IMM5(x2, x1, x2, 0);
GO( XOR_REG_LSL_IMM5(x1, xFlags, xFlags, F_OF-F_SF);
ORR_REG_LSL_IMM5(x1, x1, xFlags, F_OF-F_ZF);
TSTS_IMM8_ROR(x1, 0b10, 0x0b)
, cEQ, cNE, X_SF|X_OF|X_ZF)
break;
case 0x9F:
INST_NAME("SETG Eb");
GO( UBFX(x2, xFlags, F_SF, 1);
UBFX(x1, xFlags, F_OF, 1);
XOR_REG_LSL_IMM5(x1, x1, x2, 0);
UBFX(x2, xFlags, F_ZF, 1);
ORRS_REG_LSL_IMM5(x2, x1, x2, 0);
GO( XOR_REG_LSL_IMM5(x1, xFlags, xFlags, F_OF-F_SF);
ORR_REG_LSL_IMM5(x1, x1, xFlags, F_OF-F_ZF);
TSTS_IMM8_ROR(x1, 0b10, 0x0b)
, cNE, cEQ, X_SF|X_OF|X_ZF)
break;
#undef GO
@@ -1656,10 +1637,10 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
ed = xEAX+(nextop&7);
u8 = F8;
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 4095-32, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095-32, 0);
u8 = F8;
fixedaddress+=(u8>>5)*4;
LDR_IMM9(x1, ed, fixedaddress);
LDR_IMM9(x1, wback, fixedaddress);
ed = x1;
}
u8&=0x1f;
@@ -1672,29 +1653,23 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 5:
INST_NAME("BTS Ed, Ib");
SETFLAGS(X_CF, SF_SUBSET);
gd = x2;
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
u8 = F8;
MOVW(gd, u8);
wback = 0;
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 4095, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095-32, 0);
u8 = F8;
MOVW(gd, u8);
UBFX(x1, gd, 5, 3); // r1 = (gd>>5);
ADD_REG_LSL_IMM5(x3, ed, x1, 2); //(&ed)+=r1*4;
LDR_IMM9(x1, x3, fixedaddress);
fixedaddress+=(u8>>5)*4;
LDR_IMM9(x1, wback, fixedaddress);
ed = x1;
wback = x3;
}
AND_IMM8(x2, gd, 0x1f);
MOV_REG_LSR_REG(x14, ed, x2);
MOV_REG_LSR_IMM5(x14, ed, u8&0x1f);
ANDS_IMM8(x14, x14, 1);
BFI(xFlags, x14, F_CF, 1);
B_MARK3(cNE); // bit already set, jump to next instruction
MOVW(x14, 1);
XOR_REG_LSL_REG(ed, ed, x14, x2);
XOR_REG_LSL_IMM5(ed, ed, x14, u8&0x1f);
if(wback) {
STR_IMM9(ed, wback, fixedaddress);
}
@@ -1703,29 +1678,23 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 6:
INST_NAME("BTR Ed, Ib");
SETFLAGS(X_CF, SF_SUBSET);
gd = x2;
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
u8 = F8;
MOVW(gd, u8);
wback = 0;
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 4095, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095-32, 0);
u8 = F8;
MOVW(gd, u8);
UBFX(x1, gd, 5, 3); // r1 = (gd>>5);
ADD_REG_LSL_IMM5(x3, ed, x1, 2); //(&ed)+=r1*4;
LDR_IMM9(x1, x3, fixedaddress);
fixedaddress+=(u8>>5)*4;
LDR_IMM9(x1, wback, fixedaddress);
ed = x1;
wback = x3;
}
AND_IMM8(x2, gd, 0x1f);
MOV_REG_LSR_REG(x14, ed, x2);
MOV_REG_LSR_IMM5(x14, ed, u8&0x1f);
ANDS_IMM8(x14, x14, 1);
BFI(xFlags, x14, F_CF, 1);
B_MARK3(cEQ); // bit already clear, jump to next instruction
//MOVW(x14, 1); // already 0x01
XOR_REG_LSL_REG(ed, ed, x14, x2);
XOR_REG_LSL_IMM5(ed, ed, x14, u8&0x1f);
if(wback) {
STR_IMM9(ed, wback, fixedaddress);
}
@@ -1734,28 +1703,22 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 7:
INST_NAME("BTC Ed, Ib");
SETFLAGS(X_CF, SF_SUBSET);
gd = x2;
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
u8 = F8;
MOVW(gd, u8);
wback = 0;
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 4095, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095-32, 0);
u8 = F8;
MOVW(gd, u8);
UBFX(x1, gd, 5, 3); // r1 = (gd>>5);
ADD_REG_LSL_IMM5(x3, ed, x1, 2); //(&ed)+=r1*4;
LDR_IMM9(x1, x3, fixedaddress);
fixedaddress+=(u8>>5)*4;
LDR_IMM9(x1, wback, fixedaddress);
ed = x1;
wback = x3;
}
AND_IMM8(x2, gd, 0x1f);
MOV_REG_LSR_REG(x14, ed, x2);
MOV_REG_LSR_IMM5(x14, ed, u8&0x1f);
ANDS_IMM8(x14, x14, 1);
BFI(xFlags, x14, F_CF, 1);
MOVW_COND(cEQ, x14, 1); // may already 0x01
XOR_REG_LSL_REG(ed, ed, x14, x2);
XOR_REG_LSL_IMM5(ed, ed, x14, u8&0x1f);
if(wback) {
STR_IMM9(ed, wback, fixedaddress);
}
@@ -1767,7 +1730,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 0xBB:
INST_NAME("BTC Ed, Gd");
SETFLAGS(X_CF, SF_SET);
SETFLAGS(X_CF, SF_SUBSET);
nextop = F8;
GETGD;
if((nextop&0xC0)==0xC0) {
@@ -1792,7 +1755,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 0xBC:
INST_NAME("BSF Gd, Ed");
SETFLAGS(X_ZF, SF_SET);
SETFLAGS(X_ZF, SF_SUBSET);
nextop = F8;
GETED;
GETGD;
@@ -1808,7 +1771,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 0xBD:
INST_NAME("BSR Gd, Ed");
SETFLAGS(X_ZF, SF_SET);
SETFLAGS(X_ZF, SF_SUBSET);
nextop = F8;
GETED;
GETGD;
@@ -1856,7 +1819,6 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
GETGB(x1);
BFI(gb1, ed, gb2*8, 8); // gb <- eb
emit_add8(dyn, ninst, ed, gd, x14, x3, 1);
ADD_REG_LSL_IMM5(x14, ed, gd, 0);
EBBACK;
break;
case 0xC1:
@@ -1884,19 +1846,23 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0: VCEQQ_F32(v0, v0, v1); break; // Equal
case 1: VCGTQ_F32(v0, v1, v0); break; // Less than
case 2: VCGEQ_F32(v0, v1, v0); break; // Less or equal
case 3: VCEQQ_F32(v0, v0, v0);
q0 = fpu_get_scratch_quad(dyn);
VCEQQ_F32(q0, v1, v1);
VANDQ(v0, v0, q0);
case 3: VCEQQ_F32(v0, v0, v0);
if(v0!=v1) {
q0 = fpu_get_scratch_quad(dyn);
VCEQQ_F32(q0, v1, v1);
VANDQ(v0, v0, q0);
}
VMVNQ(v0, v0);
break; // NaN (NaN is not equal to himself)
case 4: VCEQQ_F32(v0, v0, v1); VMVNQ(v0, v0); break; // Not Equal (or unordered on ARM, not on X86...)
case 5: VCGTQ_F32(v0, v1, v0); VMVNQ(v0, v0); break; // Greater or equal or unordered
case 6: VCGEQ_F32(v0, v1, v0); VMVNQ(v0, v0); break; // Greater or unordered
case 7: VCEQQ_F32(v0, v0, v0);
q0 = fpu_get_scratch_quad(dyn);
VCEQQ_F32(q0, v1, v1);
VANDQ(v0, v0, q0);
if(v0!=v1) {
q0 = fpu_get_scratch_quad(dyn);
VCEQQ_F32(q0, v1, v1);
VANDQ(v0, v0, q0);
}
break; // not NaN
}
break;
@@ -2222,7 +2188,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
if((nextop&0xC0)==0xC0) {
DEFAULT;
} else {
v0 = mmx_get_reg(dyn, ninst, x1, gd);
v0 = mmx_get_reg(dyn, ninst, x1, x2, x3, gd);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
VST1_64(v0, ed);
}
@@ -2366,7 +2332,13 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
GETEM(v1);
VSUB_32(v0, v0, v1);
break;
case 0xFB:
INST_NAME("PSUBQ Gm,Em");
nextop = F8;
GETGM(v0);
GETEM(q0);
VSUB_64(v0, v0, q0);
break;
case 0xFC:
INST_NAME("PADDB Gm, Em");
nextop = F8;
+4 -6
View File
@@ -277,7 +277,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
grab_fsdata(dyn, addr, ninst, x14);
switch((nextop>>3)&7) {
case 2: // CALL Ed
INST_NAME("CALL Ed");
INST_NAME("CALL FS:Ed");
PASS2IF(ninst && dyn->insts && dyn->insts[ninst-1].x86.set_flags, 1) {
READFLAGS(X_PEND); // that's suspicious
} else {
@@ -291,16 +291,14 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
}
BARRIER(1);
BARRIER_NEXT(1);
if(!dyn->nolinker && (!dyn->insts || ninst!=dyn->size-1)) {
PASS2(cstack_push(dyn, ninst, addr, dyn->insts[ninst+1].address, x1, x2);)
if(!dyn->insts || ninst!=dyn->size-1) {
} else {
PASS2(cstack_push(dyn, ninst, 0, 0, x1, x2);)
*need_epilog = 0;
*ok = 0;
MOV32(x2, addr);
}
MOV32(x2, addr);
PUSH1(x2);
jump_to_linker(dyn, 0, xEIP, ninst); // smart linker
jump_to_next(dyn, 0, xEIP, ninst);
break;
case 6: // Push Ed
INST_NAME("PUSH FS:Ed");
+108 -1
View File
@@ -78,6 +78,25 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
emit_cmp32(dyn, ninst, gd, ed, x3, x14);
break;
case 0x69:
INST_NAME("IMUL Gd, GS:Ed, Id");
SETFLAGS(X_ALL, SF_PENDING);
grab_tlsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO(x14);
i32 = F32S;
MOV32(x14, i32);
UFLAG_IF {
SMULL(x3, gd, x14, ed);
UFLAG_OP1(x3);
UFLAG_RES(gd);
UFLAG_DF(x3, d_imul32);
} else {
MUL(gd, ed, x14);
}
break;
case 0x80:
case 0x82:
nextop = F8;
@@ -162,7 +181,95 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
}
break;
case 0x81:
case 0x83:
nextop = F8;
switch((nextop>>3)&7) {
case 0: //ADD
if(opcode==0x81) {
INST_NAME("ADD Ed, Id");
} else {
INST_NAME("ADD Ed, Ib");
}
SETFLAGS(X_ALL, SF_SET);
grab_tlsdata(dyn, addr, ninst, x14);
GETEDO2(x14);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
emit_add32c(dyn, ninst, ed, i32, x3, x14);
WBACK;
break;
case 1: //OR
if(opcode==0x81) {INST_NAME("OR Ed, Id");} else {INST_NAME("OR Ed, Ib");}
SETFLAGS(X_ALL, SF_SET);
grab_tlsdata(dyn, addr, ninst, x14);
GETEDO2(x14);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
emit_or32c(dyn, ninst, ed, i32, x3, x14);
WBACK;
break;
case 2: //ADC
if(opcode==0x81) {INST_NAME("ADC Ed, Id");} else {INST_NAME("ADC Ed, Ib");}
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET);
grab_tlsdata(dyn, addr, ninst, x14);
GETEDO2(x14);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
emit_adc32c(dyn, ninst, ed, i32, x3, x14);
WBACK;
break;
case 3: //SBB
if(opcode==0x81) {INST_NAME("SBB Ed, Id");} else {INST_NAME("SBB Ed, Ib");}
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET);
grab_tlsdata(dyn, addr, ninst, x14);
GETEDO2(x14);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
emit_sbb32c(dyn, ninst, ed, i32, x3, x14);
WBACK;
break;
case 4: //AND
if(opcode==0x81) {INST_NAME("AND Ed, Id");} else {INST_NAME("AND Ed, Ib");}
SETFLAGS(X_ALL, SF_SET);
grab_tlsdata(dyn, addr, ninst, x14);
GETEDO2(x14);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
emit_and32c(dyn, ninst, ed, i32, x3, x14);
WBACK;
break;
case 5: //SUB
if(opcode==0x81) {INST_NAME("SUB Ed, Id");} else {INST_NAME("SUB Ed, Ib");}
SETFLAGS(X_ALL, SF_SET);
grab_tlsdata(dyn, addr, ninst, x14);
GETEDO2(x14);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
emit_sub32c(dyn, ninst, ed, i32, x3, x14);
WBACK;
break;
case 6: //XOR
if(opcode==0x81) {INST_NAME("XOR Ed, Id");} else {INST_NAME("XOR Ed, Ib");}
SETFLAGS(X_ALL, SF_SET);
grab_tlsdata(dyn, addr, ninst, x14);
GETEDO2(x14);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
emit_xor32c(dyn, ninst, ed, i32, x3, x14);
WBACK;
break;
case 7: //CMP
if(opcode==0x81) {INST_NAME("CMP Ed, Id");} else {INST_NAME("CMP Ed, Ib");}
SETFLAGS(X_ALL, SF_SET);
grab_tlsdata(dyn, addr, ninst, x14);
GETEDO2(x14);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
if(i32) {
MOV32(x2, i32);
emit_cmp32(dyn, ninst, ed, x2, x3, x14);
} else {
emit_cmp32_0(dyn, ninst, ed, x3, x14);
}
break;
}
break;
case 0x89:
INST_NAME("MOV GS:Ed, Gd");
grab_tlsdata(dyn, addr, ninst, x14);
+35 -6
View File
@@ -92,7 +92,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETGW(x2);
GETEW(x1);
emit_or16(dyn, ninst, x1, x2, x14, x3, (wb1 && (wback==x3))?1:0);
emit_or16(dyn, ninst, x1, x2, x14, x2);
EWBACK;
break;
case 0x0B:
@@ -101,7 +101,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETGW(x1);
GETEW(x2);
emit_or16(dyn, ninst, x1, x2, x14, x3, 0);
emit_or16(dyn, ninst, x1, x2, x14, x3);
GWBACK;
break;
case 0x0D:
@@ -182,7 +182,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETGW(x2);
GETEW(x1);
emit_and16(dyn, ninst, x1, x2, x14, x3, (wb1 && (wback==x3))?1:0);
emit_and16(dyn, ninst, x1, x2, x14, x2);
EWBACK;
break;
case 0x23:
@@ -191,7 +191,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETGW(x1);
GETEW(x2);
emit_and16(dyn, ninst, x1, x2, x3, x14, 0);
emit_and16(dyn, ninst, x1, x2, x3, x14);
GWBACK;
break;
case 0x25:
@@ -240,7 +240,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETGW(x2);
GETEW(x1);
emit_xor16(dyn, ninst, x1, x2, x14, x3, (wb1 && (wback==x3))?1:0);
emit_xor16(dyn, ninst, x1, x2, x14, x2);
EWBACK;
break;
case 0x33:
@@ -249,7 +249,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETGW(x1);
GETEW(x2);
emit_xor16(dyn, ninst, x1, x2, x3, x14, 0);
emit_xor16(dyn, ninst, x1, x2, x3, x14);
GWBACK;
break;
case 0x35:
@@ -496,6 +496,35 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
emit_test16(dyn, ninst, x1, x2, x3, x14);
break;
case 0x87:
INST_NAME("XCHG Ew, Gw");
nextop = F8;
if((nextop&0xC0)==0xC0) {
GETGW(x14);
ed = xEAX + (nextop&7);
UXTH(x1, ed, 0);
// do the swap 14 -> ed, 1 -> gd
BFI(gd, x1, 0, 16);
BFI(ed, x14, 0, 16);
} else {
GETGW(x14);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
#if 0
MARKLOCK;
// do the swap with exclusive locking
LDREXH(x1, ed);
// do the swap 14 -> strb(ed), 1 -> gd
STREXH(x3, x14, ed);
CMPS_IMM8(x3, 0);
B_MARKLOCK(cNE);
#else
LDRH_IMM8(x1, ed, fixedaddress);
STRH_IMM8(x14, ed, fixedaddress);
#endif
BFI(gd, x1, 0, 16);
}
break;
case 0x89:
INST_NAME("MOV Ew, Gw");
nextop = F8;
+168 -19
View File
@@ -632,6 +632,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
nextop = F8;
GETGX(v0);
GETEX(v1);
// need rounding?
VCVTQ_S32_F32(v0, v1);
break;
case 0x5C:
@@ -650,10 +651,10 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
// MINPD: if any input is NaN, or Ex[i]<Gx[i], copy Ex[i] -> Gx[i]
VCMP_F64(v0, q0);
VMRS_APSR();
VMOVcond_64(cPL, v0, q0);
VMOVcond_64(cCS, v0, q0);
VCMP_F64(v0+1, q0+1);
VMRS_APSR();
VMOVcond_64(cPL, v0+1, q0+1);
VMOVcond_64(cCS, v0+1, q0+1);
break;
case 0x5E:
INST_NAME("DIVPD Gx, Ex");
@@ -671,10 +672,10 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
// MAXPD: if any input is NaN, or Ex[i]>Gx[i], copy Ex[i] -> Gx[i]
VCMP_F64(q0, v0);
VMRS_APSR();
VMOVcond_64(cPL, v0, q0);
VMOVcond_64(cCS, v0, q0);
VCMP_F64(q0+1, v0+1);
VMRS_APSR();
VMOVcond_64(cPL, v0+1, q0+1);
VMOVcond_64(cCS, v0+1, q0+1);
break;
case 0x60:
INST_NAME("PUNPCKLBW Gx,Ex");
@@ -1300,9 +1301,110 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
BFI(gd, x1, 0, 16);
break;
case 0xBA:
nextop = F8;
switch((nextop>>3)&7) {
case 4:
INST_NAME("BT Ew, Ib");
SETFLAGS(X_CF, SF_SUBSET);
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
u8 = F8;
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255-32, 0);
u8 = F8;
fixedaddress+=(u8>>4)*2;
LDRH_IMM8(x1, wback, fixedaddress);
ed = x1;
}
u8&=0x0f;
if(u8) {
MOV_REG_LSR_IMM5(x1, ed, u8);
ed = x1;
}
BFI(xFlags, ed, F_CF, 1);
break;
case 5:
INST_NAME("BTS Ew, Ib");
SETFLAGS(X_CF, SF_SUBSET);
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
u8 = F8;
wback = 0;
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255-32, 0);
u8 = F8;
fixedaddress+=(u8>>4)*2;
LDRH_IMM8(x1, wback, fixedaddress);
ed = x1;
}
MOV_REG_LSR_IMM5(x14, ed, u8&0x0f);
ANDS_IMM8(x14, x14, 1);
BFI(xFlags, x14, F_CF, 1);
B_MARK3(cNE); // bit already set, jump to next instruction
MOVW(x14, 1);
XOR_REG_LSL_IMM5(ed, ed, x14, u8&0x0f);
if(wback) {
STRH_IMM8(ed, wback, fixedaddress);
}
MARK3;
break;
case 6:
INST_NAME("BTR Ew, Ib");
SETFLAGS(X_CF, SF_SUBSET);
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
u8 = F8;
wback = 0;
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255-32, 0);
u8 = F8;
fixedaddress+=(u8>>4)*2;
LDRH_IMM8(x1, wback, fixedaddress);
ed = x1;
}
MOV_REG_LSR_IMM5(x14, ed, u8&0x0f);
ANDS_IMM8(x14, x14, 1);
BFI(xFlags, x14, F_CF, 1);
B_MARK3(cEQ); // bit already clear, jump to next instruction
//MOVW(x14, 1); // already 0x01
XOR_REG_LSL_IMM5(ed, ed, x14, u8&0x0f);
if(wback) {
STRH_IMM8(ed, wback, fixedaddress);
}
MARK3;
break;
case 7:
INST_NAME("BTC Ew, Ib");
SETFLAGS(X_CF, SF_SUBSET);
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
u8 = F8;
wback = 0;
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255-32, 0);
u8 = F8;
fixedaddress+=(u8>>4)*2;
LDRH_IMM8(x1, wback, fixedaddress);
ed = x1;
}
MOV_REG_LSR_IMM5(x14, ed, u8&0x0f);
ANDS_IMM8(x14, x14, 1);
BFI(xFlags, x14, F_CF, 1);
MOVW_COND(cEQ, x14, 1); // may already 0x01
XOR_REG_LSL_IMM5(ed, ed, x14, u8&0x0f);
if(wback) {
STRH_IMM8(ed, wback, fixedaddress);
}
MARK3;
break;
default:
DEFAULT;
}
break;
case 0xBB:
INST_NAME("BTC Ew, Gw");
SETFLAGS(X_CF, SF_SET);
SETFLAGS(X_CF, SF_SUBSET);
nextop = F8;
GETGD; // there is an AND below, to 32bits is the same
GETEW(x14);
@@ -1315,7 +1417,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
break;
case 0xBC:
INST_NAME("BSF Ew,Gw");
SETFLAGS(X_ZF, SF_SET);
SETFLAGS(X_ZF, SF_SUBSET);
nextop = F8;
GETEW(x1); // Get EW
TSTS_REG_LSL_IMM5(x1, x1, 0);
@@ -1331,7 +1433,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
break;
case 0xBD:
INST_NAME("BSR Ew,Gw");
SETFLAGS(X_ZF, SF_SET);
SETFLAGS(X_ZF, SF_SUBSET);
nextop = F8;
GETEW(x1); // Get EW
TSTS_REG_LSL_IMM5(x1, x1, 0);
@@ -1362,6 +1464,16 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
BFI(gd, x1, 0, 16);
break;
case 0xC1:
INST_NAME("XADD Gw, Ew");
SETFLAGS(X_ALL, SF_SET);
nextop = F8;
GETGW(x1);
GETEW(x2);
BFI((xEAX+((nextop&0x38)>>3)), x2, 0, 16); // GW <- EW
emit_add16(dyn, ninst, x1, x2, x14, x3, 1);
EWBACK;
break;
case 0xC2:
INST_NAME("CMPPD Gx, Ex");
nextop = F8;
@@ -1370,32 +1482,40 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
GETEX(d0);
u8 = F8;
// 0
VCMP_F64(v0, d0);
if((u8&7)==6){
VCMP_F64(d0, v0);
} else {
VCMP_F64(v0, d0);
}
VMRS_APSR();
MOVW(x2, 0);
switch(u8&7) {
case 0: MVN_COND_REG_LSL_IMM5(cEQ, x2, x2, 0); break; // Equal
case 1: MVN_COND_REG_LSL_IMM5(cCC, x2, x2, 0); break; // Less than
case 2: MVN_COND_REG_LSL_IMM5(cLS, x2, x2, 0); break; // Less or equal
case 1: MVN_COND_REG_LSL_IMM5(cMI, x2, x2, 0); break; // Less than
case 2: MVN_COND_REG_LSL_IMM5(cLE, x2, x2, 0); break; // Less or equal
case 3: MVN_COND_REG_LSL_IMM5(cVS, x2, x2, 0); break; // NaN
case 4: MVN_COND_REG_LSL_IMM5(cNE, x2, x2, 0); break; // Not Equal (or unordered on ARM, not on X86...)
case 5: MVN_COND_REG_LSL_IMM5(cPL, x2, x2, 0); break; // Greater or equal or unordered
case 6: MVN_COND_REG_LSL_IMM5(cHI, x2, x2, 0); break; // Greater or unordered
case 5: MVN_COND_REG_LSL_IMM5(cCS, x2, x2, 0); break; // Greater or equal or unordered
case 6: MVN_COND_REG_LSL_IMM5(cLT, x2, x2, 0); break; // Greater or unordered, test inverted, N!=V so unordereded or less than (inverted)
case 7: MVN_COND_REG_LSL_IMM5(cVC, x2, x2, 0); break; // not NaN
}
VMOVtoV_D(v0, x2, x2);
// 1
VCMP_F64(v0+1, d0+1);
if((u8&7)==6){
VCMP_F64(d0+1, v0+1);
} else {
VCMP_F64(v0+1, d0+1);
}
VMRS_APSR();
MOVW(x2, 0);
switch(u8&7) {
case 0: MVN_COND_REG_LSL_IMM5(cEQ, x2, x2, 0); break; // Equal
case 1: MVN_COND_REG_LSL_IMM5(cCC, x2, x2, 0); break; // Less than
case 2: MVN_COND_REG_LSL_IMM5(cLS, x2, x2, 0); break; // Less or equal
case 1: MVN_COND_REG_LSL_IMM5(cMI, x2, x2, 0); break; // Less than
case 2: MVN_COND_REG_LSL_IMM5(cLE, x2, x2, 0); break; // Less or equal
case 3: MVN_COND_REG_LSL_IMM5(cVS, x2, x2, 0); break; // NaN
case 4: MVN_COND_REG_LSL_IMM5(cNE, x2, x2, 0); break; // Not Equal (or unordered on ARM, not on X86...)
case 5: MVN_COND_REG_LSL_IMM5(cPL, x2, x2, 0); break; // Greater or equal or unordered
case 6: MVN_COND_REG_LSL_IMM5(cHI, x2, x2, 0); break; // Greater or unordered
case 5: MVN_COND_REG_LSL_IMM5(cCS, x2, x2, 0); break; // Greater or equal or unordered
case 6: MVN_COND_REG_LSL_IMM5(cLT, x2, x2, 0); break; // Greater or unordered, test inverted, N!=V so unordereded or less than (inverted)
case 7: MVN_COND_REG_LSL_IMM5(cVC, x2, x2, 0); break; // not NaN
}
VMOVtoV_D(v0+1, x2, x2);
@@ -1450,6 +1570,19 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
}
break;
case 0xC8:
case 0xC9:
case 0xCA:
case 0xCB:
case 0xCC:
case 0xCD:
case 0xCE:
case 0xCF: /* BSWAP reg */
INST_NAME("BSWAP Reg");
gd = xEAX+(opcode&7);
REV16(x1, gd);
BFI(gd, x1, 0, 16);
break;
case 0xD0:
INST_NAME("ADDSUBPD Gx, Ex");
nextop = F8;
@@ -1851,12 +1984,28 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
nextop = F8;
GETGX(q0);
GETEX(q1);
VABDQ_U8(q0, q0, q1);
VABDQ_U8(q0, q0, q1); // needs VABDLQ in fact
VPADDLQ_U8(q0, q0);
VPADDLQ_U16(q0, q0);
VPADDLQ_U32(q0, q0);
break;
case 0xF7:
INST_NAME("MASKMOVDQU Gx, Ex")
nextop = F8;
GETGX(q0);
GETEX(q1);
v0 = fpu_get_scratch_quad(dyn);
VLD1Q_8(v0, xEDI); // hopefully it's always aligned?
if((nextop&0xC0)==0xC0)
v1 = fpu_get_scratch_quad(dyn); // need to preserve the register
else
v1 = q1;
VCLTQ_0_8(v1, q1); // get the mask
VBICQ(v0, v0, v1); // mask destination
VANDQ(v1, q0, v1); // mask source
VORRQ(v1, v1, v0); // combine
VST1Q_8(v1, xEDI); // put back
break;
case 0xF8:
INST_NAME("PSUBB Gx,Ex");
nextop = F8;
+1 -1
View File
@@ -140,7 +140,7 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
/* out of the block */ \
i32 = dyn->insts[ninst+1].address-(dyn->arm_size+8); \
Bcond(NO, i32); \
jump_to_linker(dyn, addr+i8, 0, ninst); \
jump_to_next(dyn, addr+i8, 0, ninst); \
} else { \
/* inside the block */ \
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
+2 -2
View File
@@ -94,7 +94,7 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VCMP_F64(v1, v2);
FCOM(x1, x2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xE0:
case 0xE1:
@@ -216,7 +216,7 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
VCVT_F64_F32(d1, s0);
VCMP_F64(v1, d1);
FCOM(x1, x2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 4:
INST_NAME("FSUB ST0, float[ED]");
+14 -14
View File
@@ -58,7 +58,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xC7:
INST_NAME("FLD STx");
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
v2 = x87_do_push(dyn, ninst);
v2 = x87_do_push(dyn, ninst, x3);
VMOV_64(v2, v1);
break;
@@ -108,43 +108,43 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xE8:
INST_NAME("FLD1");
v1 = x87_do_push(dyn, ninst);
v1 = x87_do_push(dyn, ninst, x1);
MOV32(x2, (&d_1));
VLDR_64(v1, x2, 0);
break;
case 0xE9:
INST_NAME("FLDL2T");
v1 = x87_do_push(dyn, ninst);
v1 = x87_do_push(dyn, ninst, x1);
MOV32(x2, (&d_l2t));
VLDR_64(v1, x2, 0);
break;
case 0xEA:
INST_NAME("FLDL2E");
v1 = x87_do_push(dyn, ninst);
v1 = x87_do_push(dyn, ninst, x1);
MOV32(x2, (&d_l2e));
VLDR_64(v1, x2, 0);
break;
case 0xEB:
INST_NAME("FLDPI");
v1 = x87_do_push(dyn, ninst);
v1 = x87_do_push(dyn, ninst, x1);
MOV32(x2, (&d_pi));
VLDR_64(v1, x2, 0);
break;
case 0xEC:
INST_NAME("FLDLG2");
v1 = x87_do_push(dyn, ninst);
v1 = x87_do_push(dyn, ninst, x1);
MOV32(x2, (&d_lg2));
VLDR_64(v1, x2, 0);
break;
case 0xED:
INST_NAME("FLDLN2");
v1 = x87_do_push(dyn, ninst);
v1 = x87_do_push(dyn, ninst, x1);
MOV32(x2, (&d_ln2));
VLDR_64(v1, x2, 0);
break;
case 0xEE:
INST_NAME("FLDZ");
v1 = x87_do_push(dyn, ninst);
v1 = x87_do_push(dyn, ninst, x1);
MOV32(x2, (&d_0));
VLDR_64(v1, x2, 0);
break;
@@ -182,13 +182,13 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(arm_fyl2x, -1, 0);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xF2:
INST_NAME("FTAN");
x87_forget(dyn, ninst, x1, x2, 0);
CALL(arm_ftan, -1, 0);
v1 = x87_do_push(dyn, ninst);
v1 = x87_do_push(dyn, ninst, x3);
MOV32(x2, (&d_1));
VLDR_64(v1, x2, 0);
break;
@@ -197,7 +197,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(arm_fpatan, -1, 0);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xF4:
INST_NAME("FXTRACT");
@@ -238,7 +238,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(arm_fyl2xp1, -1, 0);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xFB:
INST_NAME("FSINCOS");
@@ -289,7 +289,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
switch((nextop>>3)&7) {
case 0:
INST_NAME("FLD ST0, float[ED]");
v1 = x87_do_push(dyn, ninst);
v1 = x87_do_push(dyn, ninst, x1);
s0 = fpu_get_scratch_single(dyn);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
@@ -331,7 +331,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
VMOVfrV(x2, s0);
STR_IMM9(x2, ed, fixedaddress);
}
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 4:
INST_NAME("FLDENV Ed");
+3 -3
View File
@@ -108,8 +108,8 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
v2 = x87_get_st(dyn, ninst, x1, x2, 1);
VCMP_F64(v1, v2);
FCOM(x1, x2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst, x3);
break;
case 0xE4:
@@ -168,7 +168,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
VCVT_F64_S32(d0, s0);
VCMP_F64(v1, d0);
FCOM(x1, x2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 4:
INST_NAME("FISUB ST0, Ed");
+23 -8
View File
@@ -159,7 +159,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
switch((nextop>>3)&7) {
case 0:
INST_NAME("FILD ST0, Ed");
v1 = x87_do_push(dyn, ninst);
v1 = x87_do_push(dyn, ninst, x1);
s0 = fpu_get_scratch_single(dyn);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
@@ -194,7 +194,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
MOV_IMM_COND(cNE, ed, 0b10, 1); // 0x80000000
WBACK;
VMSR(x14); // put back values
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 2:
INST_NAME("FIST Ed, ST0");
@@ -244,17 +244,32 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
TSTS_IMM8_ROR(x3, 0b00000001, 0);
MOV_IMM_COND(cNE, ed, 0b10, 1); // 0x80000000
WBACK;
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
x87_restoreround(dyn, ninst, u8);
break;
case 5:
INST_NAME("FLD tbyte");
x87_do_push_empty(dyn, ninst, x1);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
if(ed!=x1) {
MOV_REG(x1, ed);
if(PK(0)==0xDB && ((PK(1)>>3)&7)==7) {
// the FLD is immediatly followed by an FSTP
LDR_IMM9(x2, ed, 0);
LDR_IMM9(x3, ed, 4);
LDRH_IMM8(x14, ed, 8);
// no persistant scratch register, so unrool both instruction here...
MESSAGE(LOG_DUMP, "\tHack: FSTP tbyte\n");
nextop = F8; //0xDB
nextop = F8; //modrm
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
STR_IMM9(x2, ed, 0);
STR_IMM9(x3, ed, 4);
STRH_IMM8(x14, ed, 8);
} else {
if(ed!=x1) {
MOV_REG(x1, ed);
}
x87_do_push_empty(dyn, ninst, x3);
CALL(arm_fld, -1, 0);
}
CALL(arm_fld, -1, 0);
break;
case 7:
INST_NAME("FSTP tbyte");
@@ -264,7 +279,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
MOV_REG(x1, ed);
}
CALL(arm_fstp, -1, 0);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
default:
DEFAULT;
+2 -2
View File
@@ -90,7 +90,7 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VCMP_F64(v1, v2);
FCOM(x1, x2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xE0:
case 0xE1:
@@ -211,7 +211,7 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
}
VCMP_F64(v1, d1);
FCOM(x1, x2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 4:
INST_NAME("FSUB ST0, double[ED]");
+7 -7
View File
@@ -61,7 +61,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 0xD8:
INST_NAME("FSTP ST0, ST0");
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xD9:
case 0xDA:
@@ -74,7 +74,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VMOV_64(v2, v1);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xE0:
@@ -104,7 +104,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VCMP_F64(v1, v2);
FCOM(x1, x2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xC8:
@@ -138,7 +138,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
switch((nextop>>3)&7) {
case 0:
INST_NAME("FLD double");
v1 = x87_do_push(dyn, ninst);
v1 = x87_do_push(dyn, ninst, x1);
#if 0
// can bus error...
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
@@ -161,8 +161,8 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
x87_forget(dyn, ninst, x1, x2, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
if(ed!=x1) {MOV_REG(x1, ed);}
CALL(arm_fistp64, -1, 0);
x87_do_pop(dyn, ninst);
CALL(arm_fistt64, -1, 0);
x87_do_pop(dyn, ninst, x3);
break;
case 2:
INST_NAME("FST double");
@@ -191,7 +191,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
STR_IMM9(x2, ed, fixedaddress);
STR_IMM9(x3, ed, fixedaddress+4);
}
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 4:
INST_NAME("FRSTOR m108byte");
+9 -9
View File
@@ -43,7 +43,7 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VADD_F64(v2, v2, v1);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xC8:
case 0xC9:
@@ -57,7 +57,7 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VMUL_F64(v2, v2, v1);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xD0:
case 0xD1:
@@ -72,7 +72,7 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VCMP_F64(v1, v2);
FCOM(x1, x2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xD9:
@@ -81,8 +81,8 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
v2 = x87_get_st(dyn, ninst, x1, x2, 1);
VCMP_F64(v1, v2);
FCOM(x1, x2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst, x3);
break;
case 0xE0:
case 0xE1:
@@ -96,7 +96,7 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VSUB_F64(v2, v1, v2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xE8:
case 0xE9:
@@ -110,7 +110,7 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VSUB_F64(v2, v2, v1);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xF0:
case 0xF1:
@@ -124,7 +124,7 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VDIV_F64(v2, v1, v2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xF8:
case 0xF9:
@@ -138,7 +138,7 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VDIV_F64(v2, v2, v1);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xD8:
+8 -9
View File
@@ -51,14 +51,13 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xC7:
INST_NAME("FFREEP STx");
// not handling Tag...
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xE0:
INST_NAME("FNSTSW AX");
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
AND_IMM8(x2, x2, 7);
BFI(x1, x2, 11, 3); // inject top
BFI(xEAX, x1, 0, 16);
break;
@@ -76,7 +75,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VCMP_F64(v1, v2);
FCOMI(x1, x2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xF0:
case 0xF1:
@@ -92,7 +91,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VCMP_F64(v1, v2);
FCOMI(x1, x2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xC8:
@@ -141,7 +140,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
switch((nextop>>3)&7) {
case 0:
INST_NAME("FILD ST0, Ew");
v1 = x87_do_push(dyn, ninst);
v1 = x87_do_push(dyn, ninst, x1);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0);
LDRSH_IMM8(x1, wback, fixedaddress);
s0 = fpu_get_scratch_single(dyn);
@@ -168,7 +167,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
CMPS_REG_LSL_IMM5_COND(cEQ, ed, x3, 0);
MOVW_COND(cNE, x3, 0x8000); // saturated
STRH_IMM8(x3, wback, fixedaddress);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
VMSR(x14);
break;
case 2:
@@ -213,7 +212,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
CMPS_REG_LSL_IMM5_COND(cEQ, ed, x3, 0);
MOVW_COND(cNE, x3, 0x8000); // saturated
STRH_IMM8(x3, wback, fixedaddress);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
x87_restoreround(dyn, ninst, u8);
break;
case 4:
@@ -236,7 +235,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
if(ed!=x1) {MOV_REG(x1, ed);}
CALL(fpu_fbst, -1, 0);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 7: // could be inlined for most thing, but is it usefull?
INST_NAME("FISTP i64, ST0");
@@ -244,7 +243,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
if(ed!=x1) {MOV_REG(x1, ed);}
CALL(arm_fistp64, -1, 0);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
default:
DEFAULT;
+78 -208
View File
@@ -41,28 +41,21 @@ void emit_or32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF | X_AF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF), 0);
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 31);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -94,28 +87,21 @@ void emit_or32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF | X_AF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF), 0);
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 31);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -137,28 +123,21 @@ void emit_xor32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF | X_AF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF), 0);
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 31);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -190,28 +169,21 @@ void emit_xor32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF | X_AF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF), 0);
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 31);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -233,28 +205,21 @@ void emit_and32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF | X_AF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF), 0);
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 31);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -276,43 +241,44 @@ void emit_and32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
AND_IMM8(s1, s1, c);
}
} else {
IFX(X_PEND) {} else {MOV32(s3, c);}
IFX(X_ALL) {
ANDS_REG_LSL_IMM5(s1, s1, s3, 0);
if(((~c)>=0 && (~c)<256)) {
IFX(X_ALL) {
BICS_IMM8_ROR(s1, s1, ~c, 0);
} else {
BIC_IMM8(s1, s1, ~c, 0);
}
} else {
AND_REG_LSL_IMM5(s1, s1, s3, 0);
IFX(X_PEND) {} else {MOV32(s3, c);}
IFX(X_ALL) {
ANDS_REG_LSL_IMM5(s1, s1, s3, 0);
} else {
AND_REG_LSL_IMM5(s1, s1, s3, 0);
}
}
}
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF | X_AF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF), 0);
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 31);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit OR8 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch
void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4)
// emit OR8 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
@@ -329,30 +295,21 @@ void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF | X_AF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF), 0);
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 7);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
if(save_s4) {PUSH(xSP, 1<<s4);}
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
if(save_s4) {POP(xSP, 1<<s4);}
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -375,33 +332,26 @@ void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF | X_AF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF), 0);
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 7);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit XOR8 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch
void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4)
// emit XOR8 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
@@ -418,30 +368,21 @@ void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, in
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF | X_AF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF), 0);
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 7);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
if(save_s4) {PUSH(xSP, 1<<s4);}
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
if(save_s4) {POP(xSP, 1<<s4);}
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -464,33 +405,26 @@ void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF | X_AF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF), 0);
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 7);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit AND8 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch
void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4)
// emit AND8 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
@@ -507,30 +441,21 @@ void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, in
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF | X_AF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF), 0);
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 7);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
if(save_s4) {PUSH(xSP, 1<<s4);}
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
if(save_s4) {POP(xSP, 1<<s4);}
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -553,34 +478,27 @@ void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF | X_AF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF), 0);
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 7);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit OR16 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch
void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4)
// emit OR16 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
@@ -597,30 +515,21 @@ void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, in
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF | X_AF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF), 0);
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 15);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
if(save_s4) {PUSH(xSP, 1<<s4);}
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
if(save_s4) {POP(xSP, 1<<s4);}
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -652,33 +561,26 @@ void emit_or16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF | X_AF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF), 0);
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 15);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit XOR16 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch
void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4)
// emit XOR16 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
@@ -695,30 +597,21 @@ void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF | X_AF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF), 0);
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 15);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
if(save_s4) {PUSH(xSP, 1<<s4);}
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
if(save_s4) {POP(xSP, 1<<s4);}
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -750,33 +643,26 @@ void emit_xor16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF | X_AF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF), 0);
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 15);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit AND16 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch
void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4)
// emit AND16 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
@@ -793,30 +679,21 @@ void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF | X_AF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF), 0);
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 15);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
if(save_s4) {PUSH(xSP, 1<<s4);}
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
if(save_s4) {POP(xSP, 1<<s4);}
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -848,27 +725,20 @@ void emit_and16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF | X_AF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF), 0);
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 15);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
+85 -251
View File
@@ -51,13 +51,14 @@ void emit_add32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
MOV_REG_LSR_IMM5(s4, s3, 3);
BFI(xFlags, s4, F_AF, 1); // AF: bc & 0x08
}
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_CF) {
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
BIC_IMM8_COND(cCC, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_OF) {
ORR_IMM8_COND(cVS, xFlags, xFlags, 0b10, 0x0b);
@@ -68,19 +69,24 @@ void emit_add32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit ADD32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
void emit_add32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
{
if(s1==xESP && (!dyn->insts || dyn->insts[ninst].x86.need_flags==X_PEND))
{
// special case when doing math on ESP and only PEND is needed: ignoring it!
if(c>=0 && c<256) {
ADD_IMM8(s1, s1, c);
} else {
MOV32(s3, c);
ADD_REG_LSL_IMM5(s1, s1, s3, 0);
}
return;
}
IFX(X_PEND) {
MOV32(s3, c);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
@@ -127,13 +133,14 @@ void emit_add32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
MOV_REG_LSR_IMM5(s4, s3, 3);
BFI(xFlags, s4, F_AF, 1); // AF: bc & 0x08
}
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_CF) {
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
BIC_IMM8_COND(cCC, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_OF) {
ORR_IMM8_COND(cVS, xFlags, xFlags, 0b10, 0x0b);
@@ -144,13 +151,7 @@ void emit_add32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -183,14 +184,15 @@ void emit_sub32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
MOV_REG_LSR_IMM5(s4, s3, 3);
BFI(xFlags, s4, F_AF, 1); // AF: bc & 0x08
}
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_CF) {
// inverted carry
ORR_IMM8_COND(cCC, xFlags, xFlags, 1<<F_CF, 0);
BIC_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_OF) {
ORR_IMM8_COND(cVS, xFlags, xFlags, 0b10, 0x0b);
@@ -201,19 +203,24 @@ void emit_sub32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit SUB32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
void emit_sub32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
{
if(s1==xESP && (!dyn->insts || dyn->insts[ninst].x86.need_flags==X_PEND))
{
// special case when doing math on ESP and only PEND is needed: ignoring it!
if(c>=0 && c<256) {
SUB_IMM8(s1, s1, c);
} else {
MOV32(s3, c);
SUB_REG_LSL_IMM5(s1, s1, s3, 0);
}
return;
}
IFX(X_PEND) {
MOV32(s3, c);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
@@ -262,14 +269,15 @@ void emit_sub32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
MOV_REG_LSR_IMM5(s4, s3, 3);
BFI(xFlags, s4, F_AF, 1); // AF: bc & 0x08
}
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_CF) {
// Inverted carry
ORR_IMM8_COND(cCC, xFlags, xFlags, 1<<F_CF, 0);
BIC_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_OF) {
ORR_IMM8_COND(cVS, xFlags, xFlags, 0b10, 0x0b);
@@ -280,13 +288,7 @@ void emit_sub32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -336,13 +338,7 @@ void emit_add8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, in
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
IFX(X_AF|X_OF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
}
@@ -394,13 +390,7 @@ void emit_add8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -452,13 +442,7 @@ void emit_sub8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, in
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
IFX(X_AF|X_OF|X_CF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
}
@@ -511,13 +495,7 @@ void emit_sub8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -569,13 +547,7 @@ void emit_add16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
IFX(X_AF|X_OF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
}
@@ -643,13 +615,7 @@ void emit_add16c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -702,13 +668,7 @@ void emit_sub16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
IFX(X_AF|X_OF|X_CF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
}
@@ -774,13 +734,7 @@ void emit_sub16c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -824,13 +778,7 @@ void emit_inc32(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -875,13 +823,7 @@ void emit_inc8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -928,13 +870,7 @@ void emit_inc16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -979,13 +915,7 @@ void emit_dec32(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -1030,13 +960,7 @@ void emit_dec8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -1082,13 +1006,7 @@ void emit_dec16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -1139,13 +1057,7 @@ void emit_adc32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -1197,13 +1109,14 @@ void emit_adc32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
MOV_REG_LSR_IMM5(s4, s3, 3);
BFI(xFlags, s4, F_AF, 1); // AF: bc & 0x08
}
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_CF) {
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
BIC_IMM8_COND(cCC, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_OF) {
ORR_IMM8_COND(cVS, xFlags, xFlags, 0b10, 0x0b);
@@ -1214,13 +1127,7 @@ void emit_adc32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -1272,13 +1179,7 @@ void emit_adc8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, in
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
IFX(X_AF|X_OF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
}
@@ -1331,13 +1232,7 @@ void emit_adc8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -1390,13 +1285,7 @@ void emit_adc16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
IFX(X_AF|X_OF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
}
@@ -1464,13 +1353,7 @@ void emit_adc16c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -1505,14 +1388,15 @@ void emit_sbb32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
UBFX(s4, s3, 3, 1);
BFI(xFlags, s4, F_AF, 1); // AF: bc & 0x08
}
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_CF) {
// Inverted carry
ORR_IMM8_COND(cCC, xFlags, xFlags, 1<<F_CF, 0);
BIC_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_OF) {
ORR_IMM8_COND(cVS, xFlags, xFlags, 0b10, 0x0b);
@@ -1523,13 +1407,7 @@ void emit_sbb32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -1582,14 +1460,15 @@ void emit_sbb32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
UBFX(s4, s3, 3, 1);
BFI(xFlags, s4, F_AF, 1); // AF: bc & 0x08
}
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_CF) {
// Inverted carry
ORR_IMM8_COND(cCC, xFlags, xFlags, 1<<F_CF, 0);
BIC_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_OF) {
ORR_IMM8_COND(cVS, xFlags, xFlags, 0b10, 0x0b);
@@ -1600,13 +1479,7 @@ void emit_sbb32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -1660,13 +1533,7 @@ void emit_sbb8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, in
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
IFX(X_AF|X_OF|X_CF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
}
@@ -1720,13 +1587,7 @@ void emit_sbb8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -1781,13 +1642,7 @@ void emit_sbb16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
IFX(X_AF|X_OF|X_CF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
}
@@ -1855,13 +1710,7 @@ void emit_sbb16c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -1874,10 +1723,12 @@ void emit_neg32(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
} else IFX(X_ALL) {
SET_DFNONE(s3);
}
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
IFX(X_CF) {
TSTS_REG_LSL_IMM5(s1, s1, 0);
ORR_IMM8_COND(cNE, xFlags, xFlags, 1<<F_CF, 0);
BIC_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_AF) {
MOV_REG_LSL_IMM5(s3, s1, 0);
@@ -1892,7 +1743,6 @@ void emit_neg32(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_OF) {
ORR_IMM8_COND(cVS, xFlags, xFlags, 0b10, 0x0b);
@@ -1908,13 +1758,7 @@ void emit_neg32(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -1927,10 +1771,12 @@ void emit_neg16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
} else IFX(X_ALL) {
SET_DFNONE(s3);
}
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
IFX(X_CF) {
TSTS_REG_LSL_IMM5(s1, s1, 0);
ORR_IMM8_COND(cNE, xFlags, xFlags, 1<<F_CF, 0);
BIC_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_AF|X_OF) {
MOV_REG_LSL_IMM5(s3, s1, 0);
@@ -1955,20 +1801,13 @@ void emit_neg16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
UXTH(s1, s1, 0);
TSTS_REG_LSL_IMM5(s1, s1, 0);
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 15);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -1981,10 +1820,12 @@ void emit_neg8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
} else IFX(X_ALL) {
SET_DFNONE(s3);
}
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
IFX(X_CF) {
TSTS_REG_LSL_IMM5(s1, s1, 0);
ORR_IMM8_COND(cNE, xFlags, xFlags, 1<<F_CF, 0);
BIC_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_AF|X_OF) {
MOV_REG_LSL_IMM5(s3, s1, 0);
@@ -2008,19 +1849,12 @@ void emit_neg8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
IFX(X_ZF) {
ANDS_IMM8(s1, s1, 0xff);
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 7);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
+125 -42
View File
@@ -23,6 +23,63 @@
#include "dynarec_arm_functions.h"
#include "dynarec_arm_helper.h"
// emit SHL32 instruction, from s1 , shift s2, store result in s1 using s3 and s4 as scratch. s3 can be same as s2
void emit_shl32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
int32_t j32;
MAYUSE(j32);
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
SET_DF(s4, d_shl32);
} else IFX(X_ALL) {
SET_DFNONE(s4);
}
IFX(F_OF) {
CMPS_IMM8(s2, 0);
IFX(F_OF) {
BIC_IMM8_COND(cEQ, xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_PEND) {
STR_IMM9_COND(cEQ, s1, xEmu, offsetof(x86emu_t, res));
}
B_NEXT(cEQ);
}
IFX(X_CF | X_OF) {
RSB_IMM8(s4, s2, 32);
MOV_REG_LSR_REG(s4, s1, s4);
BFI(xFlags, s4, F_CF, 1);
}
IFX(X_ZF) {
MOVS_REG_LSL_REG(s1, s1, s2);
} else {
MOV_REG_LSL_REG(s1, s1, s2);
}
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s4, s1, 31);
BFI(xFlags, s4, F_SF, 1);
}
IFX(X_OF) {
CMPS_IMM8(s2, 1); // if s3==1
IFX(X_SF) {} else {MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 31);}
XOR_REG_LSL_IMM5_COND(cEQ, s4, s4, xFlags, 0); // CF is set if OF is asked
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
// else
BFC_COND(cNE, xFlags, F_OF, 1);
}
IFX(X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit SHL32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
void emit_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
{
@@ -73,13 +130,59 @@ void emit_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
}
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit SHR32 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s2 can be same as s3
void emit_shr32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
int32_t j32;
MAYUSE(j32);
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
SET_DF(s4, d_shr32);
} else IFX(X_ALL) {
SET_DFNONE(s4);
}
IFX(X_ALL) {
CMPS_IMM8(s2, 0); //if(!c)
IFX(X_PEND) {
STR_IMM9_COND(cEQ, s1, xEmu, offsetof(x86emu_t, res));
}
B_NEXT(cEQ);
}
IFX(X_ZF|X_CF) {
MOVS_REG_LSR_REG(s1, s1, s2);
} else {
MOV_REG_LSR_REG(s1, s1, s2);
}
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_CF) {
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s4, s1, 31);
BFI(xFlags, s4, F_SF, 1);
}
IFX(X_OF) {
CMPS_IMM8(s2, 1);
MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 30);
XOR_REG_LSR_IMM8_COND(cEQ, s4, s4, s4, 1);
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
}
IFX(X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -108,13 +211,14 @@ void emit_shr32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_CF) {
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
BIC_IMM8_COND(cCC, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 31);
@@ -128,13 +232,7 @@ void emit_shr32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
}
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -163,26 +261,21 @@ void emit_sar32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_CF) {
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
BIC_IMM8_COND(cCC, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 31);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -212,7 +305,6 @@ void emit_rol32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
IFX(X_OF) {
if(c==1) {
ADD_REG_LSR_IMM5(s3, s1, s1, 31);
AND_IMM8(s3, s3, 1);
BFI(xFlags, s3, F_OF, 1);
}
}
@@ -254,6 +346,7 @@ void emit_ror32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
// emit SHRD32 instruction, from s1, fill s2 , constant c, store result in s1 using s3 and s4 as scratch
void emit_shrd32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4)
{
c&=0x1f;
IFX(X_PEND) {
MOVW(s3, c);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
@@ -274,9 +367,11 @@ void emit_shrd32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int
} else {
MOV_REG_LSR_IMM5(s1, s1, c);
}
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
IFX(X_CF) {
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
BIC_IMM8_COND(cCC, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_ZF) {
ORRS_REG_LSL_IMM5(s1, s1, s2, 32-c);
@@ -288,7 +383,6 @@ void emit_shrd32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 31);
@@ -302,18 +396,13 @@ void emit_shrd32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int
}
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4)
{
c&=0x1f;
IFX(X_PEND) {
MOVW(s3, c);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
@@ -368,12 +457,6 @@ void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
+39 -64
View File
@@ -26,7 +26,7 @@
// emit CMP32 instruction, from cmp s1 , s2, using s3 and s4 as scratch
void emit_cmp32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
IFX(X_PEND) {
IFX_PENDOR0 {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
SET_DF(s4, d_cmp32);
@@ -34,12 +34,14 @@ void emit_cmp32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
SET_DFNONE(s4);
}
SUBS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 - s2
IFX(X_PEND) {
IFX_PENDOR0 {
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_OF) {
ORR_IMM8_COND(cVS, xFlags, xFlags, 0b10, 0x0b);
@@ -48,7 +50,6 @@ void emit_cmp32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
IFX(X_CF) {
// reversed carry
ORR_IMM8_COND(cCC, xFlags, xFlags, 1<<F_CF, 0);
BIC_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s4, s3, 31);
@@ -73,7 +74,7 @@ void emit_cmp32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
}
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
MOV32(s4, GetParityTab());
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
AND_IMM8(s3, s3, 31);
@@ -85,7 +86,7 @@ void emit_cmp32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
// emit CMP32 instruction, from cmp s1 , 0, using s3 and s4 as scratch
void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
{
IFX(X_PEND) {
IFX_PENDOR0 {
MOVW(s4, 0);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s4, xEmu, offsetof(x86emu_t, op2));
@@ -97,35 +98,28 @@ void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
SUBS_IMM8(s3, s1, 0); // res = s1 - 0
// and now the tricky ones (and mostly unused), PF and AF
// bc = (res & (~d | s)) | (~d & s) => is 0 here...
IFX(X_CF | X_AF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF), 0);
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
BFC(xFlags, F_OF, 1);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s4, s3, 31);
BFI(xFlags, s4, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit CMP16 instruction, from cmp s1 , s2, using s3 and s4 as scratch
void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
IFX(X_PEND) {
IFX_PENDOR0 {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
SET_DF(s3, d_cmp16);
@@ -133,7 +127,7 @@ void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
SET_DFNONE(s3);
}
SUB_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 - s2
IFX(X_PEND) {
IFX_PENDOR0 {
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF) {
@@ -167,13 +161,12 @@ void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
BFI(xFlags, s4, F_OF, 1); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
}
}
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
IFX(X_PF) {
IFX(X_CF|X_AF|X_OF) {
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
}
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
MOV32(s4, GetParityTab());
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
AND_IMM8(s3, s3, 31);
@@ -185,7 +178,7 @@ void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
// emit CMP16 instruction, from cmp s1 , #0, using s3 and s4 as scratch
void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
{
IFX(X_PEND) {
IFX_PENDOR0 {
MOVW(s3, 0);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
@@ -195,8 +188,8 @@ void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
SET_DFNONE(s3);
}
// bc = (res & (~d | s)) | (~d & s) = 0
IFX(X_CF | X_AF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF), 0);
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
BFC(xFlags, F_OF, 1);
@@ -205,26 +198,19 @@ void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
MOVW(s4, 0xffff);
TSTS_REG_LSL_IMM5(s1, s4, 0);
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s4, s1, 15);
BFI(xFlags, s4, F_SF, 1);
}
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
IFX(X_PF) {
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit CMP8 instruction, from cmp s1 , s2, using s3 and s4 as scratch
void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
IFX(X_PEND) {
IFX_PENDOR0 {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
SET_DF(s4, d_cmp8);
@@ -232,7 +218,7 @@ void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
SET_DFNONE(s4);
}
SUB_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 - s2
IFX(X_PEND) {
IFX_PENDOR0 {
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF) {
@@ -265,13 +251,12 @@ void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
BFI(xFlags, s4, F_OF, 1); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
}
}
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
IFX(X_PF) {
IFX(X_CF|X_AF|X_OF) {
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
}
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
MOV32(s4, GetParityTab());
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
AND_IMM8(s3, s3, 31);
@@ -282,7 +267,7 @@ void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
// emit CMP8 instruction, from cmp s1 , 0, using s3 and s4 as scratch
void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
{
IFX(X_PEND) {
IFX_PENDOR0 {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
MOVW(s4, 0);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, op2));
@@ -292,8 +277,8 @@ void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
SET_DFNONE(s4);
}
// bc = (res & (~d | s)) | (~d & s) = 0
IFX(X_CF | X_AF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF), 0);
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
BFC(xFlags, F_OF, 1);
@@ -301,27 +286,20 @@ void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
IFX(X_ZF) {
TSTS_IMM8(s1, 0xff);
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s4, s1, 7);
BFI(xFlags, s4, F_SF, 1);
}
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
IFX(X_PF) {
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit TEST32 instruction, from test s1 , s2, using s3 and s4 as scratch
void emit_test32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
IFX(X_PEND) {
IFX_PENDOR0 {
SET_DF(s3, d_tst32);
} else {
SET_DFNONE(s4);
@@ -329,16 +307,15 @@ void emit_test32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
IFX(X_OF) {
BFC(xFlags, F_OF, 1);
}
IFX(X_CF) {
BFC(xFlags, F_CF, 1);
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
ANDS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 & s2
IFX(X_PEND) {
IFX_PENDOR0 {
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s4, s3, 31);
@@ -347,7 +324,7 @@ void emit_test32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
IFX(X_PF) {
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
MOV32(s4, GetParityTab());
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_REG_LSL_IMM5(s3, s1, s2, 0);
AND_IMM8(s3, s3, 31);
@@ -359,7 +336,7 @@ void emit_test32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
// emit TEST16 instruction, from test s1 , s2, using s3 and s4 as scratch
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
IFX(X_PEND) {
IFX_PENDOR0 {
SET_DF(s3, d_tst16);
} else {
SET_DFNONE(s4);
@@ -367,16 +344,15 @@ void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
IFX(X_OF) {
BFC(xFlags, F_OF, 1);
}
IFX(X_CF) {
BFC(xFlags, F_CF, 1);
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
ANDS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 & s2
IFX(X_PEND) {
IFX_PENDOR0 {
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s4, s3, 15);
@@ -385,7 +361,7 @@ void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
IFX(X_PF) {
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
MOV32(s4, GetParityTab());
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_REG_LSL_IMM5(s3, s1, s2, 0);
AND_IMM8(s3, s3, 31);
@@ -397,7 +373,7 @@ void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
// emit TEST8 instruction, from test s1 , s2, using s3 and s4 as scratch
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
IFX(X_PEND) {
IFX_PENDOR0 {
SET_DF(s3, d_tst8);
} else {
SET_DFNONE(s4);
@@ -405,16 +381,15 @@ void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
IFX(X_OF) {
BFC(xFlags, F_OF, 1);
}
IFX(X_CF) {
BFC(xFlags, F_CF, 1);
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
ANDS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 & s2
IFX(X_PEND) {
IFX_PENDOR0 {
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s4, s3, 7);
@@ -423,7 +398,7 @@ void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
IFX(X_PF) {
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
MOV32(s4, GetParityTab());
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_REG_LSL_IMM5(s3, s1, s2, 0);
AND_IMM8(s3, s3, 31);
+74 -17
View File
@@ -80,19 +80,20 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
INST_NAME("LOCK OR Eb, Gb");
SETFLAGS(X_ALL, SF_SET);
nextop = F8;
GETGB(x2);
if((nextop&0xC0)==0xC0) {
GETGB(x2);
wback = (nextop&7);
wb2 = (wback>>2);
wback = xEAX+(wback&3);
UXTB(x1, wback, wb2);
emit_or8(dyn, ninst, x1, x2, x14, x3, 0);
emit_or8(dyn, ninst, x1, x2, x14, x3);
BFI(wback, ed, wb2*8, 8);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0);
MARKLOCK;
GETGB(x2);
LDREXB(x1, wback);
emit_or8(dyn, ninst, x1, x2, x14, x3, (wback==x3)?1:0);
emit_or8(dyn, ninst, x1, x2, x14, x2);
STREXB(x14, x1, wback);
CMPS_IMM8(x14, 0);
B_MARKLOCK(cNE); // write failed, try again
@@ -200,19 +201,20 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
INST_NAME("LOCK AND Eb, Gb");
SETFLAGS(X_ALL, SF_SET);
nextop = F8;
GETGB(x2);
if((nextop&0xC0)==0xC0) {
GETGB(x2);
wback = (nextop&7);
wb2 = (wback>>2);
wback = xEAX+(wback&3);
UXTB(x1, wback, wb2);
emit_and8(dyn, ninst, x1, x2, x14, x3, 0);
emit_and8(dyn, ninst, x1, x2, x14, x3);
BFI(wback, ed, wb2*8, 8);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0);
MARKLOCK;
GETGB(x2);
LDREXB(x1, wback);
emit_and8(dyn, ninst, x1, x2, x14, x3, (wback==x3)?1:0);
emit_and8(dyn, ninst, x1, x2, x14, x2);
STREXB(x14, x1, wback);
CMPS_IMM8(x14, 0);
B_MARKLOCK(cNE); // write failed, try again
@@ -280,19 +282,20 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
INST_NAME("LOCK XOR Eb, Gb");
SETFLAGS(X_ALL, SF_SET);
nextop = F8;
GETGB(x2);
if((nextop&0xC0)==0xC0) {
GETGB(x2);
wback = (nextop&7);
wb2 = (wback>>2);
wback = xEAX+(wback&3);
UXTB(x1, wback, wb2);
emit_xor8(dyn, ninst, x1, x2, x14, x3, 0);
emit_xor8(dyn, ninst, x1, x2, x14, x3);
BFI(wback, ed, wb2*8, 8);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0);
MARKLOCK;
GETGB(x2);
LDREXB(x1, wback);
emit_xor8(dyn, ninst, x1, x2, x14, x3, (wback==x3)?1:0);
emit_xor8(dyn, ninst, x1, x2, x14, x2);
STREXB(x14, x1, wback);
CMPS_IMM8(x14, 0);
B_MARKLOCK(cNE); // write failed, try again
@@ -664,6 +667,40 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
}
BFI(xFlags, ed, F_CF, 1);
break;
case 5:
INST_NAME("LOCK BTS Ed, Ib");
SETFLAGS(X_CF, SF_SUBSET);
gd = x2;
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
u8 = F8;
MOVW(gd, u8);
wback = 0;
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, 0, 0);
u8 = F8;
MOVW(gd, u8);
UBFX(x1, gd, 5, 3); // r1 = (gd>>5);
ADD_REG_LSL_IMM5(x3, ed, x1, 2); //(&ed)+=r1*4;
MARKLOCK;
LDREX(x1, x3);
ed = x1;
wback = x3;
}
AND_IMM8(x2, gd, 0x1f);
MOV_REG_LSR_REG(x14, ed, x2);
ANDS_IMM8(x14, x14, 1);
BFI(xFlags, x14, F_CF, 1);
B_MARK3(cNE); // bit already set, jump to next instruction
MOVW(x14, 1);
XOR_REG_LSL_REG(ed, ed, x14, x2);
if(wback) {
STREX(x14, ed, wback);
CMPS_IMM8(x14, 0);
B_MARKLOCK(cNE);
}
MARK3;
break;
case 6:
INST_NAME("LOCK BTR Ed, Ib");
SETFLAGS(X_CF, SF_SUBSET);
@@ -783,12 +820,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
STREX(x3, x14, wback);
CMPS_IMM8(x3, 0);
B_MARKLOCK(cNE);
IFX(X_ALL|X_PEND) {
MOV_REG(x2, x1);
emit_add32(dyn, ninst, x2, gd, x3, x14);
}
MOV_REG(gd, x1);
B_NEXT(c__);
B_MARK2(c__);
MARK;
LDR_IMM9(x1, wback, 0);
LDREXB(x14, wback);
@@ -798,6 +830,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
CMPS_IMM8(x3, 0);
B_MARK(cNE);
STR_IMM9(x14, wback, 0);
MARK2;
IFX(X_ALL|X_PEND) {
MOV_REG(x2, x1);
emit_add32(dyn, ninst, x2, gd, x3, x14);
@@ -857,12 +890,24 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
emit_inc32(dyn, ninst, ed, x3, x14);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
TSTS_IMM8(wback, 3);
B_MARK(cNE); // unaligned
MARKLOCK;
LDREX(x1, wback);
emit_inc32(dyn, ninst, x1, x3, x14);
STREX(x3, x1, wback);
CMPS_IMM8(x3, 0);
B_MARKLOCK(cNE);
B_NEXT(c__);
MARK;
LDR_IMM9(x1, wback, 0);
LDREXB(x3, wback);
BFI(x1, x3, 0, 8);
emit_inc32(dyn, ninst, x1, x3, x14);
STREXB(x3, x1, wback);
CMPS_IMM8(x3, 0);
B_MARK(cNE);
STR_IMM9(x1, wback, 0);
}
break;
case 1: //DEC Ed
@@ -873,22 +918,34 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
emit_dec32(dyn, ninst, ed, x3, x14);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
TSTS_IMM8(wback, 3);
B_MARK(cNE); // unaligned
MARKLOCK;
LDREX(x1, wback);
emit_dec32(dyn, ninst, x1, x3, x14);
STREX(x3, x1, wback);
CMPS_IMM8(x3, 0);
B_MARKLOCK(cNE);
B_NEXT(c__);
MARK;
LDR_IMM9(x1, wback, 0);
LDREXB(x3, wback);
BFI(x1, x3, 0, 8);
emit_dec32(dyn, ninst, x1, x3, x14);
STREXB(x3, x1, wback);
CMPS_IMM8(x3, 0);
B_MARK(cNE);
STR_IMM9(x1, wback, 0);
}
break;
default:
// dafault to NO LOCK
// default to NO LOCK
addr-=2;
}
break;
default:
// dafault to NO LOCK
// default to NO LOCK
--addr;
}
+13 -9
View File
@@ -137,7 +137,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
break;
case 0x2D:
INST_NAME("CVTSD2SI Gd, Ex");
u8 = x87_setround(dyn, ninst, x1, x2, x14);
u8 = sse_setround(dyn, ninst, x1, x2, x14);
nextop = F8;
GETGD;
s0 = fpu_get_scratch_single(dyn);
@@ -209,7 +209,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
// MINSD: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
VCMP_F64(v0, d0);
VMRS_APSR();
VMOVcond_64(cPL, v0, d0);
VMOVcond_64(cCS, v0, d0); // move v0 <- d0 if v0 or d0 unordered or v0 >= d0
break;
case 0x5E:
INST_NAME("DIVSD Gx, Ex");
@@ -228,7 +228,7 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
// MAXSD: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
VCMP_F64(d0, v0);
VMRS_APSR();
VMOVcond_64(cPL, v0, d0);
VMOVcond_64(cCS, v0, d0); // move v0 <- d0 if v0 or d0 is unordered or d0 >= v0
break;
case 0x70:
@@ -292,18 +292,22 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(d0);
VCMP_F64(v0, d0);
u8 = F8;
if((u8&7)==6){
VCMP_F64(d0, v0);
} else {
VCMP_F64(v0, d0);
}
VMRS_APSR();
MOVW(x2, 0);
u8 = F8;
switch(u8&7) {
case 0: MVN_COND_REG_LSL_IMM5(cEQ, x2, x2, 0); break; // Equal
case 1: MVN_COND_REG_LSL_IMM5(cCC, x2, x2, 0); break; // Less than
case 2: MVN_COND_REG_LSL_IMM5(cLS, x2, x2, 0); break; // Less or equal
case 1: MVN_COND_REG_LSL_IMM5(cMI, x2, x2, 0); break; // Less than
case 2: MVN_COND_REG_LSL_IMM5(cLE, x2, x2, 0); break; // Less or equal
case 3: MVN_COND_REG_LSL_IMM5(cVS, x2, x2, 0); break; // NaN
case 4: MVN_COND_REG_LSL_IMM5(cNE, x2, x2, 0); break; // Not Equal (or unordered on ARM, not on X86...)
case 5: MVN_COND_REG_LSL_IMM5(cPL, x2, x2, 0); break; // Greater or equal or unordered
case 6: MVN_COND_REG_LSL_IMM5(cHI, x2, x2, 0); break; // Greater or unordered
case 5: MVN_COND_REG_LSL_IMM5(cCS, x2, x2, 0); break; // Greater or equal or unordered
case 6: MVN_COND_REG_LSL_IMM5(cLT, x2, x2, 0); break; // Greater or unordered, test inverted, N!=V so unordereded or less than (inverted)
case 7: MVN_COND_REG_LSL_IMM5(cVC, x2, x2, 0); break; // not NaN
}
VMOVtoV_D(v0, x2, x2);
+23 -17
View File
@@ -227,7 +227,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
break;
case 0x2D:
INST_NAME("CVTSS2SI Gd, Ex");
u8 = x87_setround(dyn, ninst, x1, x2, x14);
u8 = sse_setround(dyn, ninst, x1, x2, x14);
nextop = F8;
GETGD;
s0 = fpu_get_scratch_single(dyn);
@@ -426,7 +426,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
// MINSS: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
VCMP_F32(s0, s1);
VMRS_APSR();
VMOVcond_32(cPL, s0, s1);
VMOVcond_32(cCS, s0, s1); // move s0 <- s1 if s0 or s1 unordered or s0 >= s1
if(v0!=d0) {
VMOV_64(v0, d0);
}
@@ -469,7 +469,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
// MAXSS: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
VCMP_F32(s1, s0);
VMRS_APSR();
VMOVcond_32(cPL, s0, s1);
VMOVcond_32(cCS, s0, s1); // move s0 <- s1 if s0 or s1 is unordered or s1 >= s0
if(v0!=d0) {
VMOV_64(v0, d0);
}
@@ -570,15 +570,17 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
nextop = F8;
GETED;
GETGD;
SET_DFNONE(x3);
TSTS_REG_LSL_IMM5(ed, ed, 0);
RBIT(x1, ed); // reverse
CLZ(gd, x1); // x2 gets leading 0 == TZCNT
MOVW_COND(cEQ, x1, 1);
MOVW_COND(cNE, x1, 0);
BFI(xFlags, x1, F_CF, 1);
RSB_IMM8(x1, x1, 1);
BFI(xFlags, x1, F_ZF, 1);
SET_DFNONE(x1);
MOVW_COND(cEQ, x3, 1);
MOVW_COND(cNE, x3, 0);
BFI(xFlags, x3, F_CF, 1); // CF = is source 0?
RBIT(x3, ed); // reverse
CLZ(gd, x3); // x2 gets leading 0 == TZCNT
TSTS_REG_LSL_IMM5(gd, gd, 0);
MOVW_COND(cEQ, x3, 1);
MOVW_COND(cNE, x3, 0);
BFI(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
break;
case 0xC2:
@@ -596,18 +598,22 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
VMOV_64(d0, v0);
}
s0 = d0*2;
VCMP_F32(s0, s1);
u8 = F8;
if((u8&7)==6){
VCMP_F32(s1, s0);
} else {
VCMP_F32(s0, s1);
}
VMRS_APSR();
MOVW(x2, 0);
u8 = F8;
switch(u8&7) {
case 0: MVN_COND_REG_LSL_IMM5(cEQ, x2, x2, 0); break; // Equal
case 1: MVN_COND_REG_LSL_IMM5(cCC, x2, x2, 0); break; // Less than
case 2: MVN_COND_REG_LSL_IMM5(cLS, x2, x2, 0); break; // Less or equal
case 1: MVN_COND_REG_LSL_IMM5(cMI, x2, x2, 0); break; // Less than
case 2: MVN_COND_REG_LSL_IMM5(cLE, x2, x2, 0); break; // Less or equal
case 3: MVN_COND_REG_LSL_IMM5(cVS, x2, x2, 0); break; // NaN
case 4: MVN_COND_REG_LSL_IMM5(cNE, x2, x2, 0); break; // Not Equal (or unordered on ARM, not on X86...)
case 5: MVN_COND_REG_LSL_IMM5(cPL, x2, x2, 0); break; // Greater or equal or unordered
case 6: MVN_COND_REG_LSL_IMM5(cHI, x2, x2, 0); break; // Greater or unordered
case 5: MVN_COND_REG_LSL_IMM5(cCS, x2, x2, 0); break; // Greater or equal or unordered
case 6: MVN_COND_REG_LSL_IMM5(cLT, x2, x2, 0); break; // Greater or unordered, test inverted, N!=V so unordereded or less than (inverted)
case 7: MVN_COND_REG_LSL_IMM5(cVC, x2, x2, 0); break; // not NaN
}
VMOVtoDx_32(v0, 0, x2);
+14 -6
View File
@@ -21,13 +21,14 @@
#include "emu/x86run_private.h"
#include "emu/x87emu_private.h"
#include "x86trace.h"
#include "signals.h"
#include "dynarec_arm.h"
#include "dynarec_arm_private.h"
#include "dynarec_arm_functions.h"
void arm_fstp(x86emu_t* emu, void* p)
{
if(ST0.ll!=STld(0).ref)
if(ST0.q!=STld(0).ref)
D2LD(&ST0.d, p);
else
memcpy(p, &STld(0).ld, 10);
@@ -56,7 +57,7 @@ void arm_fpatan(x86emu_t* emu)
}
void arm_fxtract(x86emu_t* emu)
{
int32_t tmp32s = (ST1.ll&0x7ff0000000000000LL)>>52;
int32_t tmp32s = (ST1.q&0x7ff0000000000000LL)>>52;
tmp32s -= 1023;
ST1.d /= exp2(tmp32s);
ST0.d = tmp32s;
@@ -106,7 +107,7 @@ void arm_fild64(x86emu_t* emu, int64_t* ed)
memcpy(&tmp, ed, sizeof(tmp));
ST0.d = tmp;
STll(0).ll = tmp;
STll(0).ref = ST0.ll;
STll(0).ref = ST0.q;
}
void arm_fbstp(x86emu_t* emu, uint8_t* ed)
@@ -117,7 +118,7 @@ void arm_fbstp(x86emu_t* emu, uint8_t* ed)
void arm_fistp64(x86emu_t* emu, int64_t* ed)
{
// used of memcpy to avoid aligments issues
if(STll(0).ref==ST(0).ll) {
if(STll(0).ref==ST(0).q) {
memcpy(ed, &STll(0).ll, sizeof(int64_t));
} else {
int64_t tmp;
@@ -129,16 +130,23 @@ void arm_fistp64(x86emu_t* emu, int64_t* ed)
}
}
void arm_fistt64(x86emu_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(x86emu_t* emu, uint8_t* ed)
{
memcpy(&STld(0).ld, ed, 10);
LD2D(&STld(0), &ST(0).d);
STld(0).ref = ST0.ll;
STld(0).ref = ST0.q;
}
void arm_ud(x86emu_t* emu)
{
kill(getpid(), SIGILL);
emit_signal(emu, SIGILL, (void*)R_EIP, 0);
}
void arm_fsave(x86emu_t* emu, uint8_t* ed)
+1
View File
@@ -23,6 +23,7 @@ void arm_fbld(x86emu_t* emu, uint8_t* ed);
void arm_fild64(x86emu_t* emu, int64_t* ed);
void arm_fbstp(x86emu_t* emu, uint8_t* ed);
void arm_fistp64(x86emu_t* emu, int64_t* ed);
void arm_fistt64(x86emu_t* emu, int64_t* ed);
void arm_fld(x86emu_t* emu, uint8_t* ed);
void arm_fsave(x86emu_t* emu, uint8_t* ed);
void arm_frstor(x86emu_t* emu, uint8_t* ed);
+131 -230
View File
@@ -20,6 +20,7 @@
#include "dynablock_private.h"
#include "arm_printer.h"
#include "../tools/bridge_private.h"
#include "custommem.h"
#include "dynarec_arm_functions.h"
#include "dynarec_arm_helper.h"
@@ -243,133 +244,50 @@ void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
BX(2);
}
void jump_to_linker(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
{
MESSAGE(LOG_DUMP, "Jump to linker (#%d) nolinker=%d\n", dyn->tablei, dyn->nolinker);
#if 0
int j32;
MAYUSE(j32);
#endif
if(dyn->nolinker==2) {
jump_to_epilog(dyn, ip, reg, ninst);
} else {
if(reg) {
if(reg!=xEIP) {
MOV_REG(xEIP, reg);
}
} else {
MOV32_(xEIP, ip);
}
uintptr_t* table = 0;
if(dyn->tablesz) {
table = &dyn->table[dyn->tablei];
table[0] = (uintptr_t)arm_linker;
table[1] = ip;
}
dyn->tablei+=4; // smart linker or not, we keep table correctly alligned for LDREXD/STREXD access
MOV32_(x1, (uintptr_t)table);
// TODO: This is not thread safe.
if(!ip) { // no IP, jump address in a reg, so need smart linker
#if 0
//version thread safe
MARK;
LDREXD(x2, x1); // load dest address in x2 and planned ip in x3
CMPS_REG_LSL_IMM5(xEIP, x3, 0);
BXcond(cEQ, x2);
MOV32_(x2, (uintptr_t)arm_linker);
MOV_REG(x3, x14);
STREXD(x14, x2, x1); // nope, putting back linker & IP in place
// x14 now contain success / falure for write
CMPS_IMM8(x14, 1);
MOV_REG(x14, x3); // put back IP in place...
B_MARK(cEQ);
BX(x2); // go to linker
#else
// not thread safe, is that still ok?
LDRD_IMM8(x2, x1, 0);
CMPS_REG_LSL_IMM5(xEIP, x3, 0);
BXcond(cEQ, x2);
MOV32_(x2, (uintptr_t)arm_linker);
MOV_REG(x3, x14);
STRD_IMM8(x2, x1, 0);
BX(x2);
#endif
} else {
LDR_IMM9(x2, x1, 0);
BX(x2); // jump
}
}
}
void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
{
MESSAGE(LOG_DUMP, "Jump to next nolinker=%d\n", dyn->nolinker);
MESSAGE(LOG_DUMP, "Jump to next\n");
if(dyn->nolinker==2) {
jump_to_epilog(dyn, ip, reg, ninst);
} else {
if(reg) {
if(reg!=xEIP) {
MOV_REG(xEIP, reg);
}
} else {
MOV32_(xEIP, ip);
if(reg) {
if(reg!=xEIP) {
MOV_REG(xEIP, reg);
}
MOV32_(x2, (uintptr_t)arm_next);
MOV_REG(x1, xEIP);
BX(x2);
MOV32(x2, getJumpTable());
MOV_REG_LSR_IMM5(x3, xEIP, JMPTABL_SHIFT);
LDR_REG_LSL_IMM5(x2, x2, x3, 2); // shiftsizeof(uintptr_t)
UBFX(x3, xEIP, 0, JMPTABL_SHIFT);
LDR_REG_LSL_IMM5(x3, x2, x3, 2); // shiftsizeof(uintptr_t)
} else {
uintptr_t p = getJumpTableAddress(ip);
MOV32(x2, p);
MOV32_(xEIP, ip);
LDR_IMM9(x3, x2, 0);
}
MOV_REG(x1, xEIP);
#ifdef HAVE_TRACE
MOV_REG(x2, 15); // move current PC to x2, for tracing
#endif
BX(x3);
}
void ret_to_epilog(dynarec_arm_t* dyn, int ninst)
{
// using linker here doesn't seem to bring any significant speed improvment. To much change in the jump table probably
#if 0
int i32;
MAYUSE(i32);
if(dyn->nolinker) {
#endif
MESSAGE(LOG_DUMP, "Ret next\n");
POP1(xEIP);
cstack_pop(dyn, ninst, xEIP, x1, x2);
MOV32_(x2, (uintptr_t)arm_next);
MOV32(x2, getJumpTable());
MOV_REG_LSR_IMM5(x3, xEIP, JMPTABL_SHIFT);
LDR_REG_LSL_IMM5(x2, x2, x3, 2); // shiftsizeof(uintptr_t)
UBFX(x3, xEIP, 0, JMPTABL_SHIFT);
LDR_REG_LSL_IMM5(x3, x2, x3, 2); // shiftsizeof(uintptr_t)
MOV_REG(x1, xEIP);
BX(x2);
#if 0
} else {
MESSAGE(LOG_DUMP, "Ret epilog with linker\n");
POP1(xEIP);
uintptr_t* table = 0;
if(dyn->tablesz) {
table = &dyn->table[dyn->tablei];
table[0] = (uintptr_t)arm_linker;
table[1] = 0;
}
dyn->tablei+=4; // smart linker
MOV32_(x1, (uintptr_t)table);
MARK;
LDREXD(x2, x1); // load dest address in x2 and planned ip in x3
CMPS_REG_LSL_IMM5(xEIP, x3, 0);
BXcond(cEQ, x2);
MOV32_(x2, (uintptr_t)arm_linker);
MOV_REG(x3, x14);
STREXD(x14, x2, x1); // nope, putting back linker & IP in place
// x14 now contain success / falure for write
CMPS_IMM8(x14, 1);
MOV_REG(x14, x3); // put back IP in place...
B_MARK(cEQ);
BX(x2); // go to linker
}
#endif
#ifdef HAVE_TRACE
MOV_REG(x2, 15); // move current PC to x2, for tracing
#endif
BX(x3);
}
void retn_to_epilog(dynarec_arm_t* dyn, int ninst, int n)
{
#if 0
int i32;
MAYUSE(i32);
if(dyn->nolinker) {
#endif
MESSAGE(LOG_DUMP, "Retn epilog\n");
POP1(xEIP);
if(n>0xff) {
@@ -378,37 +296,16 @@ void retn_to_epilog(dynarec_arm_t* dyn, int ninst, int n)
} else {
ADD_IMM8(xESP, xESP, n);
}
cstack_pop(dyn, ninst, xEIP, x1, x2);
MOV32_(x2, (uintptr_t)arm_next);
MOV32(x2, getJumpTable());
MOV_REG_LSR_IMM5(x3, xEIP, JMPTABL_SHIFT);
LDR_REG_LSL_IMM5(x2, x2, x3, 2); // shiftsizeof(uintptr_t)
UBFX(x3, xEIP, 0, JMPTABL_SHIFT);
LDR_REG_LSL_IMM5(x3, x2, x3, 2); // shiftsizeof(uintptr_t)
MOV_REG(x1, xEIP);
BX(x2);
#if 0
} else {
MESSAGE(LOG_DUMP, "Retn epilog with linker\n");
POP1(xEIP);
ADD_IMM8(xESP, xESP, n);
uintptr_t* table = 0;
if(dyn->tablesz) {
table = &dyn->table[dyn->tablei];
table[0] = (uintptr_t)arm_linker;
table[1] = 0;
}
dyn->tablei+=4; // smart linker
MOV32_(x1, (uintptr_t)table);
MARK;
LDREXD(x2, x1); // load dest address in x2 and planned ip in x3
CMPS_REG_LSL_IMM5(xEIP, x3, 0);
BXcond(cEQ, x2);
MOV32_(x2, (uintptr_t)arm_linker);
MOV_REG(x3, x14);
STREXD(x14, x2, x1); // nope, putting back linker & IP in place
// x14 now contain success / falure for write
CMPS_IMM8(x14, 1);
MOV_REG(x14, x3); // put back IP in place...
B_MARK(cEQ);
BX(x2); // go to linker
}
#endif
#ifdef HAVE_TRACE
MOV_REG(x2, 15); // move current PC to x2, for tracing
#endif
BX(x3);
}
void iret_to_epilog(dynarec_arm_t* dyn, int ninst)
@@ -429,9 +326,7 @@ void iret_to_epilog(dynarec_arm_t* dyn, int ninst)
ORR_IMM8(xFlags, xFlags, 2, 0);
SET_DFNONE(x1);
// Ret....
cstack_pop(dyn, ninst, xEIP, x1, x2);
PASS3(void* epilog = arm_epilog);
MOV32_(x2, (uintptr_t)epilog);
MOV32_(x2, (uintptr_t)arm_epilog); // epilog on purpose, CS might have changed!
BX(x2);
}
@@ -495,6 +390,7 @@ void grab_fsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg)
static void x87_reset(dynarec_arm_t* dyn, int ninst)
{
#if STEP > 1
dyn->x87count = 0;
for (int i=0; i<8; ++i)
dyn->x87cache[i] = -1;
dyn->x87stack = 0;
@@ -506,6 +402,8 @@ void x87_stackcount(dynarec_arm_t* dyn, int ninst, int scratch)
#if STEP > 1
if(!dyn->x87stack)
return;
if(dyn->mmxcount)
mmx_purgecache(dyn, ninst, scratch);
MESSAGE(LOG_DUMP, "\tSynch x87 Stackcount (%d)\n", dyn->x87stack);
int a = dyn->x87stack;
// Add x87stack to emu fpu_stack
@@ -531,9 +429,12 @@ void x87_stackcount(dynarec_arm_t* dyn, int ninst, int scratch)
#endif
}
int x87_do_push(dynarec_arm_t* dyn, int ninst)
int x87_do_push(dynarec_arm_t* dyn, int ninst, int s1)
{
#if STEP > 1
if(dyn->mmxcount)
mmx_purgecache(dyn, ninst, s1);
++dyn->x87count;
dyn->x87stack+=1;
// move all regs in cache, and find a free one
int ret = -1;
@@ -552,6 +453,9 @@ int x87_do_push(dynarec_arm_t* dyn, int ninst)
void x87_do_push_empty(dynarec_arm_t* dyn, int ninst, int s1)
{
#if STEP > 1
if(dyn->mmxcount)
mmx_purgecache(dyn, ninst, s1);
++dyn->x87count;
dyn->x87stack+=1;
// move all regs in cache
for(int i=0; i<8; ++i)
@@ -561,9 +465,11 @@ void x87_do_push_empty(dynarec_arm_t* dyn, int ninst, int s1)
x87_stackcount(dyn, ninst, s1);
#endif
}
void x87_do_pop(dynarec_arm_t* dyn, int ninst)
void x87_do_pop(dynarec_arm_t* dyn, int ninst, int s1)
{
#if STEP > 1
if(dyn->mmxcount)
mmx_purgecache(dyn, ninst, s1);
dyn->x87stack-=1;
// move all regs in cache, poping ST0
for(int i=0; i<8; ++i)
@@ -574,12 +480,14 @@ void x87_do_pop(dynarec_arm_t* dyn, int ninst)
dyn->x87reg[i] = -1;
}
}
--dyn->x87count;
#endif
}
static void x87_purgecache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
void x87_purgecache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
{
#if STEP > 1
dyn->x87count = 0;
int ret = 0;
for (int i=0; i<8 && !ret; ++i)
if(dyn->x87cache[i] != -1)
@@ -640,10 +548,10 @@ static void x87_purgecache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3
if(ret!=0) {
// --- set values
// prepare offset to fpu => s1
if(offsetof(x86emu_t, fpu)<256) {
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, fpu));
if(offsetof(x86emu_t, mmx87)<256) {
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, mmx87));
} else {
MOVW(s1, offsetof(x86emu_t, fpu));
MOVW(s1, offsetof(x86emu_t, mmx87));
ADD_REG_LSL_IMM5(s1, xEmu, s1, 0);
}
// Get top
@@ -674,10 +582,10 @@ static void x87_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
if(!ret) // nothing to do
return;
// prepare offset to fpu => s1
if(offsetof(x86emu_t, fpu)<256) {
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, fpu));
if(offsetof(x86emu_t, mmx87)<256) {
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, mmx87));
} else {
MOVW(s1, offsetof(x86emu_t, fpu));
MOVW(s1, offsetof(x86emu_t, mmx87));
ADD_REG_LSL_IMM5(s1, xEmu, s1, 0);
}
// Get top
@@ -697,6 +605,8 @@ static void x87_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
int x87_get_cache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
{
#if STEP > 1
if(dyn->mmxcount)
mmx_purgecache(dyn, ninst, s1);
// search in cache first
for (int i=0; i<8; ++i)
if(dyn->x87cache[i]==st)
@@ -710,10 +620,11 @@ int x87_get_cache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
// found, setup and grab the value
dyn->x87cache[ret] = st;
dyn->x87reg[ret] = fpu_get_reg_double(dyn);
if(offsetof(x86emu_t, fpu)<256) {
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, fpu));
++dyn->x87count;
if(offsetof(x86emu_t, mmx87)<256) {
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, mmx87));
} else {
MOVW(s1, offsetof(x86emu_t, fpu));
MOVW(s1, offsetof(x86emu_t, mmx87));
ADD_REG_LSL_IMM5(s1, xEmu, s1, 0);
}
LDR_IMM9(s2, xEmu, offsetof(x86emu_t, top));
@@ -758,10 +669,10 @@ void x87_refresh(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
return;
MESSAGE(LOG_DUMP, "\tRefresh x87 Cache for ST%d\n", st);
// prepare offset to fpu => s1
if(offsetof(x86emu_t, fpu)<256) {
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, fpu));
if(offsetof(x86emu_t, mmx87)<256) {
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, mmx87));
} else {
MOVW(s1, offsetof(x86emu_t, fpu));
MOVW(s1, offsetof(x86emu_t, mmx87));
ADD_REG_LSL_IMM5(s1, xEmu, s1, 0);
}
// Get top
@@ -789,10 +700,10 @@ void x87_forget(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
return;
MESSAGE(LOG_DUMP, "\tForget x87 Cache for ST%d\n", st);
// prepare offset to fpu => s1
if(offsetof(x86emu_t, fpu)<256) {
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, fpu));
if(offsetof(x86emu_t, mmx87)<256) {
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, mmx87));
} else {
MOVW(s1, offsetof(x86emu_t, fpu));
MOVW(s1, offsetof(x86emu_t, mmx87));
ADD_REG_LSL_IMM5(s1, xEmu, s1, 0);
}
// Get top
@@ -809,21 +720,24 @@ void x87_forget(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
fpu_free_reg_double(dyn, dyn->x87reg[ret]);
dyn->x87cache[ret] = -1;
dyn->x87reg[ret] = -1;
--dyn->x87count;
#endif
}
void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
{
#if STEP > 1
if(dyn->mmxcount)
mmx_purgecache(dyn, ninst, s1);
// search in cache first
for (int i=0; i<8; ++i)
if(dyn->x87cache[i]==st) {
// refresh the value
MESSAGE(LOG_DUMP, "\tRefresh x87 Cache for ST%d\n", st);
if(offsetof(x86emu_t, fpu)<256) {
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, fpu));
if(offsetof(x86emu_t, mmx87)<256) {
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, mmx87));
} else {
MOVW(s1, offsetof(x86emu_t, fpu));
MOVW(s1, offsetof(x86emu_t, mmx87));
ADD_REG_LSL_IMM5(s1, xEmu, s1, 0);
}
LDR_IMM9(s2, xEmu, offsetof(x86emu_t, top));
@@ -850,10 +764,11 @@ void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
// found, setup and grab the value
dyn->x87cache[ret] = st;
dyn->x87reg[ret] = fpu_get_reg_double(dyn);
if(offsetof(x86emu_t, fpu)<256) {
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, fpu));
++dyn->x87count;
if(offsetof(x86emu_t, mmx87)<256) {
ADD_IMM8(s1, xEmu, offsetof(x86emu_t, mmx87));
} else {
MOVW(s1, offsetof(x86emu_t, fpu));
MOVW(s1, offsetof(x86emu_t, mmx87));
ADD_REG_LSL_IMM5(s1, xEmu, s1, 0);
}
LDR_IMM9(s2, xEmu, offsetof(x86emu_t, top));
@@ -886,6 +801,20 @@ int x87_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
return s3;
}
// Set rounding according to mxcsr flags, return reg to restore flags
int sse_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
{
LDRH_IMM8(s1, xEmu, offsetof(x86emu_t, mxcsr));
UBFX(s2, s1, 13, 2); // extract round...
MOV32(s1, round_map);
LDR_REG_LSL_IMM5(s2, s1, s2, 2);
VMRS(s1); // get fpscr
MOV_REG(s3, s1);
BFI(s1, s2, 22, 2); // inject new round
VMSR(s1); // put new fpscr
return s3;
}
// Restore round flag
void x87_restoreround(dynarec_arm_t* dyn, int ninst, int s1)
{
@@ -896,18 +825,22 @@ void x87_restoreround(dynarec_arm_t* dyn, int ninst, int s1)
static void mmx_reset(dynarec_arm_t* dyn, int ninst)
{
#if STEP > 1
dyn->mmxcount = 0;
for (int i=0; i<8; ++i)
dyn->mmxcache[i] = -1;
#endif
}
// get neon register for a MMX reg, create the entry if needed
int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a)
int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a)
{
#if STEP > 1
if(dyn->x87count)
x87_purgecache(dyn, ninst, s1, s2, s3);
if(dyn->mmxcache[a]!=-1)
return dyn->mmxcache[a];
++dyn->mmxcount;
int ret = dyn->mmxcache[a] = fpu_get_reg_double(dyn);
int offs = offsetof(x86emu_t, mmx[a]);
int offs = offsetof(x86emu_t, mmx87[a]);
if(!(offs&3) && (offs>>2)<256) {
ADD_IMM8_ROR(s1, xEmu, offs>>2, 15);
} else {
@@ -921,11 +854,14 @@ int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a)
#endif
}
// get neon register for a MMX reg, but don't try to synch it if it needed to be created
int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a)
int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a)
{
#if STEP > 1
if(dyn->x87count)
x87_purgecache(dyn, ninst, s1, s2, s3);
if(dyn->mmxcache[a]!=-1)
return dyn->mmxcache[a];
++dyn->mmxcount;
int ret = dyn->mmxcache[a] = fpu_get_reg_double(dyn);
return ret;
#else
@@ -933,15 +869,18 @@ int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a)
#endif
}
// purge the MMX cache only(needs 3 scratch registers)
static void mmx_purgecache(dynarec_arm_t* dyn, int ninst, int s1)
void mmx_purgecache(dynarec_arm_t* dyn, int ninst, int s1)
{
#if STEP > 1
if(!dyn->mmxcount)
return;
dyn->mmxcount = 0;
int old = -1;
for (int i=0; i<8; ++i)
if(dyn->mmxcache[i]!=-1) {
if (old==-1) {
MESSAGE(LOG_DUMP, "\tPurge MMX Cache ------\n");
int offs = offsetof(x86emu_t, mmx[i]);
int offs = offsetof(x86emu_t, mmx87[i]);
if(!(offs&3) && (offs>>2)<256) {
ADD_IMM8_ROR(s1, xEmu, offs>>2, 15);
} else {
@@ -972,7 +911,7 @@ static void mmx_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
for (int i=0; i<8; ++i)
if(dyn->mmxcache[i]!=-1) {
if (old==-1) {
int offs = offsetof(x86emu_t, mmx[i]);
int offs = offsetof(x86emu_t, mmx87[i]);
if(!(offs&3) && (offs>>2)<256) {
ADD_IMM8_ROR(s1, xEmu, offs>>2, 15);
} else {
@@ -1098,8 +1037,8 @@ void fpu_pushcache(dynarec_arm_t* dyn, int ninst, int s1)
#if STEP > 1
// only need to push 16-31...
int n=0;
for (int i=8; i<24; i++)
if(dyn->fpuused[i])
for (int i=16; i<32; i++)
if(dyn->fpuused[i-8])
++n;
if(!n)
return;
@@ -1111,10 +1050,9 @@ void fpu_pushcache(dynarec_arm_t* dyn, int ninst, int s1)
SUB_IMM8(xSP, xSP, n*8);
}
MOV_REG(s1, xSP);
for (int i=0; i<n; ++i) { // should use VSTM?
if(dyn->fpuused[i+8]) {
PASS3(int a = 16+i);
VST1_32_W(a, s1);
for (int i=16; i<32; ++i) { // should use VSTM?
if(dyn->fpuused[i-8]) {
VST1_32_W(i, s1);
}
}
MESSAGE(LOG_DUMP, "\t------- Push FPU Cache (%d)\n", n);
@@ -1126,17 +1064,16 @@ void fpu_popcache(dynarec_arm_t* dyn, int ninst, int s1)
#if STEP > 1
// only need to push 16-31...
int n=0;
for (int i=8; i<24; i++)
if(dyn->fpuused[i])
for (int i=16; i<32; i++)
if(dyn->fpuused[i-8])
++n;
if(!n)
return;
MESSAGE(LOG_DUMP, "\tPop FPU Cache (%d)------\n", n);
MOV_REG(s1, xSP);
for (int i=0; i<n; ++i) {
if(dyn->fpuused[i+8]) {
PASS3(int a = 16+i);
VLD1_32_W(a, s1);
for (int i=16; i<32; ++i) {
if(dyn->fpuused[i-8]) {
VLD1_32_W(i, s1);
}
}
if(n>=8) {
@@ -1197,49 +1134,13 @@ void fpu_putback_single_reg(dynarec_arm_t* dyn, int ninst, int reg, int idx, int
}
}
// PUSH a x86/native couple of address in cstack, using s1, s2, s2+1
void cstack_push(dynarec_arm_t* dyn, int ninst, uintptr_t x86ip, uintptr_t armip, int s1, int s2)
void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
{
if(x86ip)
armip+=dyn->arm_start;
MESSAGE(LOG_DUMP, "CStack PUSH %p/%p-----\n", (void*)x86ip, (void*)armip);
// load current indice
LDR_IMM9(s2, xEmu, offsetof(x86emu_t, cstacki));
// calcule offset in the cstack
MOV32(s1, offsetof(x86emu_t, cstack));
TSTS_IMM8(xEmu, 0x04); // test if x86emu_t struct is not 0x8 aligned
ADD_IMM8_cond(cNE, s1, s1, 4); // align...
ADD_REG_LSL_IMM5(s1, s1, s2, 3); //*8, because it's a pair of address
// increment (mod mask) and save back index
ADD_IMM8(s2, s2, 1);
AND_IMM8(s2, s2, CSTACKMASK);
STR_IMM9(s2, xEmu, offsetof(x86emu_t, cstacki));
// push the pair of address
MOV32(s2, x86ip);
MOV32_(s2+1, armip);
STRD_REG(s2, xEmu, s1);
MESSAGE(LOG_DUMP, "--------------CStack PUSH\n");
}
// POP a x86/native couple of address from cstack, and generate the jump is x86 address is s0, use s1, s2 and s2+1 as scratch
void cstack_pop(dynarec_arm_t* dyn, int ninst, int s0, int s1, int s2)
{
MESSAGE(LOG_DUMP, "CStack POP----------------\n");
// load current indice
LDR_IMM9(s1, xEmu, offsetof(x86emu_t, cstacki));
// decrement (mod mask) and save back index
SUB_IMM8(s1, s1, 1);
AND_IMM8(s1, s1, CSTACKMASK);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, cstacki));
// calcule offset in the cstack
MOV32(s2, offsetof(x86emu_t, cstack));
TSTS_IMM8(xEmu, 0x04); // test if x86emu_t struct is not 0x8 aligned
ADD_IMM8_cond(cNE, s2, s2, 4); // align...
ADD_REG_LSL_IMM5(s1, s2, s1, 3); //*8, because it's a pair of address
// pop the pair of address
LDRD_REG(s2, xEmu, s1);
CMPS_REG_LSL_IMM5(s0, s2, 0);
BXcond(cEQ, s2+1);
MESSAGE(LOG_DUMP, "----------------CStack POP\n");
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
MOV32(s4, GetParityTab());
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
BFI(xFlags, s4, F_PF, 1);
}
+61 -49
View File
@@ -69,6 +69,16 @@
LDR_REG_LSL_IMM5(x1, wback, O, 0); \
ed = x1; \
}
//GETEDO can use r1 for ed, and r2 for wback. wback is 0 if ed is xEAX..xEDI, else O is added to wback
#define GETEDO2(O) if((nextop&0xC0)==0xC0) { \
ed = xEAX+(nextop&7); \
wback = 0; \
} else { \
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0); \
ADD_REG_LSL_IMM5(wback, wback, O, 0);\
LDR_IMM9(x1, wback, 0); \
ed = x1; \
}
#define WBACKO(O) if(wback) {STR_REG_LSL_IMM5(ed, wback, O, 0);}
//FAKEELike GETED, but doesn't get anything
#define FAKEED if((nextop&0xC0)!=0xC0) { \
@@ -234,6 +244,7 @@
Bcond(cond, j32)
#define IFX(A) if(dyn->insts && (dyn->insts[ninst].x86.need_flags&(A)))
#define IFX_PENDOR0 if(dyn->insts && (dyn->insts[ninst].x86.need_flags&(X_PEND) || !dyn->insts[ninst].x86.need_flags))
#define IFXX(A) if(dyn->insts && (dyn->insts[ninst].x86.need_flags==(A)))
#define IFX2X(A, B) if(dyn->insts && (dyn->insts[ninst].x86.need_flags==(A) || dyn->insts[ninst].x86.need_flags==(B) || dyn->insts[ninst].x86.need_flags==((A)|(B))))
#define IFXN(A, B) if(dyn->insts && (dyn->insts[ninst].x86.need_flags&(A) && !(dyn->insts[ninst].x86.need_flags&(B))))
@@ -241,37 +252,34 @@
// Generate FCOM with s1 and s2 scratch regs (the VCMP is already done)
#define FCOM(s1, s2) \
VMRS_APSR(); /* 0b0100011100000000 */ \
LDRH_IMM8(s2, xEmu, offsetof(x86emu_t, sw)); /*offset is 8bits right?*/ \
MOVW(s1, 0b0100011100000000); \
BIC_REG_LSL_IMM5(s2, s2, s1, 0); \
MOVW_COND(cVS, s1, 0b0100010100000000); /* unordered */ \
MOVW_COND(cEQ, s1, 0b0100000000000000); /* zero */ \
MOVW_COND(cGT, s1, 0b0000000000000000); /* greater than */ \
MOVW_COND(cLO, s1, 0b0000000100000000); /* less than */ \
ORR_REG_LSL_IMM5(s2, s2, s1, 0); \
STRH_IMM8(s2, xEmu, offsetof(x86emu_t, sw))
LDRH_IMM8(s1, xEmu, offsetof(x86emu_t, sw)); /*offset is 8bits right?*/ \
BIC_IMM8(s1, s1, 0b01000111, 12); \
ORR_IMM8_COND(cVS, s1, s1, 0b01000101, 12); /* unordered */ \
ORR_IMM8_COND(cEQ, s1, s1, 0b01000000, 12); /* equal */ \
ORR_IMM8_COND(cMI, s1, s1, 0b00000001, 12); /* less than */ \
/* greater than leave 0 */ \
STRH_IMM8(s1, xEmu, offsetof(x86emu_t, sw))
// Generate FCOMI with s1 and s2 scratch regs (the VCMP is already done)
#define FCOMI(s1, s2) \
VMRS_APSR(); /* 0b111 */ \
MOVW_COND(cVS, s1, 0b1000101); /* unordered */ \
MOVW_COND(cEQ, s1, 0b1000000); /* zero */ \
MOVW_COND(cGT, s1, 0b0000000); /* greater than */ \
MOVW_COND(cLO, s1, 0b0000001); /* less than */ \
IFX(X_CF|X_PF|X_ZF|X_PEND) { \
BIC_IMM8(xFlags, xFlags, 0b1000101, 0); \
ORR_REG_LSL_IMM5(xFlags, xFlags, s1, 0); \
} \
SET_DFNONE(s1); \
IFX(X_OF|X_PEND) { \
BFC(xFlags, F_OF, 1); \
} \
IFX(X_AF|X_PEND) { \
BFC(xFlags, F_AF, 1); \
} \
IFX(X_SF|X_PEND) { \
BFC(xFlags, F_SF, 1); \
} \
IFX(X_CF|X_PF|X_ZF|X_PEND) { \
VMRS_APSR(); /* 0b111 */ \
BIC_IMM8(xFlags, xFlags, 0b1000101, 0); \
ORR_IMM8_COND(cVS, xFlags, xFlags, 0b01000101, 0); /* unordered */ \
ORR_IMM8_COND(cEQ, xFlags, xFlags, 0b01000000, 0); /* zero */ \
ORR_IMM8_COND(cMI, xFlags, xFlags, 0b00000001, 0); /* less than */ \
/* greater than leave 0 */ \
} \
SET_DFNONE(s1); \
IFX(X_OF|X_PEND) { \
BFC(xFlags, F_OF, 1); \
} \
IFX(X_AF|X_PEND) { \
BFC(xFlags, F_AF, 1); \
} \
IFX(X_SF|X_PEND) { \
BFC(xFlags, F_SF, 1); \
} \
#define SET_DFNONE(S) if(!dyn->dfnone) {MOVW(S, d_none); STR_IMM9(S, xEmu, offsetof(x86emu_t, df)); dyn->dfnone=1;}
@@ -331,7 +339,6 @@
#endif
void arm_epilog();
void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
void* arm_next(x86emu_t* emu, uintptr_t addr);
#ifndef STEPNAME
@@ -364,7 +371,6 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
#define geted STEPNAME(geted_)
#define geted16 STEPNAME(geted16_)
#define jump_to_epilog STEPNAME(jump_to_epilog_)
#define jump_to_linker STEPNAME(jump_to_linker_)
#define jump_to_next STEPNAME(jump_to_next_)
#define ret_to_epilog STEPNAME(ret_to_epilog_)
#define retn_to_epilog STEPNAME(retn_to_epilog_)
@@ -432,7 +438,9 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
#define emit_neg32 STEPNAME(emit_neg32)
#define emit_neg16 STEPNAME(emit_neg16)
#define emit_neg8 STEPNAME(emit_neg8)
#define emit_shl32 STEPNAME(emit_shl32)
#define emit_shl32c STEPNAME(emit_shl32c)
#define emit_shr32 STEPNAME(emit_shr32)
#define emit_shr32c STEPNAME(emit_shr32c)
#define emit_sar32c STEPNAME(emit_sar32c)
#define emit_rol32c STEPNAME(emit_rol32c)
@@ -440,6 +448,8 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
#define emit_shrd32c STEPNAME(emit_shrd32c)
#define emit_shld32c STEPNAME(emit_shld32c)
#define emit_pf STEPNAME(emit_pf)
#define x87_do_push STEPNAME(x87_do_push)
#define x87_do_push_empty STEPNAME(x87_do_push_empty)
#define x87_do_pop STEPNAME(x87_do_pop)
@@ -451,6 +461,7 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
#define x87_stackcount STEPNAME(x87_stackcount)
#define x87_setround STEPNAME(x87_setround)
#define x87_restoreround STEPNAME(x87_restoreround)
#define sse_setround STEPNAME(sse_setround)
#define mmx_get_reg STEPNAME(mmx_get_reg)
#define mmx_get_reg_empty STEPNAME(mmx_get_reg_empty)
#define sse_get_reg STEPNAME(sse_get_reg)
@@ -460,12 +471,11 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
#define fpu_popcache STEPNAME(fpu_popcache)
#define fpu_reset STEPNAME(fpu_reset)
#define fpu_purgecache STEPNAME(fpu_purgecache)
#define x87_purgecache STEPNAME(x87_purgecache)
#define mmx_purgecache STEPNAME(mmx_purgecache)
#ifdef HAVE_TRACE
#define fpu_reflectcache STEPNAME(fpu_reflectcache)
#endif
#define cstack_push STEPNAME(cstack_push)
#define cstack_pop STEPNAME(cstack_pop)
// get the single reg that from the double "reg" (so Dx[idx])
#define fpu_get_single_reg STEPNAME(fpu_get_single_reg)
@@ -481,7 +491,6 @@ uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
// generic x86 helper
void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst);
void jump_to_linker(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst);
void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst);
void ret_to_epilog(dynarec_arm_t* dyn, int ninst);
void retn_to_epilog(dynarec_arm_t* dyn, int ninst, int n);
@@ -514,21 +523,21 @@ void emit_xor32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_xor32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_and32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_and32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_add16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
void emit_add16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_sub16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
void emit_sub16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_or16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_xor16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_and16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_inc32(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
void emit_inc16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
@@ -551,7 +560,9 @@ void emit_sbb16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
void emit_neg32(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
void emit_neg16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
void emit_neg8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
void emit_shl32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_shr32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_shr32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_sar32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_rol32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
@@ -559,15 +570,17 @@ void emit_ror32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
void emit_shrd32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4);
void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4);
void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
// x87 helper
// cache of the local stack counter, to avoid upadte at every call
void x87_stackcount(dynarec_arm_t* dyn, int ninst, int scratch);
// fpu push. Return the Dd value to be used
int x87_do_push(dynarec_arm_t* dyn, int ninst);
int x87_do_push(dynarec_arm_t* dyn, int ninst, int s1);
// 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);
void x87_do_pop(dynarec_arm_t* dyn, int ninst, int s1);
// get cache index for a x87 reg, create the entry if needed
int x87_get_cache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a);
// get vfpu register for a x87 reg, create the entry if needed
@@ -582,12 +595,14 @@ void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st);
int x87_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
// Restore round flag
void x87_restoreround(dynarec_arm_t* dyn, int ninst, int s1);
// Set rounding according to mxcsr flags, return reg to restore flags
int sse_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
//MMX helpers
// get neon register for a MMX reg, create the entry if needed
int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a);
int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a);
// get neon register for a MMX reg, but don't try to synch it if it needed to be created
int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a);
int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a);
//SSE/SSE2 helpers
// get neon register for a SSE reg, create the entry if needed
@@ -600,6 +615,8 @@ int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a);
void fpu_reset(dynarec_arm_t* dyn, int ninst);
// purge the FPU cache (needs 3 scratch registers)
void fpu_purgecache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
void x87_purgecache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
void mmx_purgecache(dynarec_arm_t* dyn, int ninst, int s1);
#ifdef HAVE_TRACE
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
#endif
@@ -630,11 +647,6 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
// PUSH a x86/native couple of address in cstack, using s1, s2, s2+1
void cstack_push(dynarec_arm_t* dyn, int ninst, uintptr_t x86ip, uintptr_t armip, int s1, int s2);
// POP a x86/native couple of address from cstack, and generate the jump is x86 address is s0, use s1, s2 and s2+1 as scratch
void cstack_pop(dynarec_arm_t* dyn, int ninst, int s0, int s1, int s2);
#if STEP < 2
#define PASS2(A)
#else
+30 -14
View File
@@ -19,18 +19,19 @@
#include "arm_printer.h"
#include "dynarec_arm_functions.h"
#include "dynarec_arm_helper.h"
#include "custommem.h"
#ifndef STEP
#error No STEP defined
#endif
void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
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;
int need_epilog = 1;
dyn->tablei = 0;
dyn->sons_size = 0;
// Clean up (because there are multiple passes)
dyn->state_flags = 0;
@@ -39,7 +40,6 @@ void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
// ok, go now
INIT;
while(ok) {
if(dyn->insts && (ninst>dyn->size)) {dynarec_log(LOG_NONE, "Warning, too many inst treated (%d / %d)\n",ninst, dyn->size);}
ip = addr;
if(dyn->insts && (dyn->insts[ninst].x86.barrier==1)) {
NEW_BARRIER_INST;
@@ -76,20 +76,35 @@ void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
if(!ok && !need_epilog && dyn->insts && (addr < (dyn->start+dyn->isize))) {
ok = 1;
}
if(!ok && !need_epilog && !dyn->insts) { // check if need to continue
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 && !need_epilog && !dyn->insts && getProtection(addr+3))
if(*(uint32_t*)addr!=0) { // check if need to continue (but is next 4 bytes are 0, stop)
uintptr_t next = get_closest_next(dyn, addr);
if(next && (
(((next-addr)<15) && is_nops(dyn, addr, next-addr))
||(((next-addr)<30) && is_instructions(dyn, addr, next-addr)) ))
{
dynarec_log(LOG_DEBUG, "Extend block %p, %p -> %p (ninst=%d)\n", dyn, (void*)addr, (void*)next, ninst);
ok = 1;
} else if(next && (next-addr)<30) {
dynarec_log(LOG_DEBUG, "Cannot extend block %p -> %p (%02X %02X %02X %02X %02X %02X %02X %02x)\n", (void*)addr, (void*)next, PK(0), PK(1), PK(2), PK(3), PK(4), PK(5), PK(6), PK(7));
}
}
}
if(ok<0) {ok = 0; need_epilog=1;}
++ninst;
#if STEP == 0
if(ok && !isJumpTableDefault((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);
@@ -97,4 +112,5 @@ void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
}
FINI;
MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d, %d sons)\n", dyn->size, dyn->sons_size);
return addr;
}
+2 -4
View File
@@ -29,9 +29,6 @@ typedef struct dynarec_arm_s {
void* block; // memory pointer where next instruction is emited
uintptr_t arm_start; // start of the arm code
int arm_size; // size of emitted arm code
uintptr_t* table; // jump table
int tablesz; // size of the jump table
int tablei; // index
int state_flags;// actual state for on-demand flags
int x87cache[8];// cache status for the 8 x87 register behind the fpu stack
int x87reg[8]; // reg used for x87cache entry
@@ -39,10 +36,11 @@ typedef struct dynarec_arm_s {
int ssecache[8];// cache status for the 8 SSE(2) registers
int fpuused[24];// all 8..31 double reg from fpu, used by x87, sse and mmx
int x87stack; // cache stack counter
int x87count; // number of x87 register used
int mmxcount; // number of mmx register used (not both mmx and x87 at the same time)
int fpu_scratch;// scratch counter
int fpu_extra_qscratch; // some opcode need an extra quad scratch register
int fpu_reg; // x87/sse/mmx reg counter
int nolinker; // disable use of (smart) linker in the block
int dfnone; // if defered flags is already set to df_none
uintptr_t* next; // variable array of "next" jump address
int next_sz;
-2
View File
@@ -31,7 +31,5 @@ typedef struct instruction_x86_s {
} instruction_x86_t;
void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const char* name);
void tableupdate(void* jumpto, uintptr_t ref, void** table);
void resettable(void** table);
#endif //__DYNAREC_PRIVATE_H_
+2
View File
@@ -289,6 +289,7 @@ ARM_ cond 0 0 0 1 0 0 1 0 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) 0 0 1
ARM_ cond/=1110 0 0 0 1 0 0 1 0 imm12 0 1 1 1 imm4 BKPT #<imm16>
ARMS cond 0 0 0 1 0 0 1 1 Rn (0) (0) (0) (0) imm5 type 0 Rm TEQ<c> <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 1 0 1 0 0 Rn Rt (0) (0) (0) (0) 1 0 0 1 Rm SWPB<c> <Rt>, <Rm>, [<Rn>]
ARM_ cond 0 0 0 1 0 1 1 0 (1) (1) (1) (1) Rd (1) (1) (1) (1) 0 0 0 1 Rm CLZ<c> <Rd>, <Rm>
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 0 1 1 imm4L STRH<c> <Rt>, [<Rn>, #+/-<imm8>]{!}
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 1 0 1 imm4L LDRD<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm8>]{!}
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 1 1 1 imm4L STRD<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm8>]{!}
@@ -375,6 +376,7 @@ ARMs cond 0 1 1 0 1 1 1 sat_imm Rd imm5 sh 0 1 Rn USAT<c> <Rd>, #<imm>, <Rn>{, <
ARM_ cond 0 1 1 0 1 1 1 0 sat_imm Rd (1) (1) (1) (1) 0 0 1 1 Rn USAT16<c> <Rd>, #<imm>, <Rn>
ARM_ cond 0 1 1 0 1 1 1 0 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm UXTB<c> <Rd>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 1 1 0 Rn Rd rotate (0) (0) 0 1 1 1 Rm UXTAB<c> <Rd>, <Rn>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 1 1 1 (1) (1) (1) (1) Rd (1) (1) (1) (1) 0 0 1 1 Rm RBIT<c> <Rd>, <Rm>
ARM_ cond 0 1 1 0 1 1 1 1 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm UXTH<c> <Rd>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 1 1 1 (1) (1) (1) (1) Rd (1) (1) (1) (1) 1 0 1 1 Rm REVSH<c> <Rd>, <Rm>
ARM_ cond 0 1 1 0 1 1 1 1 Rn Rd rotate (0) (0) 0 1 1 1 Rm UXTAH<c> <Rd>, <Rn>, <Rm>{, <rotation>}
+3 -2
View File
@@ -40,7 +40,7 @@ const char* DumpSection(Elf32_Shdr *s, char* SST) {
GO(SHT_HIPROC);
GO(SHT_LOUSER);
GO(SHT_HIUSER);
#ifdef SHT_GNU_versym
#if defined(SHT_GNU_versym) && defined(SHT_GNU_ATTRIBUTES)
GO(SHT_GNU_versym);
GO(SHT_GNU_ATTRIBUTES);
GO(SHT_GNU_HASH);
@@ -100,7 +100,7 @@ const char* DumpDynamic(Elf32_Dyn *s) {
GO(DT_RUNPATH, 0);
GO(DT_FLAGS, 0);
GO(DT_ENCODING, 0);
#ifdef DT_NUM
#if defined(DT_NUM) && defined(DT_TLSDESC_PLT)
GO(DT_NUM, 0);
GO(DT_VALRNGLO, 0);
GO(DT_GNU_PRELINKED, 0);
@@ -193,6 +193,7 @@ const char* DumpRelType(int t)
GO(R_386_TLS_GD_32);
GO(R_386_TLS_DTPMOD32);
GO(R_386_TLS_DTPOFF32);
GO(R_386_TLS_TPOFF32);
#undef GO
default: sprintf(buff, "type: 0x%x (unknown)", t); break;
}
+205 -66
View File
@@ -10,6 +10,7 @@
#include <link.h>
#include <unistd.h>
#include <errno.h>
#include <dlfcn.h>
#include "box86version.h"
#include "elfloader.h"
@@ -27,8 +28,9 @@
#include "callback.h"
#include "dynarec.h"
#include "box86stack.h"
#ifdef DYNAREC
#include "custommem.h"
#include "wine_tools.h"
#ifdef DYNAREC
#include "dynablock.h"
#endif
#include "../emu/x86emu_private.h"
@@ -181,7 +183,9 @@ int AllocElfMemory(box86context_t* context, elfheader_t* head, int mainbin)
uintptr_t start = head->multiblock_offs[j];
uintptr_t end = head->multiblock_offs[j] + head->multiblock_size[j];
start &= ~balign;
if(((bstart>=start) && (bstart<=end)) || ((bend>=start) && (bend<=end)) || ((bstart<start) && (bend>end))) {
if( (head->e_type == ET_DYN) ||
(((bstart>=start) && (bstart<=end)) || ((bend>=start) && (bend<=end)) || ((bstart<start) && (bend>end))))
{
// merge
ok = 1;
if(bstart<start)
@@ -196,18 +200,36 @@ int AllocElfMemory(box86context_t* context, elfheader_t* head, int mainbin)
++n;
}
}
head->multiblock_n = n; // might be less in fact
for (int i=0; i<head->multiblock_n; ++i) {
printf_log(LOG_DEBUG, "Allocating 0x%x memory @%p for Elf \"%s\"\n", head->multiblock_size[i], (void*)head->multiblock_offs[i], head->name);
void* p = mmap((void*)head->multiblock_offs[i], head->multiblock_size[i]
, PROT_READ | PROT_WRITE | PROT_EXEC
, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED
, 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%x/0x%x) for elf \"%s\"\n", (void*)head->multiblock_offs[i], head->multiblock_size[i], head->align, head->name);
return 1;
}
updateProtection((uintptr_t)p, head->multiblock_size[i], PROT_READ | PROT_WRITE | PROT_EXEC);
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%x/0x%x) 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 %p) \"%s\"\n", (void*)head->multiblock_offs[i], p, (void*)head->multiblock_size[i], head->name);
// need to adjust vaddr!
for (int i=0; i<head->numPHEntries; ++i)
if(head->PHEntries[i].p_type == PT_LOAD) {
Elf32_Phdr * e = &head->PHEntries[i];
if(e->p_vaddr>=head->multiblock_offs[i] && e->p_vaddr<(head->multiblock_offs[i]+head->multiblock_size[i])) {
e->p_vaddr = e->p_vaddr - head->multiblock_offs[i] + (uintptr_t)p;
if(!head->delta) head->delta = (intptr_t)p - (intptr_t)head->multiblock_offs[i];
}
}
}
}
setProtection((uintptr_t)p, head->multiblock_size[i], PROT_READ | PROT_WRITE | PROT_EXEC);
head->multiblock[i] = p;
if(p<(void*)head->memory)
head->memory = (char*)p;
@@ -217,13 +239,17 @@ int AllocElfMemory(box86context_t* context, elfheader_t* head, int mainbin)
printf_log(LOG_DEBUG, "Allocating 0x%x 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)?MAP_FIXED:0))
, 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%x/0x%x) for elf \"%s\"\n", (void*)offs, head->memsz, head->align, head->name);
return 1;
}
updateProtection((uintptr_t)p, head->memsz, PROT_READ | PROT_WRITE | PROT_EXEC);
if(offs && (p!=(void*)offs) && (head->e_type!=ET_DYN)) {
printf_log(LOG_NONE, "Error, memory map (@%p 0x%x/0x%x) 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);
head->memory = p;
memset(p, 0, head->memsz);
head->delta = (intptr_t)p - (intptr_t)head->vaddr;
@@ -271,7 +297,7 @@ int LoadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
#ifdef DYNAREC
if(e->p_flags & PF_X) {
dynarec_log(LOG_DEBUG, "Add ELF eXecutable Memory %p:%p\n", dest, (void*)e->p_memsz);
addDBFromAddressRange((uintptr_t)dest, e->p_memsz, 0);
addDBFromAddressRange((uintptr_t)dest, e->p_memsz);
}
#endif
@@ -307,11 +333,13 @@ int ReloadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
printf_log(LOG_DEBUG, "Re-loading block #%i @%p (0x%x/0x%x)\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 #%d (offset=%d, errno=%d/%s)\n", i, e->p_offset, errno, strerror(errno)); return 1;}
#ifdef DYNAREC
cleanDBFromAddressRange((uintptr_t)dest, e->p_memsz, 0);
#endif
mprotect(dest, e->p_memsz, PROT_READ | PROT_WRITE | PROT_EXEC);
setProtection((uintptr_t)dest, e->p_memsz, PROT_READ | PROT_WRITE | PROT_EXEC);
if(e->p_filesz) {
ssize_t r = -1;
#ifdef DYNAREC
unprotectDB((uintptr_t)dest, e->p_memsz);
#endif
if((r=fread(dest, e->p_filesz, 1, f))!=1) {
printf_log(LOG_NONE, "Fail to (re)read PT_LOAD part #%d (dest=%p, size=%d, return=%d, feof=%d/ferror=%d/%s)\n", i, dest, e->p_filesz, r, feof(f), ferror(f), strerror(ferror(f)));
return 1;
@@ -325,6 +353,26 @@ int ReloadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
// TLS data are just a copy, no need to re-load it
return 0;
}
int FindR386COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint32_t** p)
{
if(!h)
return 0;
Elf32_Rel * rel = (Elf32_Rel *)(h->rel + h->delta);
if(!h->rel)
return 0;
int cnt = h->relsz / h->relent;
for (int i=0; i<cnt; ++i) {
int t = ELF32_R_TYPE(rel[i].r_info);
Elf32_Sym *sym = &h->DynSym[ELF32_R_SYM(rel[i].r_info)];
const char* symname = SymName(h, sym);
if(!strcmp(symname, name) && t==R_386_COPY) {
*offs = sym->st_value + h->delta;
*p = (uint32_t*)(rel[i].r_offset + h->delta);
return 1;
}
}
return 0;
}
int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cnt, Elf32_Rel *rel)
{
@@ -338,6 +386,14 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cn
uintptr_t offs = 0;
uintptr_t end = 0;
uintptr_t tmp = 0;
int version = head->VerSym?((Elf32_Half*)((uintptr_t)head->VerSym+head->delta))[ELF32_R_SYM(rel[i].r_info)]:0;
const char* ver = GetSymbolVersion(head, version);
char SymbolVersionned[501];
strncpy(SymbolVersionned, symname, 500);
if(ver) {
strncat(SymbolVersionned, "@", 500);
strncat(SymbolVersionned, ver, 500);
}
elfheader_t* h_tls = head;
if(bind==STB_LOCAL) {
offs = sym->st_value + head->delta;
@@ -349,16 +405,23 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cn
offs = sym->st_value + head->delta;
end = offs + sym->st_size;
}
// so weak symbol are the one left
// so weak symbol are the one left, and try versionned symbol first
if(!offs && !end) {
h_tls = NULL;
if(local_maplib)
GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end);
if(!offs && !end)
GetGlobalSymbolStartEnd(maplib, symname, &offs, &end);
if(local_maplib) {
GetGlobalSymbolStartEnd(local_maplib, SymbolVersionned, &offs, &end);
if(!offs && !end)
GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end);
}
if(!offs && !end) {
GetGlobalSymbolStartEnd(maplib, SymbolVersionned, &offs, &end);
if(!offs && !end)
GetGlobalSymbolStartEnd(maplib, symname, &offs, &end);
}
}
}
uintptr_t globoffs, globend;
uint32_t* globp;
int delta;
switch(t) {
case R_386_NONE:
@@ -385,6 +448,26 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cn
}
}
break;
case R_386_TLS_TPOFF32:
// Non-negated offset in static TLS block???
{
if(h_tls)
offs = sym->st_value;
else {
if(local_maplib)
h_tls = GetGlobalSymbolElf(local_maplib, symname);
if(!h_tls)
h_tls = GetGlobalSymbolElf(maplib, symname);
}
if(h_tls) {
delta = *(int*)p;
printf_log(LOG_DUMP, "Applying %s %s on %s @%p (%d -> %d)\n", (bind==STB_LOCAL)?"Local":"Global", DumpRelType(t), symname, p, delta, (int32_t)offs + h_tls->tlsbase);
*p = (uint32_t)(-((int32_t)offs + h_tls->tlsbase));
} else {
printf_log(LOG_INFO, "Warning, cannot apply %s %s on %s @%p (%d), no elf_header found\n", (bind==STB_LOCAL)?"Local":"Global", DumpRelType(t), symname, p, (int32_t)offs);
}
}
break;
case R_386_PC32:
if (!offs) {
printf_log(LOG_NONE, "Error: Global Symbol %s not found, cannot apply R_386_PC32 @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
@@ -395,18 +478,59 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cn
*p += offs;
break;
case R_386_GLOB_DAT:
// Look for same symbol already loaded but not in self (so no need for local_maplib here)
if (GetGlobalNoWeakSymbolStartEnd(maplib, symname, &globoffs, &globend)) {
offs = globoffs;
end = globend;
}
if (!offs) {
if(strcmp(symname, "__gmon_start__"))
printf_log(LOG_NONE, "Error: Global Symbol %s not found, cannot apply R_386_GLOB_DAT @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
// return -1;
if(head!=my_context->elfs[0] && !IsGlobalNoWeakSymbolInNative(maplib, symname) && FindR386COPYRel(my_context->elfs[0], symname, &globoffs, &globp)) {
// set global offs / size for the symbol
offs = sym->st_value + head->delta;
end = offs + sym->st_size;
if(sym->st_size) {
printf_log(LOG_DUMP, "Apply %s R_386_GLOB_DAT with R_386_COPY @%p/%p (%p/%p -> %p/%p) size=%d on sym=%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);
memmove((void*)globoffs, (void*)offs, sym->st_size); // preapply to copy part from lib to main elf
AddWeakSymbol(GetGlobalData(maplib), symname, offs, sym->st_size);
} else {
printf_log(LOG_DUMP, "Apply %s R_386_GLOB_DAT with R_386_COPY @%p/%p (%p/%p -> %p/%p) null sized on sym=%s \n", (bind==STB_LOCAL)?"Local":"Global", p, globp, (void*)(p?(*p):0), (void*)(globp?(*globp):0), (void*)offs, (void*)globoffs, symname);
}
*p = globoffs;
} else {
printf_log(LOG_DUMP, "Apply %s R_386_GLOB_DAT @%p (%p -> %p) on sym=%s\n", (bind==STB_LOCAL)?"Local":"Global", p, (void*)(p?(*p):0), (void*)offs, symname);
*p = offs;
// Look for same symbol already loaded but not in self (so no need for local_maplib here)
if (GetGlobalNoWeakSymbolStartEnd(maplib, symname, &globoffs, &globend)) {
offs = globoffs;
end = globend;
}
if (!offs) {
if(strcmp(symname, "__gmon_start__"))
printf_log(LOG_NONE, "Error: Global Symbol %s not found, cannot apply R_386_GLOB_DAT @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
} else {
printf_log(LOG_DUMP, "Apply %s R_386_GLOB_DAT @%p (%p -> %p) on sym=%s\n", (bind==STB_LOCAL)?"Local":"Global", p, (void*)(p?(*p):0), (void*)offs, symname);
*p = offs;
}
}
break;
case R_386_COPY:
if(offs) {
uintptr_t old_offs = offs;
uintptr_t old_end = end;
offs = 0;
GetSymbolStartEnd(GetGlobalData(maplib), symname, &offs, &end); // try globaldata symbols first
if(offs==0) {
if(local_maplib)
GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head);
if(!offs)
GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head); // get original copy if any
}
if(!offs) {
offs = old_offs;
end = old_end;
}
printf_log(LOG_DUMP, "Apply %s R_386_COPY @%p with sym=%s, @%p size=%d (", (bind==STB_LOCAL)?"Local":"Global", p, symname, (void*)offs, sym->st_size);
memmove(p, (void*)offs, sym->st_size);
if(LOG_DUMP<=box86_log) {
uint32_t*k = (uint32_t*)p;
for (int i=0; i<((sym->st_size>128)?128:sym->st_size); i+=4, ++k)
printf_log(LOG_DUMP, "%s0x%08X", i?" ":"", *k);
printf_log(LOG_DUMP, "%s)\n", (sym->st_size>128)?" ...":"");
}
} else {
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_COPY @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
}
break;
case R_386_RELATIVE:
@@ -468,6 +592,7 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cn
tmp = (uintptr_t)(*p);
if (bind==STB_LOCAL
|| ((symname && strstr(symname, "g_cclosure_marshal_")==symname))
|| ((symname && strstr(symname, "__pthread_unwind_next")==symname))
|| !tmp
|| !((tmp>=head->plt && tmp<head->plt_end) || (tmp>=head->gotplt && tmp<head->gotplt_end))
) {
@@ -480,38 +605,19 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cn
// return -1;
} else {
if(p) {
printf_log(LOG_DUMP, "Apply %s R_386_JMP_SLOT @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)offs);
printf_log(LOG_DUMP, "Apply %s R_386_JMP_SLOT @%p with sym=%s(%s) (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, SymbolVersionned, *(void**)p, (void*)offs);
*p = offs;
} else {
printf_log(LOG_NONE, "Warning, Symbol %s found, but Jump Slot Offset is NULL \n", symname);
}
}
} else {
printf_log(LOG_DUMP, "Preparing (if needed) %s R_386_JMP_SLOT @%p (0x%x->0x%0x) with sym=%s to be apply later\n", (bind==STB_LOCAL)?"Local":"Global", p, *p, *p+head->delta, symname);
printf_log(LOG_DUMP, "Preparing (if needed) %s R_386_JMP_SLOT @%p (0x%x->0x%0x) with sym=%s(%s/version %d) to be apply later\n", (bind==STB_LOCAL)?"Local":"Global", p, *p, *p+head->delta, symname, SymbolVersionned, version);
*p += head->delta;
}
break;
case R_386_COPY:
if(offs) {
offs = 0;
if(local_maplib)
GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head);
if(!offs)
GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head); // get original copy if any
printf_log(LOG_DUMP, "Apply %s R_386_COPY @%p with sym=%s, @%p size=%d (", (bind==STB_LOCAL)?"Local":"Global", p, symname, (void*)offs, sym->st_size);
memmove(p, (void*)offs, sym->st_size);
if(LOG_DUMP<=box86_log) {
uint32_t*k = (uint32_t*)p;
for (int i=0; i<((sym->st_size>128)?128:sym->st_size); i+=4, ++k)
printf_log(LOG_DUMP, "%s0x%08X", i?" ":"", *k);
printf_log(LOG_DUMP, "%s)\n", (sym->st_size>128)?" ...":"");
}
} else {
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_COPY @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
}
break;
default:
printf_log(LOG_INFO, "Warning, don't know of to handle rel #%d %s (%p)\n", i, DumpRelType(ELF32_R_TYPE(rel[i].r_info)), p);
printf_log(LOG_INFO, "Warning, don't know of to handle rel #%d %s (%p) for %s\n", i, DumpRelType(ELF32_R_TYPE(rel[i].r_info)), p, symname?symname:"(nil)");
}
}
return 0;
@@ -614,7 +720,7 @@ Elf32_Sym* GetFunction(elfheader_t* h, const char* name)
// TODO: create a hash on named to avoid this loop
for (int i=0; i<h->numSymTab; ++i) {
int type = ELF32_ST_TYPE(h->SymTab[i].st_info);
if(/*h->SymTab[i].st_info == 18*/type==STT_FUNC) { // TODO: this "18" is probably defined somewhere
if(type==STT_FUNC) {
const char * symname = h->StrTab+h->SymTab[i].st_name;
if(strcmp(symname, name)==0) {
return h->SymTab+i;
@@ -628,7 +734,7 @@ Elf32_Sym* GetElfObject(elfheader_t* h, const char* name)
{
for (int i=0; i<h->numSymTab; ++i) {
int type = ELF32_ST_TYPE(h->SymTab[i].st_info);
if(/*h->SymTab[i].st_info == 16*/type==STT_OBJECT) {
if(type==STT_OBJECT) {
const char * symname = h->StrTab+h->SymTab[i].st_name;
if(strcmp(symname, name)==0) {
return h->SymTab+i;
@@ -692,7 +798,7 @@ void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* wea
int vis = h->SymTab[i].st_other&0x3;
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(bind==10/*STB_GNU_UNIQUE*/ && FindGlobalSymbol(maplib, symname))
if((bind==STB_GNU_UNIQUE /*|| (bind==STB_GLOBAL && type==STT_FUNC)*/) && FindGlobalSymbol(maplib, symname))
continue;
uintptr_t offs = (type==STT_TLS)?h->SymTab[i].st_value:(h->SymTab[i].st_value + h->delta);
uint32_t sz = h->SymTab[i].st_size;
@@ -717,7 +823,7 @@ void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* wea
//st_shndx==65521 means ABS value
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)) {
if(bind==10/*STB_GNU_UNIQUE*/ && FindGlobalSymbol(maplib, symname))
if((bind==STB_GNU_UNIQUE || (bind==STB_GLOBAL && type==STT_FUNC)) && FindGlobalSymbol(maplib, symname))
continue;
uintptr_t offs = (type==STT_TLS)?h->DynSym[i].st_value:(h->DynSym[i].st_value + h->delta);
uint32_t sz = h->DynSym[i].st_size;
@@ -749,7 +855,7 @@ $PLATFORM – Expands to the processor type of the current machine (see the
uname(1) man page description of the -i option). For more details of this token
expansion, see “System Specific Shared Objects”
*/
int LoadNeededLibs(elfheader_t* h, lib_t *maplib, needed_libs_t* neededlibs, int local, box86context_t *box86, x86emu_t* emu)
int LoadNeededLibs(elfheader_t* h, lib_t* maplib, needed_libs_t* neededlibs, library_t* deplib, int local, box86context_t* box86, x86emu_t* emu)
{
DumpDynamicRPath(h);
// update RPATH first
@@ -769,6 +875,21 @@ int LoadNeededLibs(elfheader_t* h, lib_t *maplib, needed_libs_t* neededlibs, int
if(rpath!=rpathref)
free(rpath);
rpath = tmp;
free(origin);
}
while(strstr(rpath, "${ORIGIN}")) {
char* origin = strdup(h->path);
char* p = strrchr(origin, '/');
if(p) *p = '\0'; // remove file name to have only full path, without last '/'
char* tmp = (char*)calloc(1, strlen(rpath)-strlen("${ORIGIN}")+strlen(origin)+1);
p = strstr(rpath, "${ORIGIN}");
memcpy(tmp, rpath, p-rpath);
strcat(tmp, origin);
strcat(tmp, p+strlen("${ORIGIN}"));
if(rpath!=rpathref)
free(rpath);
rpath = tmp;
free(origin);
}
if(strchr(rpath, '$')) {
printf_log(LOG_INFO, "BOX86: Warning, RPATH with $ variable not supported yet (%s)\n", rpath);
@@ -787,8 +908,8 @@ int LoadNeededLibs(elfheader_t* h, lib_t *maplib, needed_libs_t* neededlibs, int
for (int i=0; i<h->numDynamic; ++i)
if(h->Dynamic[i].d_tag==DT_NEEDED) {
char *needed = h->DynStrTab+h->delta+h->Dynamic[i].d_un.d_val;
// TODO: Add LD_LIBRARY_PATH and RPATH Handling
if(AddNeededLib(maplib, neededlibs, local, needed, box86, emu)) {
// TODO: Add LD_LIBRARY_PATH and RPATH handling
if(AddNeededLib(maplib, neededlibs, deplib, local, needed, box86, emu)) {
printf_log(LOG_INFO, "Error loading needed lib: \"%s\"\n", needed);
if(!allow_missing_libs)
return 1; //error...
@@ -866,9 +987,13 @@ void RunElfFini(elfheader_t* h, x86emu_t *emu)
if(!h || h->fini_done)
return;
h->fini_done = 1;
#ifdef ANDROID
// TODO: Fix .fini_array on Android
printf_log(LOG_DEBUG, "Android does not support Fini for %s\n", ElfName(h));
#else
// first check fini array
Elf32_Addr *addr = (Elf32_Addr*)(h->finiarray + h->delta);
for (int i=0; i<h->finiarray_sz; ++i) {
for (int i=h->finiarray_sz-1; i>=0; --i) {
printf_log(LOG_DEBUG, "Calling Fini[%d] for %s @%p\n", i, ElfName(h), (void*)addr[i]);
RunFunctionWithEmu(emu, 0, (uintptr_t)addr[i], 0);
}
@@ -879,7 +1004,7 @@ void RunElfFini(elfheader_t* h, x86emu_t *emu)
RunFunctionWithEmu(emu, 0, p, 0);
}
h->init_done = 0; // can be re-inited again...
return;
#endif
}
uintptr_t GetElfInit(elfheader_t* h)
@@ -1011,7 +1136,7 @@ dynablocklist_t* GetDynablocksFromAddress(box86context_t *context, uintptr_t add
return ret;
}*/
if(box86_dynarec_forced) {
addDBFromAddressRange(addr, 1, 1);
addDBFromAddressRange(addr, 1);
return getDB(addr>>DYNAMAP_SHIFT);
}
//check if address is in an elf... if yes, grant a block (should I warn)
@@ -1163,34 +1288,48 @@ EXPORT void PltResolver(x86emu_t* emu)
uintptr_t addr = Pop32(emu);
int slot = (int)Pop32(emu);
elfheader_t *h = (elfheader_t*)addr;
printf_log(LOG_DEBUG, "PltResolver: Addr=%p, Slot=%d Return=%p: elf is %s\n", (void*)addr, slot, *(void**)(R_ESP), h->name);
printf_log(LOG_DEBUG, "PltResolver: Addr=%p, Slot=%d Return=%p: elf is %s (VerSym=%p)\n", (void*)addr, slot, *(void**)(R_ESP), h->name, h->VerSym);
Elf32_Rel * rel = (Elf32_Rel *)(h->jmprel + h->delta + slot);
Elf32_Sym *sym = &h->DynSym[ELF32_R_SYM(rel->r_info)];
int bind = ELF32_ST_BIND(sym->st_info);
const char* symname = SymName(h, sym);
int version = h->VerSym?((Elf32_Half*)((uintptr_t)h->VerSym+h->delta))[ELF32_R_SYM(rel->r_info)]:0;
const char* ver = GetSymbolVersion(h, version);
char symnameversionned[501];
strncpy(symnameversionned, symname, 500);
if(ver) {
strncat(symnameversionned, "@", 500);
strncat(symnameversionned, ver, 500);
}
uint32_t *p = (uint32_t*)(rel->r_offset + h->delta);
uintptr_t offs = 0;
uintptr_t end = 0;
library_t* lib = h->lib;
lib_t* local_maplib = GetMaplib(lib);
if(local_maplib)
GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end);
if(!offs && !end)
GetGlobalSymbolStartEnd(my_context->maplib, symname, &offs, &end);
if(local_maplib) {
GetGlobalSymbolStartEnd(local_maplib, symnameversionned, &offs, &end);
if(!offs && !end)
GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end);
}
if(!offs && !end) {
GetGlobalSymbolStartEnd(my_context->maplib, symnameversionned, &offs, &end);
if(!offs && !end)
GetGlobalSymbolStartEnd(my_context->maplib, symname, &offs, &end);
}
if (!offs) {
printf_log(LOG_NONE, "Error: PltReolver: Symbol %s not found, cannot apply R_386_JMP_SLOT @%p (%p) in %s\n", symname, p, *(void**)p, h->name);
printf_log(LOG_NONE, "Error: PltReolver: Symbol %s(%s) not found, cannot apply R_386_JMP_SLOT @%p (%p) in %s\n", symname, symnameversionned, p, *(void**)p, h->name);
emu->quit = 1;
return;
} else {
if(p) {
printf_log(LOG_DEBUG, "PltReolver: Apply %s R_386_JMP_SLOT @%p with sym=%s (%p -> %p / %s)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)offs, ElfName(FindElfAddress(my_context, offs)));
printf_log(LOG_DEBUG, "PltReolver: Apply %s R_386_JMP_SLOT @%p with sym=%s(%s) (%p -> %p / %s)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, symnameversionned,*(void**)p, (void*)offs, ElfName(FindElfAddress(my_context, offs)));
*p = offs;
} else {
printf_log(LOG_NONE, "PltReolver: Warning, Symbol %s found, but Jump Slot Offset is NULL \n", symname);
printf_log(LOG_NONE, "PltReolver: Warning, Symbol %s(%s) found, but Jump Slot Offset is NULL \n", symname, symnameversionned);
}
}
+4
View File
@@ -30,6 +30,10 @@ struct elfheader_s {
int numDynamic;
char* DynStrTab;
int szDynStrTab;
Elf32_Half* VerSym;
Elf32_Verneed* VerNeed;
int szVerNeed;
int e_type;
intptr_t delta; // should be 0
+95 -48
View File
@@ -120,6 +120,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
h->numPHEntries = header.e_phnum;
h->numSHEntries = header.e_shnum;
h->SHIdx = header.e_shstrndx;
h->e_type = header.e_type;
if(header.e_shentsize && header.e_shnum) {
// special cases for nums
if(h->numSHEntries == 0) {
@@ -188,30 +189,79 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
// also grab the DT_STRTAB string table
{
for (int i=0; i<h->numDynamic; ++i) {
if(h->Dynamic[i].d_tag == DT_REL)
h->rel = h->Dynamic[i].d_un.d_ptr;
else if(h->Dynamic[i].d_tag == DT_RELSZ)
h->relsz = h->Dynamic[i].d_un.d_val;
else if(h->Dynamic[i].d_tag == DT_RELENT)
h->relent = h->Dynamic[i].d_un.d_val;
else if(h->Dynamic[i].d_tag == DT_RELA)
h->rela = h->Dynamic[i].d_un.d_ptr;
else if(h->Dynamic[i].d_tag == DT_RELASZ)
h->relasz = h->Dynamic[i].d_un.d_val;
else if(h->Dynamic[i].d_tag == DT_RELAENT)
h->relaent = h->Dynamic[i].d_un.d_val;
else if(h->Dynamic[i].d_tag == DT_PLTGOT)
h->pltgot = h->Dynamic[i].d_un.d_val;
else if(h->Dynamic[i].d_tag == DT_PLTREL)
h->pltrel = h->Dynamic[i].d_un.d_val;
else if(h->Dynamic[i].d_tag == DT_PLTRELSZ)
h->pltsz = h->Dynamic[i].d_un.d_val;
else if(h->Dynamic[i].d_tag == DT_JMPREL)
h->jmprel = h->Dynamic[i].d_un.d_val;
else if(h->Dynamic[i].d_tag == DT_STRTAB)
h->DynStrTab = (char*)(h->Dynamic[i].d_un.d_ptr);
else if(h->Dynamic[i].d_tag == DT_STRSZ)
h->szDynStrTab = h->Dynamic[i].d_un.d_val;
Elf32_Dyn d = h->Dynamic[i];
Elf32_Word val = d.d_un.d_val;
Elf32_Addr ptr = d.d_un.d_ptr;
switch (d.d_tag) {
case DT_REL:
h->rel = ptr;
break;
case DT_RELSZ:
h->relsz = val;
break;
case DT_RELENT:
h->relent = val;
break;
case DT_RELA:
h->rela = ptr;
break;
case DT_RELASZ:
h->relasz = val;
break;
case DT_RELAENT:
h->relaent = val;
break;
case DT_PLTGOT:
h->pltgot = val;
break;
case DT_PLTREL:
h->pltrel = val;
break;
case DT_PLTRELSZ:
h->pltsz = val;
break;
case DT_JMPREL:
h->jmprel = val;
break;
case DT_STRTAB:
h->DynStrTab = (char *)(ptr);
break;
case DT_STRSZ:
h->szDynStrTab = val;
break;
case DT_INIT: // Entry point
h->initentry = ptr;
printf_log(LOG_DEBUG, "The DT_INIT is at address %p\n", (void*)h->initentry);
break;
case DT_INIT_ARRAY:
h->initarray = ptr;
printf_log(LOG_DEBUG, "The DT_INIT_ARRAY is at address %p\n", (void*)h->initarray);
break;
case DT_INIT_ARRAYSZ:
h->initarray_sz = val / sizeof(Elf32_Addr);
printf_log(LOG_DEBUG, "The DT_INIT_ARRAYSZ is %d\n", h->initarray_sz);
break;
case DT_FINI: // Exit hook
h->finientry = ptr;
printf_log(LOG_DEBUG, "The DT_FINI is at address %p\n", (void*)h->finientry);
break;
case DT_FINI_ARRAY:
h->finiarray = ptr;
printf_log(LOG_DEBUG, "The DT_FINI_ARRAY is at address %p\n", (void*)h->finiarray);
break;
case DT_FINI_ARRAYSZ:
h->finiarray_sz = val / sizeof(Elf32_Addr);
printf_log(LOG_DEBUG, "The DT_FINI_ARRAYSZ is %d\n", h->finiarray_sz);
break;
case DT_VERNEEDNUM:
h->szVerNeed = val / sizeof(Elf32_Verneed);
printf_log(LOG_DEBUG, "The DT_VERNEEDNUM is %d\n", h->szVerNeed);
break;
case DT_VERNEED:
h->VerNeed = (Elf32_Verneed*)ptr;
printf_log(LOG_DEBUG, "The DT_VERNEED is at address %p\n", h->VerNeed);
break;
}
}
if(h->rel) {
if(h->relent != sizeof(Elf32_Rel)) {
@@ -269,31 +319,11 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
h->plt_end = h->plt + h->SHEntries[ii].sh_size;
printf_log(LOG_DEBUG, "The PLT Table is at address %p..%p\n", (void*)h->plt, (void*)h->plt_end);
}
// look for .init entry point
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".init");
// grab version of symbols
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".gnu.version");
if(ii) {
h->initentry = h->SHEntries[ii].sh_addr;
printf_log(LOG_DEBUG, "The .init is at address %p\n", (void*)h->initentry);
}
// and .init_array
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".init_array");
if(ii) {
h->initarray_sz = h->SHEntries[ii].sh_size / sizeof(Elf32_Addr);
h->initarray = (uintptr_t)(h->SHEntries[ii].sh_addr);
printf_log(LOG_DEBUG, "The .init_array is at address %p, and have %d elements\n", (void*)h->initarray, h->initarray_sz);
}
// look for .fini entry point
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".fini");
if(ii) {
h->finientry = h->SHEntries[ii].sh_addr;
printf_log(LOG_DEBUG, "The .fini is at address %p\n", (void*)h->finientry);
}
// and .fini_array
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".fini_array");
if(ii) {
h->finiarray_sz = h->SHEntries[ii].sh_size / sizeof(Elf32_Addr);
h->finiarray = (uintptr_t)(h->SHEntries[ii].sh_addr);
printf_log(LOG_DEBUG, "The .fini_array is at address %p, and have %d elements\n", (void*)h->finiarray, h->finiarray_sz);
h->VerSym = (Elf32_Half*)(h->SHEntries[ii].sh_addr);
printf_log(LOG_DEBUG, "The .gnu.version is at address %p\n", h->VerSym);
}
// grab .text for main code
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".text");
@@ -310,3 +340,20 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
return h;
}
const char* GetSymbolVersion(elfheader_t* h, int version)
{
if(!h->VerNeed || (version<2))
return NULL;
Elf32_Verneed *ver = (Elf32_Verneed*)((uintptr_t)h->VerNeed + h->delta);
while(ver) {
Elf32_Vernaux *aux = (Elf32_Vernaux*)((uintptr_t)ver + ver->vn_aux);
for(int j=0; j<ver->vn_cnt; ++j) {
if(aux->vna_other==version)
return h->DynStr+aux->vna_name;
aux = (Elf32_Vernaux*)((uintptr_t)aux + aux->vna_next);
}
ver = ver->vn_next?((Elf32_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
}
return NULL;
}
+3 -3
View File
@@ -111,8 +111,8 @@
} else getecommono(A, reg32_t, O)
#define getem(A) \
if((nextop&0xC0)==0xC0) { \
A = &emu->mmx[(nextop&7)]; \
} else getecommon(A, mmx_regs_t)
A = &emu->mmx87[(nextop&7)]; \
} else getecommon(A, mmx87_regs_t)
#define getex(A) \
if((nextop&0xC0)==0xC0) { \
A = &emu->xmm[(nextop&7)]; \
@@ -141,7 +141,7 @@
#define EX opex
#define GB emu->regs[(nextop>>3)&3].byte[(nextop>>5)&0x1]
#define GD emu->regs[((nextop&0x38)>>3)]
#define GM emu->mmx[((nextop&0x38)>>3)]
#define GM emu->mmx87[((nextop&0x38)>>3)]
#define GX emu->xmm[((nextop&0x38)>>3)]
// Alias
+59 -34
View File
@@ -29,7 +29,12 @@
NEXT;
_0f_0x0B: /* UD2 */
kill(getpid(), SIGILL); // this is undefined instruction
emu->old_ip = R_EIP;
R_EIP = ip-2;
emit_signal(emu, SIGILL, (void*)R_EIP, 0);
ip = R_EIP;
if(emu->quit) goto fini;
STEP;
NEXT;
_0f_0x10: /* MOVUPS Gx,Ex */
nextop = F8;
@@ -144,7 +149,7 @@
// rounding should be done; and indefinite integer should also be assigned if overflow or NaN/Inf
nextop = F8;
GET_EX;
switch(emu->round) {
switch((emu->mxcsr>>13)&3) {
case ROUND_Nearest:
GM.sd[1] = floorf(EX->f[1]+0.5f);
GM.sd[0] = floorf(EX->f[0]+0.5f);
@@ -244,6 +249,15 @@
goto _default;
}
NEXT;
_0f_0x3F:
emu->old_ip = R_EIP;
R_EIP = ip-2;
emit_signal(emu, SIGILL, (void*)R_EIP, 0);
ip = R_EIP;
if(emu->quit) goto fini;
STEP;
NEXT;
#define GOCOND(BASE, PREFIX, CONDITIONAL) \
_0f_##BASE##_0: \
@@ -478,10 +492,14 @@
GM.sb[1] = (GM.sw[1] > 127) ? 127 : ((GM.sw[1] < -128) ? -128 : GM.sw[1]);
GM.sb[2] = (GM.sw[2] > 127) ? 127 : ((GM.sw[2] < -128) ? -128 : GM.sw[2]);
GM.sb[3] = (GM.sw[3] > 127) ? 127 : ((GM.sw[3] < -128) ? -128 : GM.sw[3]);
GM.sb[4] = (EM->sw[0] > 127) ? 127 : ((EM->sw[0] < -128) ? -128 : EM->sw[0]);
GM.sb[5] = (EM->sw[1] > 127) ? 127 : ((EM->sw[1] < -128) ? -128 : EM->sw[1]);
GM.sb[6] = (EM->sw[2] > 127) ? 127 : ((EM->sw[2] < -128) ? -128 : EM->sw[2]);
GM.sb[7] = (EM->sw[3] > 127) ? 127 : ((EM->sw[3] < -128) ? -128 : EM->sw[3]);
if(EM==&GM)
GM.ud[1] = GM.ud[0];
else {
GM.sb[4] = (EM->sw[0] > 127) ? 127 : ((EM->sw[0] < -128) ? -128 : EM->sw[0]);
GM.sb[5] = (EM->sw[1] > 127) ? 127 : ((EM->sw[1] < -128) ? -128 : EM->sw[1]);
GM.sb[6] = (EM->sw[2] > 127) ? 127 : ((EM->sw[2] < -128) ? -128 : EM->sw[2]);
GM.sb[7] = (EM->sw[3] > 127) ? 127 : ((EM->sw[3] < -128) ? -128 : EM->sw[3]);
}
NEXT;
_0f_0x64: /* PCMPGTB Gm,Em */
nextop = F8;
@@ -509,33 +527,42 @@
GET_EM;
for(int i=0; i<4; ++i)
GM.ub[i] = (GM.sw[i]<0)?0:((GM.sw[i]>0xff)?0xff:GM.sw[i]);
for(int i=0; i<4; ++i)
GM.ub[4+i] = (EM->sw[i]<0)?0:((EM->sw[i]>0xff)?0xff:EM->sw[i]);
if(EM==&GM)
GM.ud[1] = GM.ud[0];
else
for(int i=0; i<4; ++i)
GM.ub[4+i] = (EM->sw[i]<0)?0:((EM->sw[i]>0xff)?0xff:EM->sw[i]);
NEXT;
_0f_0x68: /* PUNPCKHBW Gm,Em */
nextop = F8;
GET_EM;
if(EM==&GM) {eam1 = GM; EM = &eam1;} // copy is needed
for(int i=0; i<4; ++i)
GM.ub[2 * i] = GM.ub[i + 4];
for(int i=0; i<4; ++i)
GM.ub[2 * i + 1] = EM->ub[i + 4];
if(EM==&GM)
for(int i=0; i<4; ++i)
GM.ub[2 * i + 1] = GM.ub[2 * i];
else
for(int i=0; i<4; ++i)
GM.ub[2 * i + 1] = EM->ub[i + 4];
NEXT;
_0f_0x69: /* PUNPCKHWD Gm,Em */
nextop = F8;
GET_EM;
if(EM==&GM) {eam1 = GM; EM = &eam1;} // copy is needed
for(int i=0; i<2; ++i)
GM.uw[2 * i] = GM.uw[i + 2];
for(int i=0; i<2; ++i)
GM.uw[2 * i + 1] = EM->uw[i + 2];
if(EM==&GM)
for(int i=0; i<2; ++i)
GM.uw[2 * i + 1] = GM.uw[2 * i];
else
for(int i=0; i<2; ++i)
GM.uw[2 * i + 1] = EM->uw[i + 2];
NEXT;
_0f_0x6A: /* PUNPCKHDQ Gm,Em */
nextop = F8;
GET_EM;
if(EM==&GM) {eam1 = GM; EM = &eam1;} // copy is needed
GM.ud[0] = GM.ud[1];
GM.ud[1] = EM->ud[1];
if(EM!=&GM)
GM.ud[1] = EM->ud[1];
NEXT;
_0f_0x6B: /* PACKSSDW Gm,Em */
nextop = F8;
@@ -543,8 +570,11 @@
if(EM==&GM) {eam1 = GM; EM = &eam1;} // copy is needed
for(int i=0; i<2; ++i)
GM.sw[i] = (GM.sd[i]<-32768)?-32768:((GM.sd[i]>32767)?32767:GM.sd[i]);
for(int i=0; i<2; ++i)
GM.sw[2+i] = (EM->sd[i]<-32768)?-32768:((EM->sd[i]>32767)?32767:EM->sd[i]);
if(EM==&GM)
GM.ud[1] = GM.ud[0];
else
for(int i=0; i<2; ++i)
GM.sw[2+i] = (EM->sd[i]<-32768)?-32768:((EM->sd[i]>32767)?32767:EM->sd[i]);
NEXT;
_0f_0x6E: /* MOVD Gm, Ed */
@@ -762,22 +792,17 @@
// should save flags & all
// copy MMX regs...
for(int i=0; i<8; ++i)
memcpy(((void*)(ED))+32+i*16, &emu->mmx[0], sizeof(emu->mmx[0]));
memcpy(((void*)(ED))+32+i*16, &emu->mmx87[0], sizeof(emu->mmx87[0]));
// copy SSE regs
memcpy(((void*)(ED))+160, &emu->xmm[0], sizeof(emu->xmm));
// put also FPU regs in a reserved area...
for(int i=0; i<8; ++i)
memcpy(((void*)(ED))+416+i*8, &emu->fpu[0], sizeof(emu->fpu[0]));
break;
case 1: /* FXRSTOR m512byte */
// should restore flags & all
// copy back MMX regs...
for(int i=0; i<8; ++i)
memcpy(&emu->mmx[i], ((void*)(ED))+32+i*16, sizeof(emu->mmx[0]));
memcpy(&emu->mmx87[i], ((void*)(ED))+32+i*16, sizeof(emu->mmx87[0]));
// copy SSE regs
memcpy(&emu->xmm[0], ((void*)(ED))+160/4, sizeof(emu->xmm));
for(int i=0; i<8; ++i)
memcpy(&emu->fpu[0], ((void*)(ED))+416+i*8, sizeof(emu->fpu[0]));
break;
case 2: /* LDMXCSR Md */
emu->mxcsr = ED->dword[0];
@@ -795,7 +820,6 @@
GD.dword[0] = imul32(emu, GD.dword[0], ED->dword[0]);
NEXT;
_0f_0xB0: /* CMPXCHG Eb,Gb */
CHECK_FLAGS(emu);
nextop = F8;
GET_EB;
cmp8(emu, R_AL, EB->byte[0]);
@@ -1192,20 +1216,17 @@
GM.sd[i] >>= tmp8u;
}
NEXT;
_0f_0xE3: /* PSRAQ Gm, Em */
_0f_0xE3: /* PAVGW Gm, Em */
nextop = F8;
GET_EM;
if(EM->q>63)
tmp8u = 64;
else
tmp8u = EM->ub[0];
GM.sq >>= tmp8u;
for(int i=0; i<4; ++i)
GM.uw[i] = ((uint32_t)GM.uw[i]+EM->uw[i]+1)>>1;
NEXT;
_0f_0xE4: /* PMULHUW Gm, Em */
nextop = F8;
GET_EM;
for(int i=0; i<4; ++i) {
tmp32u = (int32_t)GM.uw[i] * EM->uw[i];
tmp32u = (uint32_t)GM.uw[i] * EM->uw[i];
GM.uw[i] = (tmp32u>>16)&0xffff;
}
NEXT;
@@ -1358,7 +1379,11 @@
for(int i=0; i<2; ++i)
GM.sd[i] -= EM->sd[i];
NEXT;
_0f_0xFB: /* PSUBQ Gm,Em */
nextop = F8;
GET_EM;
GM.sq -= EM->sq;
NEXT;
_0f_0xFC: /* PADDB Gm, Em */
nextop = F8;
GET_EM;
+8 -1
View File
@@ -153,6 +153,13 @@
R_AX = Pop16(emu);
NEXT;
_66_0x64:
R_EIP = ip-2;
RunFS66(emu, GetFSBaseEmu(emu));
ip = R_EIP;
STEP;
NEXT;
_66_0x66:
goto _0x66; // 0x66 0x66 => can remove one 0x66
@@ -401,7 +408,7 @@
_66_0xF0: /* LOCK prefix */
emu->old_ip = R_EIP;
R_EIP = ip;
R_EIP = ip - 2;
RunLock66(emu);
ip = R_EIP;
if(emu->quit) goto fini;
+5 -5
View File
@@ -8,9 +8,9 @@
case 0xC5:
case 0xC6:
case 0xC7: /* FLD STx */
ll = ST(nextop&7).ll;
ll = ST(nextop&7).q;
fpu_do_push(emu);
ST0.ll = ll;
ST0.q = ll;
break;
case 0xC8:
case 0xC9:
@@ -20,9 +20,9 @@
case 0xCD:
case 0xCE:
case 0xCF: /* FXCH STx */
ll = ST(nextop&7).ll;
ST(nextop&7).ll = ST0.ll;
ST0.ll = ll;
ll = ST(nextop&7).q;
ST(nextop&7).q = ST0.q;
ST0.q = ll;
break;
case 0xD0: /* FNOP */
+4 -4
View File
@@ -11,7 +11,7 @@
case 0xC7:
CHECK_FLAGS(emu);
if(ACCESS_FLAG(F_CF))
ST0.ll = ST(nextop&7).ll;
ST0.q = ST(nextop&7).q;
break;
case 0xC8: /* FCMOVE ST(0), ST(i) */
case 0xC9:
@@ -23,7 +23,7 @@
case 0xCF:
CHECK_FLAGS(emu);
if(ACCESS_FLAG(F_ZF))
ST0.ll = ST(nextop&7).ll;
ST0.q = ST(nextop&7).q;
break;
case 0xD0: /* FCMOVBE ST(0), ST(i) */
case 0xD1:
@@ -35,7 +35,7 @@
case 0xD7:
CHECK_FLAGS(emu);
if(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF))
ST0.ll = ST(nextop&7).ll;
ST0.q = ST(nextop&7).q;
break;
case 0xD8: /* FCMOVU ST(0), ST(i) */
case 0xD9:
@@ -47,7 +47,7 @@
case 0xDF:
CHECK_FLAGS(emu);
if(ACCESS_FLAG(F_PF))
ST0.ll = ST(nextop&7).ll;
ST0.q = ST(nextop&7).q;
break;
case 0xE9: /* FUCOMPP */
+6 -6
View File
@@ -10,7 +10,7 @@
case 0xC7:
CHECK_FLAGS(emu);
if(!ACCESS_FLAG(F_CF))
ST0.ll = ST(nextop&7).ll;
ST0.q = ST(nextop&7).q;
break;
case 0xC8: /* FCMOVNE ST(0), ST(i) */
case 0xC9:
@@ -22,7 +22,7 @@
case 0xCF:
CHECK_FLAGS(emu);
if(!ACCESS_FLAG(F_ZF))
ST0.ll = ST(nextop&7).ll;
ST0.q = ST(nextop&7).q;
break;
case 0xD0: /* FCMOVNBE ST(0), ST(i) */
case 0xD1:
@@ -34,7 +34,7 @@
case 0xD7:
CHECK_FLAGS(emu);
if(!(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)))
ST0.ll = ST(nextop&7).ll;
ST0.q = ST(nextop&7).q;
break;
case 0xD8: /* FCMOVNU ST(0), ST(i) */
case 0xD9:
@@ -46,7 +46,7 @@
case 0xDF:
CHECK_FLAGS(emu);
if(!ACCESS_FLAG(F_PF))
ST0.ll = ST(nextop&7).ll;
ST0.q = ST(nextop&7).q;
break;
case 0xE1: /* FDISI8087_NOP */
@@ -133,11 +133,11 @@
fpu_do_push(emu);
memcpy(&STld(0).ld, ED, 10);
LD2D(&STld(0), &ST(0).d);
STld(0).ref = ST0.ll;
STld(0).ref = ST0.q;
break;
case 7: /* FSTP tbyte */
GET_ED;
if(ST0.ll!=STld(0).ref)
if(ST0.q!=STld(0).ref)
D2LD(&ST0.d, ED);
else
memcpy(ED, &STld(0).ld, 10);
+1 -1
View File
@@ -38,7 +38,7 @@
case 0xDD:
case 0xDE:
case 0xDF: /* FCOMP */
fpu_fcom(emu, ST(nextop&7).d); // TODO: is this ok?
fpu_fcom(emu, ST(nextop&7).d);
fpu_do_pop(emu);
break;
case 0xE0:
+2 -2
View File
@@ -20,7 +20,7 @@
case 0xD5:
case 0xD6:
case 0xD7:
ST(nextop&7).ll = ST0.ll;
ST(nextop&7).q = ST0.q;
break;
case 0xD8: /* FSTP ST0, STx */
case 0xD9:
@@ -30,7 +30,7 @@
case 0xDD:
case 0xDE:
case 0xDF:
ST(nextop&7).ll = ST0.ll;
ST(nextop&7).q = ST0.q;
fpu_do_pop(emu);
break;
case 0xE0: /* FUCOM ST0, STx */
+15 -11
View File
@@ -12,6 +12,18 @@
fpu_do_pop(emu);
break;
case 0xD0: /* FSTP STx, ST0 */
case 0xD1:
case 0xD2:
case 0xD3:
case 0xD4:
case 0xD5:
case 0xD6:
case 0xD7:
ST(nextop&7).q = ST0.q;
fpu_do_pop(emu);
break;
case 0xE0: /* FNSTSW AX */
emu->sw.f.F87_TOP = emu->top&7;
R_AX = emu->sw.x16;
@@ -49,14 +61,6 @@
case 0xCD:
case 0xCE:
case 0xCF:
case 0xD0:
case 0xD1:
case 0xD2:
case 0xD3:
case 0xD4:
case 0xD5:
case 0xD6:
case 0xD7:
case 0xD8:
case 0xD9:
case 0xDA:
@@ -122,7 +126,7 @@
fpu_do_push(emu);
ST0.d = tmp64s;
STll(0).ll = tmp64s;
STll(0).ref = ST0.ll;
STll(0).ref = ST0.q;
break;
case 6: /* FBSTP tbytes, ST0 */
GET_ED;
@@ -133,7 +137,7 @@
GET_ED;
if((uintptr_t)ED & 0x7) {
// un-aligned!
if(STll(0).ref==ST(0).ll)
if(STll(0).ref==ST(0).q)
memcpy(ED, &STll(0).ll, sizeof(int64_t));
else {
int64_t i64;
@@ -144,7 +148,7 @@
memcpy(ED, &i64, sizeof(int64_t));
}
} else {
if(STll(0).ref==ST(0).ll)
if(STll(0).ref==ST(0).q)
*(int64_t*)ED = STll(0).ll;
else {
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, -(double)(int64_t)0x7fffffffffffffffLL) || !isfinite(ST0.d))
+19 -4
View File
@@ -35,7 +35,7 @@
case 0x2D: /* CVTSD2SI Gd, Ex */
nextop = F8;
GET_EX;
switch(emu->round) {
switch((emu->mxcsr>>13)&3) {
case ROUND_Nearest:
GD.sdword[0] = floor(EX->d[0]+0.5);
break;
@@ -66,7 +66,6 @@
GET_EX;
GX.d[0] *= EX->d[0];
break;
case 0x5A: /* CVTSD2SS Gx, Ex */
nextop = F8;
GET_EX;
@@ -248,8 +247,24 @@
case 0xE6: /* CVTPD2DQ Gx, Ex */
nextop = F8;
GET_EX;
GX.sd[0] = EX->d[0];
GX.sd[1] = EX->d[1];
switch((emu->mxcsr>>13)&3) {
case ROUND_Nearest:
GX.sd[0] = floor(EX->d[0]+0.5);
GX.sd[1] = floor(EX->d[1]+0.5);
break;
case ROUND_Down:
GX.sd[0] = floor(EX->d[0]);
GX.sd[1] = floor(EX->d[1]);
break;
case ROUND_Up:
GX.sd[0] = ceil(EX->d[0]);
GX.sd[1] = ceil(EX->d[1]);
break;
case ROUND_Chop:
GX.sd[0] = EX->d[0];
GX.sd[1] = EX->d[1];
break;
}
GX.q[1] = 0;
break;
+1 -1
View File
@@ -52,7 +52,7 @@
case 0x2D: /* CVTSS2SI Gd, Ex */
nextop = F8;
GET_EX;
switch(emu->round) {
switch((emu->mxcsr>>13)&3) {
case ROUND_Nearest:
GD.sdword[0] = floor(EX->f[0]+0.5);
break;
+46 -29
View File
@@ -5,6 +5,7 @@
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/mman.h>
#include "debug.h"
#include "box86stack.h"
@@ -15,6 +16,10 @@
#include "x86run.h"
#include "x86run_private.h"
#include "callback.h"
#include "bridge.h"
#ifdef HAVE_TRACE
#include "x86trace.h"
#endif
#ifdef DYNAREC
#include "custommem.h"
#endif
@@ -37,22 +42,20 @@ static uint32_t x86emu_parity_tab[8] =
0x69969669,
};
static uint8_t EndEmuMarker[] = {0xcc, 'S', 'C', 0, 0, 0, 0};
#ifdef DYNAREC
void DynablockEmuMarker(box86context_t* context)
uint32_t* GetParityTab()
{
dynarec_log(LOG_DUMP, "Create bridge memory map for PushExit\n");
addDBFromAddressRange((uintptr_t)&EndEmuMarker[0], sizeof(EndEmuMarker), 0);
return x86emu_parity_tab;
}
#endif
void PushExit(x86emu_t* emu)
{
Push(emu, (uint32_t)&EndEmuMarker);
uintptr_t endMarker = AddCheckBridge(my_context->system, NULL, NULL, 0);
Push(emu, endMarker);
}
void* GetExit()
{
return &EndEmuMarker;
return (void*)AddCheckBridge(my_context->system, NULL, NULL, 0);
}
static void internalX86Setup(x86emu_t* emu, box86context_t *context, uintptr_t start, uintptr_t stack, int stacksize, int ownstack)
@@ -78,6 +81,7 @@ static void internalX86Setup(x86emu_t* emu, box86context_t *context, uintptr_t s
emu->segs[_GS] = 0x33;
// setup fpu regs
reset_fpu(emu);
emu->mxcsr = 0x1f80;
}
EXPORTDYN
@@ -167,11 +171,14 @@ void CallAllCleanup(x86emu_t *emu)
RunFunctionWithEmu(emu, 0, (uintptr_t)(my_context->cleanups[i].f), my_context->cleanups[i].arg, my_context->cleanups[i].a );
}
my_context->clean_sz = 0;
free(my_context->cleanups);
my_context->cleanups = NULL;
}
static void internalFreeX86(x86emu_t* emu)
{
free(emu->stack2free);
if(emu->stack2free)
munmap(emu->stack2free, emu->size_stack);
}
EXPORTDYN
@@ -204,7 +211,7 @@ void CloneEmu(x86emu_t *newemu, const x86emu_t* emu)
newemu->old_ip = emu->old_ip;
memcpy(newemu->segs, emu->segs, sizeof(emu->segs));
memset(newemu->segs_serial, 0, sizeof(newemu->segs_serial));
memcpy(newemu->fpu, emu->fpu, sizeof(emu->fpu));
memcpy(newemu->mmx87, emu->mmx87, sizeof(emu->mmx87));
memcpy(newemu->fpu_ld, emu->fpu_ld, sizeof(emu->fpu_ld));
memcpy(newemu->fpu_ll, emu->fpu_ll, sizeof(emu->fpu_ll));
memcpy(newemu->p_regs, emu->p_regs, sizeof(emu->p_regs));
@@ -214,7 +221,6 @@ void CloneEmu(x86emu_t *newemu, const x86emu_t* emu)
newemu->top = emu->top;
newemu->fpu_stack = emu->fpu_stack;
memcpy(&newemu->round, &emu->round, sizeof(emu->round));
memcpy(newemu->mmx, emu->mmx, sizeof(emu->mmx));
memcpy(newemu->xmm, emu->xmm, sizeof(emu->xmm));
newemu->mxcsr = emu->mxcsr;
newemu->quit = emu->quit;
@@ -302,7 +308,7 @@ const char* DumpCPURegs(x86emu_t* emu, uintptr_t ip)
if(trace_emm) {
// do emm reg is needed
for(int i=0; i<8; ++i) {
sprintf(tmp, "mm%d:%016llx", i, emu->mmx[i].q);
sprintf(tmp, "mm%d:%016llx", i, emu->mmx87[i].q);
strcat(buff, tmp);
if ((i&3)==3) strcat(buff, "\n"); else strcat(buff, " ");
}
@@ -318,7 +324,7 @@ const char* DumpCPURegs(x86emu_t* emu, uintptr_t ip)
// start with FPU regs...
if(emu->fpu_stack) {
for (int i=0; i<emu->fpu_stack; i++) {
sprintf(tmp, "ST%d=%f", i, emu->fpu[(emu->top+i)&7].d);
sprintf(tmp, "ST%d=%f", i, emu->mmx87[(emu->top+i)&7].d);
strcat(buff, tmp);
int c = 10-strlen(tmp);
if(c<1) c=1;
@@ -352,8 +358,19 @@ void StopEmu(x86emu_t* emu, const char* reason)
emu->quit = 1;
printf_log(LOG_NONE, "%s", reason);
// dump stuff...
printf_log(LOG_NONE, "CPU Regs=%s\n", DumpCPURegs(emu, R_EIP));
// TODO: stack, memory/instruction around EIP, etc..
printf_log(LOG_NONE, "\n==== CPU Registers ====\n%s\n", DumpCPURegs(emu, R_EIP));
printf_log(LOG_NONE, "\n======== Stack ========\nStack is from 0x%x to 0x%0x\n", R_EBP, R_ESP);
if (R_EBP == R_ESP) {
printf_log(LOG_NONE, "EBP = ESP: leaf function detected; next 128 bytes should be either data or random.\n");
} else {
// TODO: display stack if operation should be allowed (to avoid crashes)
/* for (uint32_t *sp = R_EBP; sp >= R_ESP; --sp) {
} */
}
printf_log(LOG_NONE, "\n====== Past data ======\nOld IP: %tX\n", emu->old_ip);
#ifdef HAVE_TRACE
printf_log(LOG_NONE, "%s\n", DecodeX86Trace(my_context->dec, emu->old_ip));
#endif
}
void UnimpOpcode(x86emu_t* emu)
@@ -361,8 +378,8 @@ void UnimpOpcode(x86emu_t* emu)
R_EIP = emu->old_ip;
int tid = syscall(SYS_gettid);
printf_log(LOG_NONE, "%04d|%p: Unimplemented Opcode %02X %02X %02X %02X %02X %02X %02X %02X\n",
tid, (void*)emu->old_ip,
printf_log(LOG_NONE, "%04d|%p: Unimplemented Opcode (%02X) %02X %02X %02X %02X %02X %02X %02X %02X\n",
tid, (void*)emu->old_ip, Peek(emu, -1),
Peek(emu, 0), Peek(emu, 1), Peek(emu, 2), Peek(emu, 3),
Peek(emu, 4), Peek(emu, 5), Peek(emu, 6), Peek(emu, 7));
emu->quit=1;
@@ -437,11 +454,11 @@ static inline void init_perfcounters (int32_t do_reset, int32_t enable_divider)
uint64_t ReadTSC(x86emu_t* emu)
{
// Read the TimeStamp Counter as 64bits.
// this is supposed to be the number of instrunctions executed since last reset
// this is supposed to be the number of instructions executed since last reset
#if defined(__i386__)
uint64_t ret;
__asm__ volatile("rdtsc" : "=A"(ret));
return ret;
uint64_t ret;
__asm__ volatile("rdtsc" : "=A"(ret));
return ret;
#if 0
#elif defined(__ARM_ARCH)
#if (__ARM_ARCH >= 6)
@@ -457,15 +474,15 @@ uint64_t ReadTSC(x86emu_t* emu)
#endif
#endif
#endif
// fall back to gettime...
// fall back to gettime...
#ifndef NOGETCLOCK
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
return (uint64_t)(ts.tv_sec) * 1000000000LL + ts.tv_nsec;
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
return (uint64_t)(ts.tv_sec) * 1000000000LL + ts.tv_nsec;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
return (uint64_t)(tv.tv_sec) * 1000000 + tv.tv_usec;
struct timeval tv;
gettimeofday(&tv, NULL);
return (uint64_t)(tv.tv_sec) * 1000000 + tv.tv_usec;
#endif
}
@@ -474,4 +491,4 @@ void ResetSegmentsCache(x86emu_t *emu)
if(!emu)
return;
memset(emu->segs_serial, 0, sizeof(emu->segs_serial));
}
}
+5 -12
View File
@@ -29,18 +29,16 @@ typedef struct x86emu_s {
x86flags_t eflags;
reg32_t ip;
uintptr_t old_ip;
// fpu
fpu_reg_t fpu[9];
// fpu / mmx
mmx87_regs_t mmx87[8];
uint16_t cw,cw_mask_all;
x87flags_t sw;
uint32_t top; // top is part of sw, but it's faster to have it separatly
int fpu_stack;
fpu_round_t round;
fpu_ld_t fpu_ld[9]; // for long double emulation / 80bits fld fst
fpu_ll_t fpu_ll[9]; // for 64bits fild / fist sequence
fpu_p_reg_t p_regs[9];
// mmx
mmx_regs_t mmx[8];
fpu_ld_t fpu_ld[8]; // for long double emulation / 80bits fld fst
fpu_ll_t fpu_ll[8]; // for 64bits fild / fist sequence
fpu_p_reg_t p_regs[8];
// sse
sse_regs_t xmm[8];
uint32_t mxcsr;
@@ -67,11 +65,6 @@ typedef struct x86emu_s {
int longjmp; // if quit because of longjmp
// parent context
box86context_t *context;
#ifdef DYNAREC
// virtual return stack
int cstacki; // current index
uint64_t cstack[CSTACK+1]; // pair of x86 address / native address for call/ret, using uint64_t for alignement, +1 for allignment
#endif
// cpu helpers
reg32_t zero;
reg32_t *sbiidx[8];
+20 -8
View File
@@ -121,7 +121,7 @@ void x86Int3(x86emu_t* emu)
} else if(!strcmp(s, "opendir")) {
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4));
perr = 1;
} else if(strstr(s, "__open")==s || strcmp(s, "open")==0) {
} else if(strstr(s, "__open")==s || !strcmp(s, "open") || !strcmp(s, "my_open64")) {
tmp = *(char**)(R_ESP+4);
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d (,%d))", tid, *(void**)(R_ESP), s, (tmp)?tmp:"(nil)", *(int*)(R_ESP+8), *(int*)(R_ESP+12));
perr = 1;
@@ -178,7 +178,7 @@ void x86Int3(x86emu_t* emu)
pu32 = *(uint32_t**)(R_ESP+8);
} else if(strstr(s, "semop")==s) {
int16_t* p16 = *(int16_t**)(R_ESP+8);
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p[%u/%d/%d], %d)", tid, *(void**)(R_ESP), s, *(int*)(R_ESP+4), p16, p16[0], p16[1], p16[2], *(int*)(R_ESP+12));
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p[%u/%d/0x%x], %d)", tid, *(void**)(R_ESP), s, *(int*)(R_ESP+4), p16, p16[0], p16[1], p16[2], *(int*)(R_ESP+12));
perr = 1;
} else if(!strcmp(s, "my_mmap64")) {
snprintf(buff, 255, "%04d|%p: Calling %s(%p, 0x%x, %d, 0x%x, %d, %lld)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(size_t*)(R_ESP+8), *(int*)(R_ESP+12), *(int*)(R_ESP+16), *(int*)(R_ESP+20), *(int64_t*)(R_ESP+24));
@@ -201,7 +201,11 @@ void x86Int3(x86emu_t* emu)
pu32 = *(uint32_t**)(R_ESP+4);
post = 3;
} else if(strstr(s, "my_vsprintf")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, \"%s\"...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(char**)(R_ESP+8));
snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\", %p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
pu32 = *(uint32_t**)(R_ESP+4);
post = 3;
} else if(strstr(s, "my___vsprintf_chk")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %d, %zu, \"%s\", %p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(int*)(R_ESP+8), *(size_t*)(R_ESP+12), *(char**)(R_ESP+16), *(void**)(R_ESP+20));
pu32 = *(uint32_t**)(R_ESP+4);
post = 3;
} else if(strstr(s, "my_snprintf")==s) {
@@ -213,7 +217,10 @@ void x86Int3(x86emu_t* emu)
pu32 = *(uint32_t**)(R_ESP+4);
post = 3;
} else if(strstr(s, "my_printf")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\"...)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4));
pu32 = *(uint32_t**)(R_ESP+4);
if(((uintptr_t)pu32)<0x5) // probably a _chk function
pu32 = *(uint32_t**)(R_ESP+8);
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\"...)", tid, *(void**)(R_ESP), s, pu32?((char*)(pu32)):"nil");
} else if(strstr(s, "puts")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\"...)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4));
} else if(strstr(s, "fputs")==s) {
@@ -224,14 +231,19 @@ void x86Int3(x86emu_t* emu)
pu32 = *(uint32_t**)(R_ESP+12);
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, \"%s\", ...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), pu32?((char*)(pu32)):"nil");
} else if(strstr(s, "my_vfprintf")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, \"%s\", ...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(char**)(R_ESP+8));
pu32 = *(uint32_t**)(R_ESP+8);
if(((uintptr_t)pu32)<0x5) // probably a _chk function
pu32 = *(uint32_t**)(R_ESP+12);
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, \"%s\", ...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), pu32?((char*)(pu32)):"nil");
} else if(strstr(s, "vkGetInstanceProcAddr")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\")", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(char**)(R_ESP+8));
} else if(strstr(s, "vkGetDeviceProcAddr")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\")", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(char**)(R_ESP+8));
} else if(strstr(s, "my_glXGetProcAddress")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4));
} else if(strstr(s, "my_sscanf")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\", ...)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
} else if(strstr(s, "vsscanf")==s) {
} else if(!strcmp(s, "vsscanf")) {
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\", ...)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
} else if(strstr(s, "XCreateWindow")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %p, %d, %d, %u, %u, %u, %d, %u, %p, %u, %p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(void**)(R_ESP+8), *(int*)(R_ESP+12), *(int*)(R_ESP+16), *(uint32_t*)(R_ESP+20), *(uint32_t*)(R_ESP+24), *(uint32_t*)(R_ESP+28), *(int32_t*)(R_ESP+32), *(uint32_t*)(R_ESP+36), *(void**)(R_ESP+40), *(uint32_t*)(R_ESP+44), *(void**)(R_ESP+48));
@@ -291,10 +303,10 @@ void x86Int3(x86emu_t* emu)
}
return;
}
if(my_context->signals[SIGTRAP])
if(0 && my_context->signals[SIGTRAP])
raise(SIGTRAP);
else
printf_log(LOG_INFO, "Warning, ignoring unsupported Int 3 call\n");
printf_log(LOG_INFO, "%04d|Warning, ignoring unsupported Int 3 call @%p\n", GetTID(), (void*)R_EIP);
//emu->quit = 1;
}
+35 -9
View File
@@ -20,6 +20,7 @@
#include "box86context.h"
#include "my_cpuid.h"
#include "bridge.h"
#include "signals.h"
#ifdef DYNAREC
#include "../dynarec/arm_lock_helper.h"
#endif
@@ -44,13 +45,13 @@ int Run(x86emu_t *emu, int step)
float f;
int64_t ll;
sse_regs_t *opex, eax1;
mmx_regs_t *opem, eam1;
mmx87_regs_t *opem, eam1;
if(emu->quit)
return 0;
//ref opcode: http://ref.x86asm.net/geek32.html#xA1
printf_log(LOG_DEBUG, "Run X86 (%p), EIP=%p, Stack=%p\n", emu, (void*)R_EIP, emu->context->stack);
printf_log(LOG_DEBUG, "Run X86 (%p), EIP=%p, Stack=%p\n", emu, (void*)R_EIP, (void*)R_ESP);
#define F8 *(uint8_t*)(ip++)
#define F8S *(int8_t*)(ip++)
#define F16 *(uint16_t*)(ip+=2, ip-2)
@@ -94,7 +95,7 @@ int Run(x86emu_t *emu, int step)
&&_0xD8, &&_0xD9, &&_0xDA, &&_0xDB, &&_0xDC, &&_0xDD, &&_0xDE, &&_0xDF,
&&_0xE0, &&_0xE1, &&_0xE2, &&_0xE3, &&_0xE4, &&_0xE5, &&_0xE6, &&_0xE7,
&&_0xE8, &&_0xE9, &&_default, &&_0xEB, &&_0xEC, &&_0xED, &&_default, &&_default,
&&_0xF0, &&_0xF1, &&_0xF2, &&_0xF3, &&_default, &&_0xF5, &&_0xF6, &&_0xF7,
&&_0xF0, &&_0xF1, &&_0xF2, &&_0xF3, &&_0xF4, &&_0xF5, &&_0xF6, &&_0xF7,
&&_0xF8, &&_0xF9, &&_0xFA, &&_0xFB, &&_0xFC, &&_0xFD, &&_0xFE, &&_0xFF
};
@@ -106,7 +107,7 @@ int Run(x86emu_t *emu, int step)
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x20-0x27
&&_0f_0x28, &&_0f_0x29, &&_0f_0x2A, &&_0f_0x2B, &&_0f_0x2C, &&_0f_0x2D, &&_0f_0x2E, &&_0f_0x2F,
&&_default, &&_0f_0x31, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x30-0x37
&&_0f_0x38, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x38-0x3F
&&_0f_0x38, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_0f_0x3F, //0x38-0x3F
&&_0f_0x40_0, &&_0f_0x40_1, &&_0f_0x40_2, &&_0f_0x40_3, &&_0f_0x40_4, &&_0f_0x40_5, &&_0f_0x40_6, &&_0f_0x40_7,
&&_0f_0x40_8, &&_0f_0x40_9, &&_0f_0x40_A, &&_0f_0x40_B, &&_0f_0x40_C, &&_0f_0x40_D, &&_0f_0x40_E, &&_0f_0x40_F,
&&_0f_0x50, &&_0f_0x51, &&_0f_0x52, &&_0f_0x53, &&_0f_0x54, &&_0f_0x55, &&_0f_0x56, &&_0f_0x57, //0x50-0x57
@@ -130,7 +131,7 @@ int Run(x86emu_t *emu, int step)
&&_0f_0xE0, &&_0f_0xE1, &&_0f_0xE2, &&_0f_0xE3, &&_0f_0xE4 ,&&_0f_0xE5, &&_default, &&_0f_0xE7, //0xE0-0xE7
&&_0f_0xE8, &&_0f_0xE9, &&_0f_0xEA, &&_0f_0xEB, &&_0f_0xEC ,&&_0f_0xED, &&_0f_0xEE, &&_0f_0xEF, //0xE8-0xEF
&&_default, &&_0f_0xF1, &&_0f_0xF2, &&_0f_0xF3, &&_0f_0xF4 ,&&_0f_0xF5, &&_0f_0xF6, &&_0f_0xF7, //0xF0-0xF7
&&_0f_0xF8, &&_0f_0xF9, &&_0f_0xFA, &&_default, &&_0f_0xFC ,&&_0f_0xFD, &&_0f_0xFE, &&_default //0xF8-0xFF
&&_0f_0xF8, &&_0f_0xF9, &&_0f_0xFA, &&_0f_0xFB, &&_0f_0xFC ,&&_0f_0xFD, &&_0f_0xFE, &&_default //0xF8-0xFF
};
static const void* opcodes66[256] = {
@@ -146,7 +147,7 @@ int Run(x86emu_t *emu, int step)
&&_66_0x48, &&_66_0x49, &&_66_0x4A, &&_66_0x4B, &&_66_0x4C, &&_66_0x4D, &&_66_0x4E, &&_66_0x4F,
&&_66_0x50, &&_66_0x51, &&_66_0x52, &&_66_0x53, &&_66_0x54, &&_66_0x55, &&_66_0x56, &&_66_0x57, //0x50-0x57
&&_66_0x58, &&_66_0x59, &&_66_0x5A, &&_66_0x5B, &&_66_0x5C, &&_66_0x5D, &&_66_0x5E, &&_66_0x5F, //0x58-0x5F
&&_66_0x60, &&_66_0x61, &&_default, &&_default, &&_default ,&&_default, &&_66_0x66, &&_default, //0x60-0x67
&&_66_0x60, &&_66_0x61, &&_default, &&_default, &&_66_0x64 ,&&_default, &&_66_0x66, &&_default, //0x60-0x67
&&_66_0x68, &&_66_0x69, &&_66_0x6A, &&_66_0x6B, &&_default, &&_default, &&_default, &&_default, //0x68-0x6F
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x70-0x77
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x78-0x7F
@@ -920,7 +921,6 @@ _trace:
GET_ED;
ED->dword[0] = F32;
NEXT;
_0xC8: /* ENTER Iw,Ib */
tmp16u = F16;
tmp8u = (F8) & 0x1f;
@@ -936,7 +936,6 @@ _trace:
}
R_ESP -= tmp16u;
NEXT;
_0xC9: /* LEAVE */
R_ESP = R_EBP;
R_EBP = Pop(emu);
@@ -1245,6 +1244,24 @@ _trace:
case 0x4D:
case 0x4E:
case 0x4F:
case 0x50:
case 0x51:
case 0x52:
case 0x53:
case 0x54:
case 0x55:
case 0x56:
case 0x57:
case 0x58:
case 0x59:
case 0x5A:
case 0x5B:
case 0x5C:
case 0x5D:
case 0x5E:
case 0x5F:
case 0x60:
case 0x61:
case 0x70:
case 0x71:
case 0x72:
@@ -1261,12 +1278,17 @@ _trace:
case 0x7D:
case 0x7E:
case 0x7F: /* BND / NOP */
case 0x80:
case 0x86: /* XACQUIRE/XRELEASE XCHG */
case 0x87: /* XACQUIRE/XRELEASE XCHG */
case 0x88: /* XRELEASE MOV... */
case 0x89: /* XRELEASE MOV... ignoring acquire thingy */
case 0x9C:
case 0xA0:
case 0xC0:
case 0xC3: /* yup, repz ret is valid */
case 0xD0:
case 0xE0:
case 0xE8:
case 0xE9:
case 0xEB:
@@ -1424,7 +1446,11 @@ _trace:
R_ECX = tmp32u;
} // else(nextop==0x0F)
NEXT;
_0xF4: /* HLT */
// this is a privilege opcode... should an error be called instead?
sched_yield();
STEP;
NEXT;
_0xF5: /* CMC */
CHECK_FLAGS(emu);
CONDITIONAL_SET_FLAG(!ACCESS_FLAG(F_CF), F_CF);
+190 -29
View File
@@ -11,6 +11,7 @@
#include "x86primop.h"
#include "x86trace.h"
#include "box86context.h"
#include "bridge.h"
#ifdef DYNAREC
#include "../dynarec/arm_lock_helper.h"
#endif
@@ -42,7 +43,7 @@ void Run6766(x86emu_t *emu)
default:
ip-=2; //unfetch
ip-=3; //unfetch
UnimpOpcode(emu);
}
R_EIP = ip;
@@ -120,6 +121,14 @@ void Run67(x86emu_t *emu)
R_DI+=1;
break;
case 0xAC: /* LODSB */
R_AL = *(int8_t*)(R_SI+GetDSBaseEmu(emu));
if(ACCESS_FLAG(F_DF))
R_SI-=1;
else
R_SI+=1;
break;
case 0xE0: /* LOOPNZ */
CHECK_FLAGS(emu);
tmp8s = F8S;
@@ -153,6 +162,7 @@ void Run67(x86emu_t *emu)
break;
default:
ip-=2;
UnimpOpcode(emu);
}
R_EIP = ip;
@@ -381,6 +391,38 @@ void RunLock(x86emu_t *emu)
else
CLEAR_FLAG(F_CF);
pthread_mutex_unlock(&emu->context->mutex_lock);
#endif
break;
case 5: /* BTS Ed, Ib */
CHECK_FLAGS(emu);
GET_ED;
tmp8u = F8;
if((nextop&0xC0)!=0xC0)
{
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
}
tmp8u&=31;
#ifdef DYNAREC
do {
tmp32u = arm_lock_read_d(ED);
if(tmp32u & (1<<tmp8u)) {
SET_FLAG(F_CF);
tmp32s = 0;
} else {
CLEAR_FLAG(F_CF);
tmp32u ^= (1<<tmp8u);
tmp32s = arm_lock_write_d(ED, tmp32u);
}
} while(tmp32s);
#else
pthread_mutex_lock(&emu->context->mutex_lock);
if(ED->dword[0] & (1<<tmp8u)) {
SET_FLAG(F_CF);
} else {
CLEAR_FLAG(F_CF);
ED->dword[0] ^= (1<<tmp8u);
}
pthread_mutex_unlock(&emu->context->mutex_lock);
#endif
break;
case 6: /* BTR Ed, Ib */
@@ -416,7 +458,7 @@ void RunLock(x86emu_t *emu)
break;
default:
ip -= 2; //unfetchall 0F BA but not F0, continue normal without LOCK
ip -= 3; //unfetchall 0F BA nextop but not F0, continue normal without LOCK
break;
}
break;
@@ -554,11 +596,16 @@ void RunLock(x86emu_t *emu)
break;
default:
// trigger invalid lock?
ip -= 1; // unfetch 0F but not F0
ip -= 2; // unfetch 0F and nextop but not F0
break;
}
break;
case 0x66:
RunLock66(emu);
ip = R_EIP;
break;
case 0x81: /* GRP Ed,Id */
case 0x83: /* GRP Ed,Ib */
nextop = F8;
@@ -614,9 +661,19 @@ void RunLock(x86emu_t *emu)
switch((nextop>>3)&7) {
case 0: /* INC Ed */
#ifdef DYNAREC
do {
tmp32u = arm_lock_read_d(ED);
} while(arm_lock_write_d(ED, inc32(emu, tmp32u)));
if((uintptr_t)ED&3) {
//meh.
do {
tmp32u = ED->dword[0];
tmp32u &=~0xff;
tmp32u |= arm_lock_read_b(ED);
tmp32u = inc32(emu, tmp32u);
} while(arm_lock_write_b(ED, tmp32u&0xff));
ED->dword[0] = tmp32u;
} else
do {
tmp32u = arm_lock_read_d(ED);
} while(arm_lock_write_d(ED, inc32(emu, tmp32u)));
#else
pthread_mutex_lock(&emu->context->mutex_lock);
ED->dword[0] = inc32(emu, ED->dword[0]);
@@ -625,9 +682,19 @@ void RunLock(x86emu_t *emu)
break;
case 1: /* DEC Ed */
#ifdef DYNAREC
do {
tmp32u = arm_lock_read_d(ED);
} while(arm_lock_write_d(ED, dec32(emu, tmp32u)));
if((uintptr_t)ED&3) {
//meh.
do {
tmp32u = ED->dword[0];
tmp32u &=~0xff;
tmp32u |= arm_lock_read_b(ED);
tmp32u = dec32(emu, tmp32u);
} while(arm_lock_write_b(ED, tmp32u&0xff));
ED->dword[0] = tmp32u;
} else
do {
tmp32u = arm_lock_read_d(ED);
} while(arm_lock_write_d(ED, dec32(emu, tmp32u)));
#else
pthread_mutex_lock(&emu->context->mutex_lock);
ED->dword[0] = dec32(emu, ED->dword[0]);
@@ -655,9 +722,12 @@ void RunLock66(x86emu_t *emu)
uint8_t opcode = F8;
uint8_t nextop;
reg32_t *oped;
uint16_t tmp16u, tmp16u2;
uint16_t tmp16u;
int16_t tmp16s;
#ifdef DYNAREC
uint16_t tmp16u2;
int32_t tmp32s;
#endif
switch(opcode) {
case 0x0f:
opcode = F8;
@@ -759,11 +829,31 @@ void RunGS(x86emu_t *emu)
GD.dword[0] = add32(emu, GD.dword[0], ED->dword[0]);
break;
case 0x06: /* PUSH ES */
Push(emu, emu->segs[_ES]);
break;
case 0x07: /* POP ES */
emu->segs[_ES] = Pop(emu);
emu->segs_serial[_ES] = 0;
break;
case 0x0f:
RunGS0F(emu, tlsdata);
ip = R_EIP;
break;
case 0x11: /* ADC GS:Ed, Gd */
nextop = F8;
GET_ED_OFFS(tlsdata);
ED->dword[0] = adc32(emu, ED->dword[0], GD.dword[0]);
break;
case 0x13: /* ADC Gd, GS:Ed */
nextop = F8;
GET_ED_OFFS(tlsdata);
GD.dword[0] = adc32(emu, GD.dword[0], ED->dword[0]);
break;
case 0x2B: /* SUB Gd, GS:Ed */
nextop = F8;
GET_ED_OFFS(tlsdata);
@@ -776,6 +866,29 @@ void RunGS(x86emu_t *emu)
GD.dword[0] = xor32(emu, GD.dword[0], ED->dword[0]);
break;
case 0x40:
case 0x41:
case 0x42:
case 0x43:
case 0x44:
case 0x45:
case 0x46:
case 0x47: /* INC Reg */
tmp8u = opcode&7;
emu->regs[tmp8u].dword[0] = inc32(emu, emu->regs[tmp8u].dword[0]);
break;
case 0x48:
case 0x49:
case 0x4A:
case 0x4B:
case 0x4C:
case 0x4D:
case 0x4E:
case 0x4F: /* DEC Reg */
tmp8u = opcode&7;
emu->regs[tmp8u].dword[0] = dec32(emu, emu->regs[tmp8u].dword[0]);
break;
case 0x64: /* FS: */
// so just ignore that GS: prefix then
--ip; // put FS back
@@ -915,7 +1028,7 @@ void RunGS(x86emu_t *emu)
ED->dword[0] = dec32(emu, ED->dword[0]);
break;
case 2: /* CALL NEAR Ed */
R_EIP = ED->dword[0];
R_EIP = (uintptr_t)getAlternate((void*)ED->dword[0]);
Push(emu, ip);
ip = R_EIP;
break;
@@ -932,7 +1045,7 @@ void RunGS(x86emu_t *emu)
}
break;
case 4: /* JMP NEAR Ed */
ip = ED->dword[0];
ip = (uintptr_t)getAlternate((void*)ED->dword[0]);
break;
case 5: /* JMP FAR Ed */
if(nextop>0xc0) {
@@ -954,7 +1067,7 @@ void RunGS(x86emu_t *emu)
}
break;
default:
ip--;
ip=R_EIP;
UnimpOpcode(emu);
}
R_EIP = ip;
@@ -1026,21 +1139,18 @@ void RunFS(x86emu_t *emu)
break;
case 0x66:
opcode = F8;
switch(opcode) {
case 0x8B: /* MOV Gw,FS:Ew */
nextop = F8;
GET_EW_OFFS(tlsdata);
GW.word[0] = EW->word[0];
break;
default:
ip-=2;
UnimpOpcode(emu);
}
RunFS66(emu, tlsdata);
ip = R_EIP;
break;
case 0x67:
opcode = F8;
switch(opcode) {
case 0x3B: /* CMP GD, FS:Ed16 */
nextop = F8;
GET_EW16_OFFS(tlsdata);
cmp32(emu, GD.dword[0], ED->dword[0]);
break;
case 0x89: /* MOV ED16,Gd */
nextop = F8;
GET_EW16_OFFS(tlsdata);
@@ -1075,12 +1185,12 @@ void RunFS(x86emu_t *emu)
Push(emu, ED->dword[0]);
break;
default:
ip-=2;
ip-=3;
UnimpOpcode(emu);
}
break;
default:
ip-=2;
ip-=3;
UnimpOpcode(emu);
}
break;
@@ -1154,6 +1264,12 @@ void RunFS(x86emu_t *emu)
GET_ED_OFFS(tlsdata);
ED->dword[0] = Pop(emu);
break;
case 0x9C: /* PUSHFD */
// Segment override if for memory loc, no stack segment
--ip; // so ignore prefix and continue
break;
case 0xA0: /* MOV AL,Ob */
tmp32s = F32S;
R_AL = *(uint8_t*)((tlsdata) + tmp32s);
@@ -1214,7 +1330,7 @@ void RunFS(x86emu_t *emu)
ED->dword[0] = dec32(emu, ED->dword[0]);
break;
case 2: /* CALL NEAR Ed */
R_EIP = ED->dword[0];
R_EIP = (uintptr_t)getAlternate((void*)ED->dword[0]);
Push(emu, ip);
ip = R_EIP;
break;
@@ -1231,11 +1347,12 @@ void RunFS(x86emu_t *emu)
}
break;
case 4: /* JMP NEAR Ed */
ip = ED->dword[0];
ip = (uintptr_t)getAlternate((void*)ED->dword[0]);
break;
case 5: /* JMP FAR Ed */
if(nextop>0xc0) {
printf_log(LOG_NONE, "Illegal Opcode 0x%02X 0x%02X\n", opcode, nextop);
ip-=3;
emu->quit=1;
emu->error |= ERR_ILLEGAL;
} else {
@@ -1254,8 +1371,52 @@ void RunFS(x86emu_t *emu)
}
break;
default:
ip--;
ip = R_EIP;
UnimpOpcode(emu);
}
R_EIP = ip;
}
void RunFS66(x86emu_t *emu, uintptr_t tlsdata)
{
uintptr_t ip = R_EIP+2;
uint8_t opcode = F8;
uint8_t nextop;
reg32_t *oped;
switch(opcode) {
case 0x03: /* ADD Gw, FS:Ew */
nextop = F8;
GET_EW_OFFS(tlsdata);
GW.word[0] = add16(emu, GW.word[0], EW->word[0]);
break;
case 0x8B: /* MOV Gw,FS:Ew */
nextop = F8;
GET_EW_OFFS(tlsdata);
GW.word[0] = EW->word[0];
break;
default:
ip=R_EIP;
UnimpOpcode(emu);
}
R_EIP = ip;
}
void RunGS0F(x86emu_t *emu, uintptr_t tlsdata)
{
uintptr_t ip = R_EIP+2;
uint8_t opcode = F8;
uint8_t nextop;
reg32_t *oped;
switch(opcode) {
case 0xB6: /* MOVZX Gd,GS:Eb */
nextop = F8;
GET_EB_OFFS(tlsdata);
GD.dword[0] = EB->byte[0];
break;
default:
ip=R_EIP;
UnimpOpcode(emu);
}
R_EIP = ip;
}
+340 -348
View File
File diff suppressed because it is too large. Load diff
+23 -4
View File
@@ -27,10 +27,27 @@
#define PARITY(x) (((emu->x86emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0)
#define XOR2(x) (((x) ^ ((x)>>1)) & 0x1)
#ifdef ANDROID
void EXPORT my___libc_init(x86emu_t* emu, void* raw_args __unused, void (*onexit)(void) __unused, int (*main)(int, char**, char**), void const * const structors __unused)
{
//TODO: register fini
// let's cheat and set all args...
Push(emu, (uint32_t)my_context->envv);
Push(emu, (uint32_t)my_context->argv);
Push(emu, (uint32_t)my_context->argc);
printf_log(LOG_DEBUG, "Transfert to main(%d, %p, %p)=>%p from __libc_init\n", my_context->argc, my_context->argv, my_context->envv, main);
// call main and finish
PushExit(emu);
R_EIP=(uint32_t)main;
DynaRun(emu);
emu->quit = 1; // finished!
}
#else
int32_t EXPORT my___libc_start_main(x86emu_t* emu, int *(main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end))
{
//TODO: register rtld_fini
//TODO: register fini
// let's cheat and set all args...
Push(emu, (uint32_t)my_context->envv);
Push(emu, (uint32_t)my_context->argv);
@@ -48,11 +65,13 @@ int32_t EXPORT my___libc_start_main(x86emu_t* emu, int *(main) (int, char * *, c
// call main and finish
PushExit(emu);
R_EIP=(uint32_t)main;
#ifdef DYNAREC
DynaRun(emu);
#endif
emu->quit = 1; // finished!
return 0;
}
#endif
const char* GetNativeName(void* p)
{
+8 -5
View File
@@ -149,12 +149,12 @@ static inline reg32_t* GetEw16off(x86emu_t *emu, uint32_t v, uintptr_t offset)
}
}
static inline mmx_regs_t* GetEm(x86emu_t *emu, uint32_t v)
static inline mmx87_regs_t* GetEm(x86emu_t *emu, uint32_t v)
{
uint32_t m = v&0xC7; // filter Ed
if(m>=0xC0) {
return &emu->mmx[m&0x07];
} else return (mmx_regs_t*)GetECommon(emu, m);
return &emu->mmx87[m&0x07];
} else return (mmx87_regs_t*)GetECommon(emu, m);
}
static inline sse_regs_t* GetEx(x86emu_t *emu, uint32_t v)
@@ -177,10 +177,10 @@ static inline reg32_t* GetGb(x86emu_t *emu, uint32_t v)
return (reg32_t*)&emu->regs[m&3].byte[m>>2];
}
static inline mmx_regs_t* GetGm(x86emu_t *emu, uint32_t v)
static inline mmx87_regs_t* GetGm(x86emu_t *emu, uint32_t v)
{
uint8_t m = (v&0x38)>>3;
return &emu->mmx[m&7];
return &emu->mmx87[m&7];
}
static inline sse_regs_t* GetGx(x86emu_t *emu, uint32_t v)
@@ -200,7 +200,9 @@ void Run660F(x86emu_t *emu);
void Run66D9(x86emu_t *emu); // x87
void Run6766(x86emu_t *emu);
void RunGS(x86emu_t *emu);
void RunGS0F(x86emu_t *emu, uintptr_t tlsdata);
void RunFS(x86emu_t *emu);
void RunFS66(x86emu_t *emu, uintptr_t tlsdata);
void RunLock(x86emu_t *emu);
void RunLock66(x86emu_t *emu);
@@ -212,6 +214,7 @@ uintptr_t GetSegmentBaseEmu(x86emu_t* emu, int seg);
#define GetGSBaseEmu(emu) GetSegmentBaseEmu(emu, _GS)
#define GetFSBaseEmu(emu) GetSegmentBaseEmu(emu, _FS)
#define GetESBaseEmu(emu) GetSegmentBaseEmu(emu, _ES)
#define GetDSBaseEmu(emu) GetSegmentBaseEmu(emu, _DS)
const char* GetNativeName(void* p);
+8 -1
View File
@@ -228,12 +228,17 @@ scwrap_t syscallwrap[] = {
{ 266, __NR_clock_getres, 2 },
//{ 270, __NR_tgkill, 3 },
{ 271, __NR_utimes, 2 },
{ 291, __NR_inotify_init, 0},
{ 292, __NR_inotify_add_watch, 3},
{ 293, __NR_inotify_rm_watch, 2},
{ 311, __NR_set_robust_list, 2 },
{ 312, __NR_get_robust_list, 4 },
{ 318, __NR_getcpu, 3},
#ifdef NOALIGN
{ 329, __NR_epoll_create1, 1 },
#endif
{ 331, __NR_pipe2, 2},
{ 332, __NR_inotify_init1, 1},
#ifdef __NR_getrandom
{ 355, __NR_getrandom, 3 },
#endif
@@ -476,6 +481,7 @@ void EXPORT x86Syscall(x86emu_t *emu)
break;
case 120: // clone
{
// should wrap that using a thread...
//struct x86_pt_regs *regs = (struct x86_pt_regs *)R_EDI;
// lets duplicate the emu
void* stack_base = (void*)R_ECX;
@@ -483,7 +489,8 @@ void EXPORT x86Syscall(x86emu_t *emu)
if(!R_ECX) {
// allocate a new stack...
stack_size = 1024*1024;
stack_base = malloc(stack_size); // why not 1M... (normal operation do copy on write, simpler to just copy)
//stack_base = malloc(stack_size); // why not 1M... (normal operation do copy on write, simpler to just copy)
stack_base = mmap(NULL, stack_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_GROWSDOWN, -1, 0);
// copy value from old stack to new stack
int size_to_copy = (uintptr_t)emu->init_stack + emu->size_stack - (R_ESP);
memcpy(stack_base-size_to_copy, (void*)R_ESP, size_to_copy);
+2 -1
View File
@@ -186,8 +186,9 @@ static void* GetSeg33Base()
if ((ptr = (tlsdatasize_t*)pthread_getspecific(my_context->tlskey)) == NULL) {
ptr = (tlsdatasize_t*)fillTLSData(my_context);
}
if(ptr->tlssize != my_context->tlssize)
if(ptr->tlssize != my_context->tlssize) {
ptr = (tlsdatasize_t*)resizeTLSData(my_context, ptr);
}
return ptr->tlsdata+ptr->tlssize;
}
+304 -253
View File
@@ -3018,109 +3018,121 @@ typedef struct ZydisDecodedOperand_
} imm;
} ZydisDecodedOperand;
/**
* @brief Defines the `ZydisCPUFlags` datatype.
* Defines the `ZydisCPUFlags` data-type.
*/
typedef ZyanU32 ZydisCPUFlags;
typedef ZyanU8 ZydisCPUFlag;
/**
* @brief Defines the `ZydisCPUFlag` enum.
*/
typedef enum ZydisCPUFlag_
{
/**
* @brief Carry flag.
*/
ZYDIS_CPUFLAG_CF,
/**
* @brief Parity flag.
*/
ZYDIS_CPUFLAG_PF,
/**
* @brief Adjust flag.
*/
ZYDIS_CPUFLAG_AF,
/**
* @brief Zero flag.
*/
ZYDIS_CPUFLAG_ZF,
/**
* @brief Sign flag.
*/
ZYDIS_CPUFLAG_SF,
/**
* @brief Trap flag.
*/
ZYDIS_CPUFLAG_TF,
/**
* @brief Interrupt enable flag.
*/
ZYDIS_CPUFLAG_IF,
/**
* @brief Direction flag.
*/
ZYDIS_CPUFLAG_DF,
/**
* @brief Overflow flag.
*/
ZYDIS_CPUFLAG_OF,
/**
* @brief I/O privilege level flag.
*/
ZYDIS_CPUFLAG_IOPL,
/**
* @brief Nested task flag.
*/
ZYDIS_CPUFLAG_NT,
/**
* @brief Resume flag.
*/
ZYDIS_CPUFLAG_RF,
/**
* @brief Virtual 8086 mode flag.
*/
ZYDIS_CPUFLAG_VM,
/**
* @brief Alignment check.
*/
ZYDIS_CPUFLAG_AC,
/**
* @brief Virtual interrupt flag.
*/
ZYDIS_CPUFLAG_VIF,
/**
* @brief Virtual interrupt pending.
*/
ZYDIS_CPUFLAG_VIP,
/**
* @brief Able to use CPUID instruction.
*/
ZYDIS_CPUFLAG_ID,
/**
* @brief FPU condition-code flag 0.
*/
ZYDIS_CPUFLAG_C0,
/**
* @brief FPU condition-code flag 1.
*/
ZYDIS_CPUFLAG_C1,
/**
* @brief FPU condition-code flag 2.
*/
ZYDIS_CPUFLAG_C2,
/**
* @brief FPU condition-code flag 3.
*/
ZYDIS_CPUFLAG_C3,
* Carry flag.
*/
#define ZYDIS_CPUFLAG_CF 0
/**
* Parity flag.
*/
#define ZYDIS_CPUFLAG_PF 2
/**
* Adjust flag.
*/
#define ZYDIS_CPUFLAG_AF 4
/**
* Zero flag.
*/
#define ZYDIS_CPUFLAG_ZF 6
/**
* Sign flag.
*/
#define ZYDIS_CPUFLAG_SF 7
/**
* Trap flag.
*/
#define ZYDIS_CPUFLAG_TF 8
/**
* Interrupt enable flag.
*/
#define ZYDIS_CPUFLAG_IF 9
/**
* Direction flag.
*/
#define ZYDIS_CPUFLAG_DF 10
/**
* Overflow flag.
*/
#define ZYDIS_CPUFLAG_OF 11
/**
* I/O privilege level flag.
*/
#define ZYDIS_CPUFLAG_IOPL 12
/**
* Nested task flag.
*/
#define ZYDIS_CPUFLAG_NT 14
/**
* Resume flag.
*/
#define ZYDIS_CPUFLAG_RF 16
/**
* Virtual 8086 mode flag.
*/
#define ZYDIS_CPUFLAG_VM 17
/**
* Alignment check.
*/
#define ZYDIS_CPUFLAG_AC 18
/**
* Virtual interrupt flag.
*/
#define ZYDIS_CPUFLAG_VIF 19
/**
* Virtual interrupt pending.
*/
#define ZYDIS_CPUFLAG_VIP 20
/**
* Able to use CPUID instruction.
*/
#define ZYDIS_CPUFLAG_ID 21
///////////////////////////////////////////////////////////////////////////////////////////////////
/**
* FPU condition-code flag 0.
*
* DEPRECATED. This flag is not actually part of `FLAGS/EFLAGS/RFLAGS` and will be removed in the
* next major release. Please refer to the `fpu_flags_read`/`fpu_flags_written` field instead and
* use one of the `ZYDIS_FPUFLAG_XXX` masks to check for specific a flag.
*/
#define ZYDIS_CPUFLAG_C0 22
/**
* FPU condition-code flag 1.
*
* DEPRECATED. This flag is not actually part of `FLAGS/EFLAGS/RFLAGS` and will be removed in the
* next major release. Please refer to the `fpu_flags_read`/`fpu_flags_written` field instead and
* use one of the `ZYDIS_FPUFLAG_XXX` masks to check for specific a flag.
*/
#define ZYDIS_CPUFLAG_C1 23
/**
* FPU condition-code flag 2.
*
* DEPRECATED. This flag is not actually part of `FLAGS/EFLAGS/RFLAGS` and will be removed in the
* next major release. Please refer to the `fpu_flags_read`/`fpu_flags_written` field instead and
* use one of the `ZYDIS_FPUFLAG_XXX` masks to check for specific a flag.
*/
#define ZYDIS_CPUFLAG_C2 24
/**
* FPU condition-code flag 3.
*
* DEPRECATED. This flag is not actually part of `FLAGS/EFLAGS/RFLAGS` and will be removed in the
* next major release. Please refer to the `fpu_flags_read`/`fpu_flags_written` field instead and
* use one of the `ZYDIS_FPUFLAG_XXX` masks to check for specific a flag.
*/
#define ZYDIS_CPUFLAG_C3 25
/**
* DEPRECATED. This define will be removed in the next major release.
*/
#define ZYDIS_CPUFLAG_MAX_VALUE ZYDIS_CPUFLAG_C3
/**
* @brief Maximum value of this enum.
*/
ZYDIS_CPUFLAG_MAX_VALUE = ZYDIS_CPUFLAG_C3,
/**
* @brief The minimum number of bits required to represent all values of this enum.
*/
ZYDIS_CPUFLAG_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_CPUFLAG_MAX_VALUE)
} ZydisCPUFlag;
/**
* @brief Defines the `ZydisMaskMode` enum.
*/
@@ -3793,66 +3805,79 @@ typedef enum ZydisCPUFlagAction_
*/
ZYDIS_CPUFLAG_ACTION_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_CPUFLAG_ACTION_MAX_VALUE)
} ZydisCPUFlagAction;
/**
* Defines the `ZydisFPUFlags` data-type.
*/
typedef ZyanU8 ZydisFPUFlags;
/**
* @brief Defines the `ZydisDecodedInstruction` struct.
*/
typedef struct ZydisDecodedInstruction_
{
/**
* @brief The machine mode used to decode this instruction.
* The machine mode used to decode this instruction.
*/
ZydisMachineMode machine_mode;
/**
* @brief The instruction-mnemonic.
* The instruction-mnemonic.
*/
ZydisMnemonic mnemonic;
/**
* @brief The length of the decoded instruction.
* The length of the decoded instruction.
*/
ZyanU8 length;
/**
* @brief The instruction-encoding (`LEGACY`, `3DNOW`, `VEX`, `EVEX`, `XOP`).
* The instruction-encoding (`LEGACY`, `3DNOW`, `VEX`, `EVEX`, `XOP`).
*/
ZydisInstructionEncoding encoding;
/**
* @brief The opcode-map.
* The opcode-map.
*/
ZydisOpcodeMap opcode_map;
/**
* @brief The instruction-opcode.
* The instruction-opcode.
*/
ZyanU8 opcode;
/**
* @brief The stack width.
* The stack width.
*/
ZyanU8 stack_width;
/**
* @brief The effective operand width.
* The effective operand width.
*/
ZyanU8 operand_width;
/**
* @brief The effective address width.
* The effective address width.
*/
ZyanU8 address_width;
/**
* @brief The number of instruction-operands.
* The number of instruction-operands.
*/
ZyanU8 operand_count;
/**
* @brief Detailed info for all instruction operands.
* Detailed info for all instruction operands.
*
* Explicit operands are guaranteed to be in the front and ordered as they are printed
* by the formatter in Intel mode. No assumptions can be made about the order of hidden
* operands, except that they always located behind the explicit operands.
*/
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
/**
* @brief Instruction attributes.
* Instruction attributes.
*/
ZydisInstructionAttributes attributes;
/**
* @brief Information about accessed CPU flags.
* Information about accessed CPU flags.
*
* DEPRECATED. This field will be removed in the next major release. Please use the
* `cpu_flags_read`/`cpu_flags_written` or `fpu_flags_read`/`fpu_flags_written` fields
* instead.
*/
struct
struct ZydisDecodedInstructionAccessedFlags_
{
/**
* @brief The CPU-flag action.
* The CPU-flag action.
*
* Use `ZydisGetAccessedFlagsByAction` to get a mask with all flags matching a specific
* action.
@@ -3860,160 +3885,186 @@ typedef struct ZydisDecodedInstruction_
ZydisCPUFlagAction action;
} accessed_flags[ZYDIS_CPUFLAG_MAX_VALUE + 1];
/**
* @brief Extended info for `AVX` instructions.
* A mask containing the CPU flags read by the instruction.
*
* The bits in this mask correspond to the actual bits in the `FLAGS/EFLAGS/RFLAGS`
* register.
*
* This mask includes the actions `TESTED` and `TESTED_MODIFIED`.
*/
struct
ZydisCPUFlags cpu_flags_read;
/**
* A mask containing the CPU flags written by the instruction.
*
* The bits in this mask correspond to the actual bits in the `FLAGS/EFLAGS/RFLAGS`
* register.
*
* This mask includes the actions `TESTED_MODIFIED`, `SET_0`, `SET_1` and `UNDEFINED`.
*/
ZydisCPUFlags cpu_flags_written;
/**
* A mask containing the FPU flags read by the instruction.
*/
ZydisFPUFlags fpu_flags_read;
/**
* A mask containing the FPU flags written by the instruction.
*/
ZydisFPUFlags fpu_flags_written;
/**
* Extended info for `AVX` instructions.
*/
struct ZydisDecodedInstructionAvx_
{
/**
* @brief The `AVX` vector-length.
* The `AVX` vector-length.
*/
ZyanU16 vector_length;
/**
* @brief Info about the embedded writemask-register (`AVX-512` and `KNC` only).
* Info about the embedded writemask-register (`AVX-512` and `KNC` only).
*/
struct
struct ZydisDecodedInstructionAvxMask_
{
/**
* @brief The masking mode.
* The masking mode.
*/
ZydisMaskMode mode;
/**
* @brief The mask register.
* The mask register.
*/
ZydisRegister reg;
} mask;
/**
* @brief Contains info about the `AVX` broadcast.
* Contains info about the `AVX` broadcast.
*/
struct
struct ZydisDecodedInstructionAvxBroadcast_
{
/**
* @brief Signals, if the broadcast is a static broadcast.
* Signals, if the broadcast is a static broadcast.
*
* This is the case for instructions with inbuild broadcast functionality, which is
* This is the case for instructions with inbuilt broadcast functionality, which is
* always active and not controlled by the `EVEX/MVEX.RC` bits.
*/
ZyanBool is_static;
/**
* @brief The `AVX` broadcast-mode.
* The `AVX` broadcast-mode.
*/
ZydisBroadcastMode mode;
} broadcast;
/**
* @brief Contains info about the `AVX` rounding.
* Contains info about the `AVX` rounding.
*/
struct
struct ZydisDecodedInstructionAvxRounding_
{
/**
* @brief The `AVX` rounding-mode.
* The `AVX` rounding-mode.
*/
ZydisRoundingMode mode;
} rounding;
/**
* @brief Contains info about the `AVX` register-swizzle (`KNC` only).
* Contains info about the `AVX` register-swizzle (`KNC` only).
*/
struct
struct ZydisDecodedInstructionAvxSwizzle_
{
/**
* @brief The `AVX` register-swizzle mode.
* The `AVX` register-swizzle mode.
*/
ZydisSwizzleMode mode;
} swizzle;
/**
* @brief Contains info about the `AVX` data-conversion (`KNC` only).
* Contains info about the `AVX` data-conversion (`KNC` only).
*/
struct
struct ZydisDecodedInstructionAvxConversion_
{
/**
* @brief The `AVX` data-conversion mode.
* The `AVX` data-conversion mode.
*/
ZydisConversionMode mode;
} conversion;
/**
* @brief Signals, if the `SAE` (suppress-all-exceptions) functionality is enabled for
* the instruction.
* Signals, if the `SAE` (suppress-all-exceptions) functionality is
* enabled for the instruction.
*/
ZyanBool has_sae;
/**
* @brief Signals, if the instruction has a memory-eviction-hint (`KNC` only).
* Signals, if the instruction has a memory-eviction-hint (`KNC` only).
*/
ZyanBool has_eviction_hint;
// TODO: publish EVEX tuple-type and MVEX functionality
} avx;
/**
* @brief Meta info.
* Meta info.
*/
struct
struct ZydisDecodedInstructionMeta_
{
/**
* @brief The instruction category.
* The instruction category.
*/
ZydisInstructionCategory category;
/**
* @brief The ISA-set.
* The ISA-set.
*/
ZydisISASet isa_set;
/**
* @brief The ISA-set extension.
* The ISA-set extension.
*/
ZydisISAExt isa_ext;
/**
* @brief The branch type.
* The branch type.
*/
ZydisBranchType branch_type;
/**
* @brief The exception class.
* The exception class.
*/
ZydisExceptionClass exception_class;
} meta;
/**
* @brief Detailed info about different instruction-parts like `ModRM`, `SIB` or
* encoding-prefixes.
* Detailed info about different instruction-parts like `ModRM`, `SIB` or
* encoding-prefixes.
*/
struct
struct ZydisDecodedInstructionRaw_
{
/**
* @brief The number of legacy prefixes.
* The number of legacy prefixes.
*/
ZyanU8 prefix_count;
/**
* @brief Detailed info about the legacy prefixes (including `REX`).
* Detailed info about the legacy prefixes (including `REX`).
*/
struct
struct ZydisDecodedInstructionRawPrefixes_
{
/**
* @brief The prefix type.
* The prefix type.
*/
ZydisPrefixType type;
/**
* @brief The prefix byte.
* The prefix byte.
*/
ZyanU8 value;
} prefixes[ZYDIS_MAX_INSTRUCTION_LENGTH];
/**
* @brief Detailed info about the `REX` prefix.
* Detailed info about the `REX` prefix.
*/
struct
struct ZydisDecodedInstructionRawRex_
{
/**
* @brief 64-bit operand-size promotion.
* 64-bit operand-size promotion.
*/
ZyanU8 W;
/**
* @brief Extension of the `ModRM.reg` field.
* Extension of the `ModRM.reg` field.
*/
ZyanU8 R;
/**
* @brief Extension of the `SIB.index` field.
* Extension of the `SIB.index` field.
*/
ZyanU8 X;
/**
* @brief Extension of the `ModRM.rm`, `SIB.base`, or `opcode.reg` field.
* Extension of the `ModRM.rm`, `SIB.base`, or `opcode.reg` field.
*/
ZyanU8 B;
/**
* @brief The offset of the effective `REX` byte, relative to the beginning of the
* instruction, in bytes.
* The offset of the effective `REX` byte, relative to the beginning of the
* instruction, in bytes.
*
* This offset always points to the "effective" `REX` prefix (the one closest to the
* instruction opcode), if multiple `REX` prefixes are present.
@@ -4025,320 +4076,320 @@ typedef struct ZydisDecodedInstruction_
ZyanU8 offset;
} rex;
/**
* @brief Detailed info about the `XOP` prefix.
* Detailed info about the `XOP` prefix.
*/
struct
struct ZydisDecodedInstructionRawXop_
{
/**
* @brief Extension of the `ModRM.reg` field (inverted).
* Extension of the `ModRM.reg` field (inverted).
*/
ZyanU8 R;
/**
* @brief Extension of the `SIB.index` field (inverted).
* Extension of the `SIB.index` field (inverted).
*/
ZyanU8 X;
/**
* @brief Extension of the `ModRM.rm`, `SIB.base`, or `opcode.reg` field (inverted).
* Extension of the `ModRM.rm`, `SIB.base`, or `opcode.reg` field (inverted).
*/
ZyanU8 B;
/**
* @brief Opcode-map specifier.
* Opcode-map specifier.
*/
ZyanU8 m_mmmm;
/**
* @brief 64-bit operand-size promotion or opcode-extension.
* 64-bit operand-size promotion or opcode-extension.
*/
ZyanU8 W;
/**
* @brief `NDS`/`NDD` (non-destructive-source/destination) register specifier
* (inverted).
* `NDS`/`NDD` (non-destructive-source/destination) register
* specifier (inverted).
*/
ZyanU8 vvvv;
/**
* @brief Vector-length specifier.
* Vector-length specifier.
*/
ZyanU8 L;
/**
* @brief Compressed legacy prefix.
* Compressed legacy prefix.
*/
ZyanU8 pp;
/**
* @brief The offset of the first xop byte, relative to the beginning of the
* instruction, in bytes.
* The offset of the first xop byte, relative to the beginning of
* the instruction, in bytes.
*/
ZyanU8 offset;
} xop;
/**
* @brief Detailed info about the `VEX` prefix.
* Detailed info about the `VEX` prefix.
*/
struct
struct ZydisDecodedInstructionRawVex_
{
/**
* @brief Extension of the `ModRM.reg` field (inverted).
* Extension of the `ModRM.reg` field (inverted).
*/
ZyanU8 R;
/**
* @brief Extension of the `SIB.index` field (inverted).
* Extension of the `SIB.index` field (inverted).
*/
ZyanU8 X;
/**
* @brief Extension of the `ModRM.rm`, `SIB.base`, or `opcode.reg` field (inverted).
* Extension of the `ModRM.rm`, `SIB.base`, or `opcode.reg` field (inverted).
*/
ZyanU8 B;
/**
* @brief Opcode-map specifier.
* Opcode-map specifier.
*/
ZyanU8 m_mmmm;
/**
* @brief 64-bit operand-size promotion or opcode-extension.
* 64-bit operand-size promotion or opcode-extension.
*/
ZyanU8 W;
/**
* @brief `NDS`/`NDD` (non-destructive-source/destination) register specifier
* (inverted).
* `NDS`/`NDD` (non-destructive-source/destination) register specifier
* (inverted).
*/
ZyanU8 vvvv;
/**
* @brief Vector-length specifier.
* Vector-length specifier.
*/
ZyanU8 L;
/**
* @brief Compressed legacy prefix.
* Compressed legacy prefix.
*/
ZyanU8 pp;
/**
* @brief The offset of the first `VEX` byte, relative to the beginning of the
* instruction, in bytes.
* The offset of the first `VEX` byte, relative to the beginning of the instruction, in
* bytes.
*/
ZyanU8 offset;
/**
* @brief The size of the `VEX` prefix, in bytes.
* The size of the `VEX` prefix, in bytes.
*/
ZyanU8 size;
} vex;
/**
* @brief Detailed info about the `EVEX` prefix.
* Detailed info about the `EVEX` prefix.
*/
struct
struct ZydisDecodedInstructionRawEvex_
{
/**
* @brief Extension of the `ModRM.reg` field (inverted).
* Extension of the `ModRM.reg` field (inverted).
*/
ZyanU8 R;
/**
* @brief Extension of the `SIB.index/vidx` field (inverted).
* Extension of the `SIB.index/vidx` field (inverted).
*/
ZyanU8 X;
/**
* @brief Extension of the `ModRM.rm` or `SIB.base` field (inverted).
* Extension of the `ModRM.rm` or `SIB.base` field (inverted).
*/
ZyanU8 B;
/**
* @brief High-16 register specifier modifier (inverted).
* High-16 register specifier modifier (inverted).
*/
ZyanU8 R2;
/**
* @brief Opcode-map specifier.
* Opcode-map specifier.
*/
ZyanU8 mm;
/**
* @brief 64-bit operand-size promotion or opcode-extension.
* 64-bit operand-size promotion or opcode-extension.
*/
ZyanU8 W;
/**
* @brief `NDS`/`NDD` (non-destructive-source/destination) register specifier
* (inverted).
* `NDS`/`NDD` (non-destructive-source/destination) register specifier
* (inverted).
*/
ZyanU8 vvvv;
/**
* @brief Compressed legacy prefix.
* Compressed legacy prefix.
*/
ZyanU8 pp;
/**
* @brief Zeroing/Merging.
* Zeroing/Merging.
*/
ZyanU8 z;
/**
* @brief Vector-length specifier or rounding-control (most significant bit).
* Vector-length specifier or rounding-control (most significant bit).
*/
ZyanU8 L2;
/**
* @brief Vector-length specifier or rounding-control (least significant bit).
* Vector-length specifier or rounding-control (least significant bit).
*/
ZyanU8 L;
/**
* @brief Broadcast/RC/SAE context.
* Broadcast/RC/SAE context.
*/
ZyanU8 b;
/**
* @brief High-16 `NDS`/`VIDX` register specifier.
* High-16 `NDS`/`VIDX` register specifier.
*/
ZyanU8 V2;
/**
* @brief Embedded opmask register specifier.
* Embedded opmask register specifier.
*/
ZyanU8 aaa;
/**
* @brief The offset of the first evex byte, relative to the beginning of the
* instruction, in bytes.
* The offset of the first evex byte, relative to the beginning of the
* instruction, in bytes.
*/
ZyanU8 offset;
} evex;
/**
* @brief Detailed info about the `MVEX` prefix.
* Detailed info about the `MVEX` prefix.
*/
struct
struct ZydisDecodedInstructionRawMvex_
{
/**
* @brief Extension of the `ModRM.reg` field (inverted).
* Extension of the `ModRM.reg` field (inverted).
*/
ZyanU8 R;
/**
* @brief Extension of the `SIB.index/vidx` field (inverted).
* Extension of the `SIB.index/vidx` field (inverted).
*/
ZyanU8 X;
/**
* @brief Extension of the `ModRM.rm` or `SIB.base` field (inverted).
* Extension of the `ModRM.rm` or `SIB.base` field (inverted).
*/
ZyanU8 B;
/**
* @brief High-16 register specifier modifier (inverted).
* High-16 register specifier modifier (inverted).
*/
ZyanU8 R2;
/**
* @brief Opcode-map specifier.
* Opcode-map specifier.
*/
ZyanU8 mmmm;
/**
* @brief 64-bit operand-size promotion or opcode-extension.
* 64-bit operand-size promotion or opcode-extension.
*/
ZyanU8 W;
/**
* @brief `NDS`/`NDD` (non-destructive-source/destination) register specifier
* (inverted).
* `NDS`/`NDD` (non-destructive-source/destination) register specifier
* (inverted).
*/
ZyanU8 vvvv;
/**
* @brief Compressed legacy prefix.
* Compressed legacy prefix.
*/
ZyanU8 pp;
/**
* @brief Non-temporal/eviction hint.
* Non-temporal/eviction hint.
*/
ZyanU8 E;
/**
* @brief Swizzle/broadcast/up-convert/down-convert/static-rounding controls.
* Swizzle/broadcast/up-convert/down-convert/static-rounding controls.
*/
ZyanU8 SSS;
/**
* @brief High-16 `NDS`/`VIDX` register specifier.
* High-16 `NDS`/`VIDX` register specifier.
*/
ZyanU8 V2;
/**
* @brief Embedded opmask register specifier.
* Embedded opmask register specifier.
*/
ZyanU8 kkk;
/**
* @brief The offset of the first mvex byte, relative to the beginning of the
* instruction, in bytes.
* The offset of the first mvex byte, relative to the beginning of the
* instruction, in bytes.
*/
ZyanU8 offset;
} mvex;
/**
* @brief Detailed info about the `ModRM` byte.
* Detailed info about the `ModRM` byte.
*/
struct
struct ZydisDecodedInstructionModRm_
{
/**
* @brief The addressing mode.
* The addressing mode.
*/
ZyanU8 mod;
/**
* @brief Register specifier or opcode-extension.
* Register specifier or opcode-extension.
*/
ZyanU8 reg;
/**
* @brief Register specifier or opcode-extension.
* Register specifier or opcode-extension.
*/
ZyanU8 rm;
/**
* @brief The offset of the `ModRM` byte, relative to the beginning of the
* instruction, in bytes.
* The offset of the `ModRM` byte, relative to the beginning of the
* instruction, in bytes.
*/
ZyanU8 offset;
} modrm;
/**
* @brief Detailed info about the `SIB` byte.
* Detailed info about the `SIB` byte.
*/
struct
struct ZydisDecodedInstructionRawSib_
{
/**
* @brief The scale factor.
* The scale factor.
*/
ZyanU8 scale;
/**
* @brief The index-register specifier.
* The index-register specifier.
*/
ZyanU8 index;
/**
* @brief The base-register specifier.
* The base-register specifier.
*/
ZyanU8 base;
/**
* @brief The offset of the `SIB` byte, relative to the beginning of the instruction,
* in bytes.
* The offset of the `SIB` byte, relative to the beginning of the
* instruction, in bytes.
*/
ZyanU8 offset;
} sib;
/**
* @brief Detailed info about displacement-bytes.
* Detailed info about displacement-bytes.
*/
struct
struct ZydisDecodedInstructionRawDisp_
{
/**
* @brief The displacement value
* The displacement value
*/
ZyanI64 value;
/**
* @brief The physical displacement size, in bits.
* The physical displacement size, in bits.
*/
ZyanU8 size;
// TODO: publish cd8 scale
/**
* @brief The offset of the displacement data, relative to the beginning of the
* instruction, in bytes.
* The offset of the displacement data, relative to the beginning of the
* instruction, in bytes.
*/
ZyanU8 offset;
} disp;
/**
* @brief Detailed info about immediate-bytes.
* Detailed info about immediate-bytes.
*/
struct
struct ZydisDecodedInstructionRawImm_
{
/**
* @brief Signals, if the immediate value is signed.
* Signals, if the immediate value is signed.
*/
ZyanBool is_signed;
/**
* @brief Signals, if the immediate value contains a relative offset. You can use
* `ZydisCalcAbsoluteAddress` to determine the absolute address value.
* Signals, if the immediate value contains a relative offset. You can use
* `ZydisCalcAbsoluteAddress` to determine the absolute address value.
*/
ZyanBool is_relative;
/**
* @brief The immediate value.
* The immediate value.
*/
union
union ZydisDecodedInstructionRawImmValue_
{
ZyanU64 u;
ZyanI64 s;
} value;
/**
* @brief The physical immediate size, in bits.
* The physical immediate size, in bits.
*/
ZyanU8 size;
/**
* @brief The offset of the immediate data, relative to the beginning of the
* instruction, in bytes.
* The offset of the immediate data, relative to the beginning of the
* instruction, in bytes.
*/
ZyanU8 offset;
} imm[2];
+43 -43
View File
@@ -11,13 +11,13 @@
void reset_fpu(x86emu_t* emu)
{
memset(emu->fpu, 0, sizeof(emu->fpu));
memset(emu->mmx87, 0, sizeof(emu->mmx87));
memset(emu->fpu_ld, 0, sizeof(emu->fpu_ld));
emu->cw = 0x37F;
emu->sw.x16 = 0x0000;
emu->top = 0;
emu->fpu_stack = 0;
for(int i=0; i<9; ++i)
for(int i=0; i<8; ++i)
emu->p_regs[i].tag = 0b11; // STx is empty
}
@@ -67,7 +67,7 @@ void fpu_fbld(x86emu_t* emu, uint8_t* s) {
}
#define FPU_t fpu_reg_t
#define FPU_t mmx87_regs_t
#define BIAS80 16383
#define BIAS64 1023
// long double (80bits) -> double (64bits)
@@ -83,8 +83,8 @@ void LD2D(void* ld, void* d)
#if 1
memcpy(&val, ld, 10);
#else
val.f.l.lower = *(uint32_t*)ld;
val.f.l.upper = *(uint32_t*)(char*)(ld+4);
val.f.ud[0] = *(uint32_t*)ld;
val.f.ud[1] = *(uint32_t*)(char*)(ld+4);
val.b = *(int16_t*)((char*)ld+8);
#endif
int32_t exp64 = (((uint32_t)(val.b&0x7fff) - BIAS80) + BIAS64);
@@ -95,21 +95,21 @@ void LD2D(void* ld, void* d)
if((uint32_t)(val.b&0x7fff)==0x7fff) {
// infinity and nans
int t = 0; //nan
switch((val.f.l.upper>>30)) {
case 0: if((val.f.l.upper&(1<<29))==0) t = 1;
switch((val.f.ud[1]>>30)) {
case 0: if((val.f.ud[1]&(1<<29))==0) t = 1;
break;
case 2: if((val.f.l.upper&(1<<29))==0) t = 1;
case 2: if((val.f.ud[1]&(1<<29))==0) t = 1;
break;
}
if(t) { // infinite
result.d = HUGE_VAL;
} else { // NaN
result.l.upper = 0x7ff << 20;
result.l.lower = 0;
result.ud[1] = 0x7ff << 20;
result.ud[0] = 0;
}
if(val.b&0x8000)
result.l.upper |= 0x80000000;
*(uint64_t*)d = result.ll;
result.ud[1] |= 0x80000000;
*(uint64_t*)d = result.q;
return;
}
if(((uint32_t)(val.b&0x7fff)==0) || (exp64<=0)) {
@@ -128,17 +128,17 @@ void LD2D(void* ld, void* d)
// to big value...
result.d = HUGE_VAL;
if(val.b&0x8000)
result.l.upper |= 0x80000000;
*(uint64_t*)d = result.ll;
result.ud[1] |= 0x80000000;
*(uint64_t*)d = result.q;
return;
}
uint64_t mant64 = (val.f.ll >> 11) & 0xfffffffffffffLL;
uint64_t mant64 = (val.f.q >> 11) & 0xfffffffffffffLL;
uint32_t sign = (val.b&0x8000)?1:0;
result.ll = mant64;
result.l.upper |= (sign <<31)|((exp64final&0x7ff) << 20);
result.q = mant64;
result.ud[1] |= (sign <<31)|((exp64final&0x7ff) << 20);
*(uint64_t*)d = result.ll;
*(uint64_t*)d = result.q;
}
// double (64bits) -> long double (80bits)
@@ -151,12 +151,12 @@ void D2LD(void* d, void* ld)
} val;
#pragma pack(pop)
FPU_t s;
s.ll = *(uint64_t*)d; // use memcpy to avoid risk of Bus Error?
s.q = *(uint64_t*)d; // use memcpy to avoid risk of Bus Error?
// do special value first
if((s.ll&0x7fffffffffffffffLL)==0) {
if((s.q&0x7fffffffffffffffLL)==0) {
// zero...
val.f.ll = 0;
if(s.l.upper&0x8000)
val.f.q = 0;
if(s.ud[1]&0x8000)
val.b = 0x8000;
else
val.b = 0;
@@ -164,10 +164,10 @@ void D2LD(void* d, void* ld)
return;
}
int32_t sign80 = (s.l.upper&0x80000000)?1:0;
int32_t exp80 = s.l.upper&0x7ff00000;
int32_t sign80 = (s.ud[1]&0x80000000)?1:0;
int32_t exp80 = s.ud[1]&0x7ff00000;
int32_t exp80final = (exp80>>20);
int64_t mant80 = s.ll&0x000fffffffffffffLL;
int64_t mant80 = s.q&0x000fffffffffffffLL;
int64_t mant80final = (mant80 << 11);
if(exp80final==0x7ff) {
// NaN and Infinite
@@ -183,7 +183,7 @@ void D2LD(void* d, void* ld)
}
}
val.b = ((int16_t)(sign80)<<15)| (int16_t)(exp80final);
val.f.ll = mant80final;
val.f.q = mant80final;
memcpy(ld, &val, 10);
/*memcpy(ld, &f.ll, 8);
memcpy((char*)ld + 8, &val.b, 2);*/
@@ -196,6 +196,21 @@ double FromLD(void* ld)
return ret;
}
#ifndef HAVE_LD80BITS
long double LD2localLD(void* ld)
{
// local implementation may not be try Quad precision, but double-double precision, so simple way to keep the 80bits precision in the conversion
double ret;
LD2D(ld, &ret);
return ret;
}
#else
long double LD2localLD(void* ld)
{
return *(long double*)ld;
}
#endif
void fpu_loadenv(x86emu_t* emu, char* p, int b16)
{
emu->cw = *(uint16_t*)p;
@@ -270,14 +285,9 @@ void fpu_fxsave(x86emu_t* emu, void* ed)
p->MxCsr_Mask = 0;
// copy MMX regs...
for(int i=0; i<8; ++i)
memcpy(&p->FloatRegisters[i].q[0], &emu->mmx[0], sizeof(emu->mmx[0]));
memcpy(&p->FloatRegisters[i].q[0], &emu->mmx87[0], sizeof(emu->mmx87[0]));
// copy SSE regs
memcpy(&p->XmmRegisters[0], &emu->xmm[0], sizeof(emu->xmm));
// put also FPU regs in a reserved area... on XMM 8-15
for(int i=0; i<8; ++i)
memcpy(&p->XmmRegisters[8+i].q[0], &emu->fpu[0], sizeof(emu->fpu[0]));
// put a magic sign in reserved area, box86 specific
((unsigned int *)p->Reserved4)[11] = 0x50515253;
}
void fpu_fxrstor(x86emu_t* emu, void* ed)
@@ -291,17 +301,7 @@ void fpu_fxrstor(x86emu_t* emu, void* ed)
emu->p_regs[i].tag = (tags>>(i*2))?0:0b11;
// copy back MMX regs...
for(int i=0; i<8; ++i)
memcpy(&emu->mmx[i], &p->FloatRegisters[i].q[0], sizeof(emu->mmx[0]));
memcpy(&emu->mmx87[i], &p->FloatRegisters[i].q[0], sizeof(emu->mmx87[0]));
// copy SSE regs
memcpy(&emu->xmm[0], &p->XmmRegisters[0], sizeof(emu->xmm));
// check the box86 magic sign in reserved area
if(((unsigned int *)p->Reserved4)[11] == 0x50515253) {
// also FPU regs where a reserved area... on XMM 8-15?
for(int i=0; i<8; ++i)
memcpy(&emu->fpu[0], &p->XmmRegisters[8+i].q[0], sizeof(emu->fpu[0]));
} else {
// copy the mmx to fpu...
for(int i=0; i<8; ++i)
memcpy(&emu->fpu[0], &emu->mmx[i], sizeof(emu->mmx[0]));
}
}
+5 -5
View File
@@ -18,9 +18,9 @@ void Run66D9(x86emu_t *emu);
void Run66DD(x86emu_t *emu);
void RunDF(x86emu_t *emu);
#define ST0 emu->fpu[emu->top]
#define ST1 emu->fpu[(emu->top+1)&7]
#define ST(a) emu->fpu[(emu->top+(a))&7]
#define ST0 emu->mmx87[emu->top]
#define ST1 emu->mmx87[(emu->top+1)&7]
#define ST(a) emu->mmx87[(emu->top+(a))&7]
#define STld(a) emu->fpu_ld[(emu->top+(a))&7]
#define STll(a) emu->fpu_ll[(emu->top+(a))&7]
@@ -133,7 +133,7 @@ static inline double fpu_round(x86emu_t* emu, double d) {
}
static inline void fpu_fxam(x86emu_t* emu) {
emu->sw.f.F87_C1 = (ST0.l.upper&0x80000000)?1:0;
emu->sw.f.F87_C1 = (ST0.ud[1]&0x80000000)?1:0;
if(!emu->fpu_stack) {
emu->sw.f.F87_C3 = 1;
emu->sw.f.F87_C2 = 0;
@@ -187,7 +187,7 @@ static inline void fpu_ftst(x86emu_t* emu) {
// normal...
emu->sw.f.F87_C3 = 0;
emu->sw.f.F87_C2 = 0;
emu->sw.f.F87_C0 = (ST0.l.upper&0x80000000)?1:0;
emu->sw.f.F87_C0 = (ST0.ud[1]&0x80000000)?1:0;
}
void fpu_fbst(x86emu_t* emu, uint8_t* d);
+11 -22
View File
@@ -15,7 +15,6 @@ typedef struct kh_symbolmap_s kh_symbolmap_t;
typedef struct library_s library_t;
typedef struct kh_fts_s kh_fts_t;
typedef struct kh_threadstack_s kh_threadstack_t;
typedef struct kh_cancelthread_s kh_cancelthread_t;
typedef struct zydis_dec_s zydis_dec_t;
typedef struct atfork_fnc_s {
uintptr_t prepare;
@@ -29,8 +28,10 @@ typedef struct dynablocklist_s dynablocklist_t;
typedef struct mmaplist_s mmaplist_t;
typedef struct kh_dynablocks_s kh_dynablocks_t;
#endif
#define DYNAMAP_SIZE (1<<20)
#define DYNAMAP_SHIFT 12
#define DYNAMAP_SHIFT 16
#define DYNAMAP_SIZE (1<<(32-DYNAMAP_SHIFT))
#define JMPTABL_SHIFT 16
#define JMPTABL_SIZE (1<<(32-JMPTABL_SHIFT))
typedef void* (*procaddess_t)(const char* name);
typedef void* (*vkprocaddess_t)(void* instance, const char* name);
@@ -49,9 +50,7 @@ typedef struct needed_libs_s {
int size;
library_t **libs;
} needed_libs_t;
void add_neededlib(needed_libs_t* needed, library_t* lib);
void free_neededlib(needed_libs_t* needed);
void free_neededlib(needed_libs_t* needed); // defined in library.c
typedef struct base_segment_s {
uintptr_t base;
@@ -61,7 +60,6 @@ typedef struct base_segment_s {
} base_segment_t;
typedef struct box86context_s {
uint32_t* memprot; // protection flags by 4K block
path_collection_t box86_path; // PATH env. variable
path_collection_t box86_ld_lib; // LD_LIBRARY_PATH env. variable
@@ -100,8 +98,6 @@ typedef struct box86context_s {
lib_t *local_maplib; // libs and symbols openned has local (only collection of libs, no symbols)
kh_threadstack_t *stacksizes; // stack sizes attributes for thread (temporary)
kh_cancelthread_t *cancelthread; // thread cancel mecanism is bit complex, create a map to ease it
bridge_t *threads; // threads
bridge_t *system; // other bridges
uintptr_t vsyscall; // vsyscall bridge value
dlprivate_t *dlprivate; // dlopen library map
@@ -131,14 +127,10 @@ typedef struct box86context_s {
void* sdl1allocrw;
void* sdl1freerw;
library_t *sdl1mixerlib;
library_t *sdl1imagelib;
library_t *sdl1ttflib;
library_t *sdl2lib; // shortcut to SDL2 library (if loaded)
void* sdl2allocrw;
void* sdl2freerw;
library_t *sdl2mixerlib;
library_t *sdl2imagelib;
library_t *sdl2ttflib;
library_t *x11lib;
library_t *libxcb;
library_t *libxcbxfixes;
@@ -206,16 +198,13 @@ int AddElfHeader(box86context_t* ctx, elfheader_t* head);
// return the tlsbase (negative) for the new TLS partition created (no partition index is stored in the context)
int AddTLSPartition(box86context_t* context, int tlssize);
#define PROT_DYNAREC 0x10000
void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot);
uint32_t getProtection(uintptr_t addr);
#ifdef DYNAREC
void protectDB(uintptr_t addr, uintptr_t size);
void unprotectDB(uintptr_t addr, uintptr_t size);
#endif
// defined in fact in threads.c
void thread_set_emu(x86emu_t* emu);
x86emu_t* thread_get_emu();
#endif //__BOX86CONTEXT_H_
// unlock mutex that are locked by current thread (for signal handling). Return a mask of unlock mutex
int unlockMutex();
// relock the muxtex that were unlocked
void relockMutex(int locks);
#endif //__BOX86CONTEXT_H_
+20 -1
View File
@@ -23,12 +23,31 @@ typedef struct dynablocklist_s dynablocklist_t;
uintptr_t AllocDynarecMap(dynablock_t* db, int size);
void FreeDynarecMap(dynablock_t* db, uintptr_t addr, uint32_t size);
void addDBFromAddressRange(uintptr_t addr, uintptr_t size, int nolinker);
void addDBFromAddressRange(uintptr_t addr, uintptr_t size);
void cleanDBFromAddressRange(uintptr_t addr, uintptr_t size, int destroy);
dynablocklist_t* getDB(uintptr_t idx);
void addJumpTableIfDefault(void* addr, void* jmp);
void setJumpTableDefault(void* addr);
int isJumpTableDefault(void* addr);
uintptr_t getJumpTable();
uintptr_t getJumpTableAddress(uintptr_t addr);
#endif
#define PROT_DYNAREC 0x80
void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot);
void setProtection(uintptr_t addr, uintptr_t size, uint32_t prot);
uint32_t getProtection(uintptr_t addr);
#ifdef DYNAREC
void protectDB(uintptr_t addr, uintptr_t size);
void unprotectDB(uintptr_t addr, uintptr_t size);
#endif
// unlock mutex that are locked by current thread (for signal handling). Return a mask of unlock mutex
int unlockCustommemMutex();
// relock the muxtex that were unlocked
void relockCustommemMutex(int locks);
void init_custommem_helper(box86context_t* ctx);
void fini_custommem_helper(box86context_t* ctx);
+2 -4
View File
@@ -9,12 +9,10 @@ extern int box86_dynarec;
extern int box86_pagesize;
#ifdef DYNAREC
extern int box86_dynarec_dump;
extern int box86_dynarec_linker;
extern int box86_dynarec_trace;
extern int box86_dynarec_forced;
extern int box86_dynarec_largest;
extern int box86_dynarec_smc;
extern int box86_dynarec_safemmap;
extern uintptr_t box86_nodynarec_start, box86_nodynarec_end;
#ifdef ARM
extern int arm_vfp; // vfp version (3 or 4), with 32 registers is mendatory
extern int arm_swap;
@@ -44,7 +42,7 @@ extern FILE* ftrace;
#define printf_log(L, ...) do {if(L<=box86_log) {fprintf(ftrace, __VA_ARGS__); fflush(ftrace);}} while(0)
#define dynarec_log(L, ...) do {if(L<=box86_dynarec_log) {fprintf(ftrace, __VA_ARGS__); /*fflush(ftrace);*/}} while(0)
#define dynarec_log(L, ...) do {if(L<=box86_dynarec_log) {fprintf(ftrace, __VA_ARGS__); fflush(ftrace);}} while(0)
#define EXPORT __attribute__((visibility("default")))
#ifdef BUILD_DYNAMIC
+1 -5
View File
@@ -7,14 +7,10 @@ typedef struct dynablocklist_s dynablocklist_t;
typedef struct kh_dynablocks_s kh_dynablocks_t;
uint32_t X31_hash_code(void* addr, int len);
dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int nolinker, int direct);
dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct);
void FreeDynablockList(dynablocklist_t** dynablocks);
void FreeDynablock(dynablock_t* db);
void MarkDynablock(dynablock_t* db);
void MarkDynablockList(dynablocklist_t** dynablocks);
void ProtectDynablock(dynablock_t* db);
void ProtectDynablockList(dynablocklist_t** dynablocks);
void ProtectDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
void FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
+11 -10
View File
@@ -24,30 +24,30 @@ int AllocElfMemory(box86context_t* context, elfheader_t* head, int mainbin);
void FreeElfMemory(elfheader_t* head);
int LoadElfMemory(FILE* f, box86context_t* context, elfheader_t* head);
int ReloadElfMemory(FILE* f, box86context_t* context, elfheader_t* head);
int RelocateElf(lib_t *maplib, lib_t* local_maplib, elfheader_t* head);
int RelocateElfPlt(lib_t *maplib, lib_t* local_maplib, elfheader_t* head);
int RelocateElf(lib_t* maplib, lib_t* local_maplib, elfheader_t* head);
int RelocateElfPlt(lib_t* maplib, lib_t* local_maplib, elfheader_t* head);
void CalcStack(elfheader_t* h, uint32_t* stacksz, int* stackalign);
uintptr_t GetEntryPoint(lib_t* maplib, elfheader_t* h);
uintptr_t GetLastByte(elfheader_t* h);
void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* weaksymbols, kh_mapsymbols_t* localsymbols, elfheader_t* h);
int LoadNeededLibs(elfheader_t* h, lib_t *maplib, needed_libs_t* neededlibs, int local, box86context_t *box86, x86emu_t* emu);
void AddSymbols(lib_t* maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* weaksymbols, kh_mapsymbols_t* localsymbols, elfheader_t* h);
int LoadNeededLibs(elfheader_t* h, lib_t* maplib, needed_libs_t* neededlibs, library_t* deplib, int local, box86context_t* box86, x86emu_t* emu);
uintptr_t GetElfInit(elfheader_t* h);
uintptr_t GetElfFini(elfheader_t* h);
void RunElfInit(elfheader_t* h, x86emu_t *emu);
void RunElfFini(elfheader_t* h, x86emu_t *emu);
void RunDeferedElfInit(x86emu_t *emu);
void RunElfInit(elfheader_t* h, x86emu_t* emu);
void RunElfFini(elfheader_t* h, x86emu_t* emu);
void RunDeferedElfInit(x86emu_t* emu);
void* GetBaseAddress(elfheader_t* h);
void* GetElfDelta(elfheader_t* h);
uint32_t GetBaseSize(elfheader_t* h);
int IsAddressInElfSpace(elfheader_t* h, uintptr_t addr);
elfheader_t* FindElfAddress(box86context_t *context, uintptr_t addr);
elfheader_t* FindElfAddress(box86context_t* context, uintptr_t addr);
const char* FindNearestSymbolName(elfheader_t* h, void* p, uintptr_t* start, uint32_t* sz);
int32_t GetTLSBase(elfheader_t* h);
uint32_t GetTLSSize(elfheader_t* h);
void* GetTLSPointer(box86context_t* context, elfheader_t* h);
void* GetDTatOffset(box86context_t* context, int index, int offset);
#ifdef DYNAREC
dynablocklist_t* GetDynablocksFromAddress(box86context_t *context, uintptr_t addr);
dynablocklist_t* GetDynablocksFromAddress(box86context_t* context, uintptr_t addr);
dynablocklist_t* GetDynablocksFromElf(elfheader_t* h);
#endif
void ResetSpecialCaseMainElf(elfheader_t* h);
@@ -55,5 +55,6 @@ void CreateMemorymapFile(box86context_t* context, int fd);
int ElfCheckIfUseTCMallocMinimal(elfheader_t* h); // return 1 if tcmalloc is used
const char* GetSymbolVersion(elfheader_t* h, int version);
#endif //__ELF_LOADER_H_
#endif //__ELF_LOADER_H_
+32
View File
@@ -185,6 +185,35 @@ typedef struct my_GtkTreeViewClass_s
void (*_gtk_reserved4) (void);
} my_GtkTreeViewClass_t;
typedef struct my_GtkBinClass_s
{
my_GtkContainerClass_t parent_class;
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
} my_GtkBinClass_t;
typedef struct my_GtkWindowClass_s {
my_GtkBinClass_t parent_class;
void (* set_focus) (void* window, void* focus);
int (* frame_event) (void* window, void* event);
void (* activate_focus) (void* window);
void (* activate_default) (void* window);
void (* move_focus) (void* window, int direction);
void (*keys_changed) (void* window);
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
} my_GtkWindowClass_t;
typedef struct my_MetaFramesClass_s
{
my_GtkWindowClass_t parent_class;
} my_MetaFramesClass_t;
// GTypeValueTable
typedef struct my_GTypeValueTable_s {
void (*value_init) (void* value);
@@ -248,6 +277,9 @@ GTKCLASS(GtkAction) \
GTKCLASS(GtkLabel) \
GTKCLASS(GtkMisc) \
GTKCLASS(GtkTreeView) \
GTKCLASS(GtkBin) \
GTKCLASS(GtkWindow) \
GTKCLASS(MetaFrames) \
#define GTKCLASS(A) void Set##A##ID(int id);
GTKCLASSES()
+5 -3
View File
@@ -16,7 +16,7 @@ typedef struct kh_mapoffsets_s kh_mapoffsets_t;
typedef char* cstr_t;
lib_t *NewLibrarian(box86context_t* context, int ownlibs);
void FreeLibrarian(lib_t **maplib);
void FreeLibrarian(lib_t **maplib, x86emu_t* emu);
dlprivate_t *NewDLPrivate();
void FreeDLPrivate(dlprivate_t **lib);
@@ -24,7 +24,8 @@ box86context_t* GetLibrarianContext(lib_t* maplib);
kh_mapsymbols_t* GetMapSymbol(lib_t* maplib);
kh_mapsymbols_t* GetWeakSymbol(lib_t* maplib);
kh_mapsymbols_t* GetLocalSymbol(lib_t* maplib);
int AddNeededLib(lib_t* maplib, needed_libs_t* neededlibs, int local, const char* path, box86context_t* box86, x86emu_t* emu); // 0=success, 1=error
kh_mapsymbols_t* GetGlobalData(lib_t* maplib);
int AddNeededLib(lib_t* maplib, needed_libs_t* neededlibs, library_t* deplib, int local, const char* path, box86context_t* box86, x86emu_t* emu); // 0=success, 1=error
library_t* GetLibMapLib(lib_t* maplib, const char* name);
library_t* GetLibInternal(const char* name);
uintptr_t FindGlobalSymbol(lib_t *maplib, const char* name);
@@ -35,6 +36,7 @@ int GetGlobalNoWeakSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* st
int GetLocalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self);
int GetNoWeakSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self);
elfheader_t* GetGlobalSymbolElf(lib_t *maplib, const char* name);
int IsGlobalNoWeakSymbolInNative(lib_t *maplib, const char* name);
void AddSymbol(kh_mapsymbols_t *mapsymbols, const char* name, uintptr_t addr, uint32_t sz); // replace if already there
uintptr_t FindSymbol(kh_mapsymbols_t *mapsymbols, const char* name);
@@ -47,4 +49,4 @@ const char* FindSymbolName(lib_t *maplib, void* p, void** start, uint32_t* sz, c
void AddOffsetSymbol(lib_t *maplib, void* offs, const char* name);
const char* GetNameOffset(lib_t *maplib, void* offs);
#endif //__LIBRARIAN_H_
#endif //__LIBRARIAN_H_
+1 -1
View File
@@ -14,7 +14,7 @@ int AddSymbolsLibrary(lib_t* maplib, library_t* lib, x86emu_t* emu);
int FinalizeLibrary(library_t* lib, lib_t* local_maplib, x86emu_t* emu);
int ReloadLibrary(library_t* lib, x86emu_t* emu);
void InactiveLibrary(library_t* lib);
void Free1Library(library_t **lib);
void Free1Library(library_t **lib, x86emu_t* emu);
char* GetNameLib(library_t *lib);
int IsSameLib(library_t* lib, const char* path); // check if lib is same (path -> name)
+3
View File
@@ -44,8 +44,11 @@ void AlignSmpegInfo(void* dest, void* source); // x86 -> Arm
// stat64 is packed on i386, not on arm (and possibly other structures)
#undef st_atime
#undef st_atime_nsec
#undef st_mtime
#undef st_mtime_nsec
#undef st_ctime
#undef st_ctime_nsec
struct i386_stat64 {
uint64_t st_dev;
uint8_t __pad0[4];
Loaded 100 of 303 files, more files were not shown because too many files have changed in this diff. Show more