443 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
ptitSeb b2d5587ea1 Bumped to v0.2.0 2021-01-12 19:44:14 +01:00
ptitSeb 4b020ab4f5 Merge pull request #309 from heavygabriel/master
Simplified code
2021-01-11 19:43:05 +01:00
heavygabriel 088a85c125 Update COMPILE.md 2021-01-11 11:45:54 -05:00
heavygabriel 2bf60dc00d Removed some typos. 2021-01-11 11:39:04 -05:00
unknown b5ffa0e92a Simplified a bunch of ifs and elses 2021-01-11 10:21:01 -05:00
ptitSeb 258f7f9b50 Added BOX86_NOVULKAN to disable loading of vulkan libs 2021-01-10 11:24:55 +01:00
ptitSeb 07c403243d Added 66 CB opcode 2021-01-10 11:03:19 +01:00
ptitSeb 709de6a858 Fix compilation for build without Dynarec 2021-01-09 19:35:41 +01:00
ptitSeb dfed557f61 [DYNAREC] Fixed SAKF opcode, and improved a but flag handling (fixing regression on GIG Installer from Dec. 30th commit) 2021-01-09 17:36:27 +01:00
ptitSeb f143771be8 Merge pull request #303 from heavygabriel/master
Remove the //TODO: in USAGE.md
2021-01-08 19:20:00 +01:00
heavygabriel fc20c410c0 Delete TROUBLESHOOTING.md 2021-01-08 10:23:37 -05:00
heavygabriel 677205a288 Update USAGE.md
removed //TODO:
2021-01-08 09:17:37 -05:00
heavygabriel abb9acfd42 Create TROUBLESHOOTING.md
Information on how to solve specific problems.
2021-01-08 09:16:29 -05:00
ptitSeb 75dca68db0 Fixed custom allocator for memory block >= 256k (should help old 32bits Factorio, and maybe #274) 2021-01-08 09:53:03 +01:00
ptitSeb 5c1a8ad128 Fixed USAGE.md, default log is now 0 2021-01-08 09:51:44 +01:00
ptitSeb e4cf8f8c94 Merge pull request #302 from heavygabriel/master
Updated documentation
2021-01-08 07:49:19 +01:00
heavygabriel 30968917a4 Merge pull request #7 from heavygabriel/patch-7
Update USAGE.md
2021-01-07 18:59:11 -05:00
heavygabriel 84ea9e3301 Merge branch 'master' into patch-7 2021-01-07 18:59:02 -05:00
heavygabriel 1f9c046919 Merge pull request #6 from heavygabriel/patch-8
Update USAGE.md
2021-01-07 18:48:28 -05:00
heavygabriel cefe210184 Merge pull request #5 from heavygabriel/patch-9
Update USAGE.md
2021-01-07 18:47:29 -05:00
heavygabriel 02aa791fd9 Merge pull request #4 from heavygabriel/patch-10
Update COMPILE.md
2021-01-07 18:45:58 -05:00
heavygabriel d8c1341068 Merge pull request #2 from heavygabriel/patch-2
Patch 2
2021-01-07 18:45:14 -05:00
heavygabriel ca648ea128 Merge pull request #3 from heavygabriel/patch-3
Patch 3
2021-01-07 18:43:43 -05:00
heavygabriel daf5a9d91d Merge pull request #1 from heavygabriel/patch-1
Patch 1
2021-01-07 18:43:02 -05:00
heavygabriel 16b95f2088 Update COMPILE.md
Added further clarifications, fixed typos ,etc.
2021-01-07 18:38:26 -05:00
heavygabriel 41dfcb559a Update USAGE.md
Added a bit of documentation, fixed things, etc. (This really needs some love, can anyone better suited for the task contribute? thanks.
2021-01-07 18:32:11 -05:00
heavygabriel 37c871ec2e Update USAGE.md
Added a bit of documentation, fixed things, etc. (This really needs some love, can anyone better suited for the task contribute? thanks.
2021-01-07 18:31:18 -05:00
heavygabriel 34bd1ff42f Update USAGE.md
Added a bit of documentation, fixed things, etc. (This really needs some love, can anyone better suited for the task contribute? thanks.
2021-01-07 18:30:34 -05:00
heavygabriel e0f1d4fecf Update README.md
Changed how things are worded (again again+3 ) . Added some new clarification in the documentation (Need to see how to reword the box86 discord mentionning thingy) etc.
2021-01-07 18:16:37 -05:00
heavygabriel c94d992ef6 Update README.md
Changed how things are worded (again again+3 ) . Added some new clarification in the documentation (Need to see how to reword the box86 discord mentionning thingy) etc.
2021-01-07 18:16:34 -05:00
ptitSeb bfe83d827d Fixed a potential BUSERROR on 66 0F 12 opcode 2021-01-07 19:44:06 +01:00
ptitSeb 1c45795828 Merge pull request #298 from heavygabriel/patch-1
Update README.md
2021-01-07 16:09:30 +01:00
heavygabriel 8dc5c164d8 Update README.md
again, updated typos.
2021-01-07 09:34:47 -05:00
heavygabriel 326032aa23 Update README.md
Changed the notes for raspberry pi a bit, changed how the unity section is worded and generally changed small little typos and things.
2021-01-07 09:24:25 -05:00
ptitSeb b79e234da2 Merge pull request #297 from kalashnikovdmitryv/patch-1
Add flag for RPI4 with arm64+armhf multiatch
2021-01-06 20:32:50 +01:00
kalashnikovdmitryv 5bc6962a9d Update CMakeLists.txt 2021-01-06 22:23:21 +03:00
ptitSeb 168717a90a Added some more functions t wrapped libxslt 2021-01-06 20:02:56 +01:00
ptitSeb dd6b0f6c9a [DYNAREC] Tiny optim on dynablock creation 2021-01-05 22:04:27 +01:00
ptitSeb 0a3c678877 Fixed compilation on non Dynarec build 2021-01-04 18:57:26 +01:00
ptitSeb e2df6f6ce0 Added 66 F0 81/83 opcodes 2021-01-04 08:35:25 +01:00
ptitSeb e58ebdac18 [TRACE] Fix build when trace is enabled 2021-01-03 18:16:10 +01:00
ptitSeb 537312a91f Use Custom allocator for all hash map 2021-01-03 16:39:58 +01:00
ptitSeb 11c08acd6c [DYNAREC] Need to improve this optimization, reverting for now (help Unity3D games) 2021-01-03 15:40:48 +01:00
ptitSeb cf9a38fb02 [DYNBAREC] Try to make dynarec more resiliant on heavily multi-threaded program 2021-01-03 11:20:56 +01:00
ptitSeb 83dff2bf25 Merge branch 'master' of https://github.com/ptitSeb/box86 2021-01-03 10:43:03 +01:00
ptitSeb 49694f300a Fixed a warning on wrapped libdl 2021-01-03 10:21:10 +01:00
ptitSeb daddc8246e Small fixes in xcb wrapped functions signature 2021-01-03 10:20:14 +01:00
ptitSeb 9f92377edc Small change to some pthread wrapped functions 2021-01-02 16:18:21 +01:00
ptitSeb 1ce392d968 Fixed the added flags in O_* converters 2021-01-02 15:03:46 +01:00
ptitSeb bf730b43e2 Add a few more flags in O_* converters 2021-01-02 14:57:38 +01:00
ptitSeb a4adb47caf Various small changes in some libc functions signature 2021-01-02 14:47:19 +01:00
ptitSeb 9317572874 Minor changes to O_* flags handling and conversion 2021-01-02 13:13:58 +01:00
ptitSeb eca39e6a8f Improve Signal and Memory protection Handling on multi-thread program, and added BOX86_JITGDB=2 (Should help #273, KSP old linux32 version now works, should also help .net programs) 2021-01-01 18:32:18 +01:00
ptitSeb 4639dc8ffd Minor signature changes for some libpulse functions 2021-01-01 18:32:18 +01:00
ptitSeb 5a9b34f54b Added log for waitpid 2021-01-01 18:32:18 +01:00
ptitSeb dc07d477de Added syscall 318 getcpu (should help #217) 2021-01-01 18:09:53 +01:00
ptitSeb db5efa8908 Fix compile on non-Dynarec build 2021-01-01 11:12:38 +01:00
ptitSeb 7d462dd837 Try to detect Excution error on Signal handling, to help .net programs 2021-01-01 10:37:56 +01:00
ptitSeb 76010f63c0 Fixed BOX86_LOG=2 on some wrapped libc functions 2021-01-01 09:40:17 +01:00
ptitSeb be7f72808b Merge pull request #292 from Hacker1245/patch-1
Fix a typo
2020-12-31 16:27:01 +01:00
ptitSeb 25f1e8e6fa Fixed some lib pulse callback (should help both #193 and #293 and maybe other pulseaudio apps) 2020-12-31 16:25:10 +01:00
ptitSeb 047df311f0 Added xcb_send_request_with_fds64 to wrapped lib xcb 2020-12-31 16:23:24 +01:00
ptitSeb bcdd99328c [DYNAREC] Fixed a samll issue with Logs 2020-12-31 16:22:40 +01:00
ptitSeb 5cc76a0071 [DYNAREC] Another small optim on flags handling 2020-12-31 12:53:55 +01:00
ptitSeb dee55a9ac2 [DYNAREC] Fixed a potential segfault 2020-12-31 08:59:04 +01:00
ptitSeb 9ff20da9bb Added more slots for pulse audio callback (should help #293) 2020-12-30 22:56:42 +01:00
Hacker1245 0520f5abcd Fix a typo 2020-12-30 22:07:19 +01:00
ptitSeb e1201ff0de [DYNAREC] Optimize test emiter to avoid BFI/UBFX when possible 2020-12-30 18:13:32 +01:00
ptitSeb bc2d7e7396 [DYNAREC] Optimize shift emiter to avoid BFI/UBFX when possible 2020-12-30 17:50:58 +01:00
ptitSeb 9a058a2416 [DYNAREC] Optimize logic emiter to avoid BFI/UBFX when possible 2020-12-30 17:29:51 +01:00
ptitSeb 49fea86b28 [DYNAREC] Optimized math emiter to avoid UBFX/BFI when possible 2020-12-30 16:52:34 +01:00
ptitSeb 1617439d37 Flags are only handled in packed form now, removed Unpacked array 2020-12-30 15:58:07 +01:00
ptitSeb 540459cb78 [DYNAREC] Now used r14 (so lr) instead of r12 for EIP/scratch register 2020-12-29 20:02:12 +01:00
ptitSeb 54b8522df6 [DYNAREC] Added SHLD32c emiter 2020-12-29 16:27:27 +01:00
ptitSeb bf65e606d3 [DYNAREC] Minor reordering of operation in DB E2 opcode 2020-12-29 16:27:01 +01:00
ptitSeb 5335a641df [DYNAREC] Fixed 66 99 CWD opcode 2020-12-29 16:26:16 +01:00
ptitSeb 323ece7417 [DYNAREC] Added amiter for SHRD32c 2020-12-29 13:37:57 +01:00
ptitSeb ca1fc0ffad [DYNAREC] Fix a potential memory corruption on exit 2020-12-29 11:18:30 +01:00
ptitSeb c0706e227e [DYNAREC] Removed a warning 2020-12-29 09:40:48 +01:00
ptitSeb 995e4a9b68 [DYNAREC] Switch POP/PUSH from STM/LDM to LDR/STR, so there is no alignment constraint anymore 2020-12-29 08:43:56 +01:00
ptitSeb 7f53379552 Don't printf Segfault handler message if custom handler is setuped on LOG_NONE level 2020-12-28 16:12:26 +01:00
ptitSeb 3e17299a34 Made 8F opcode consistant on segfault ([DYNAREC] too) 2020-12-28 16:11:06 +01:00
ptitSeb c63cdc9506 Added 66 CC opcode, and handling of CC by using raise(SIGTRAP) if SIGTRAP is handled ([DYNAREC] too) 2020-12-28 10:26:09 +01:00
ptitSeb 7965186817 Added TSC flag to CPUID cpu capabilities 2020-12-28 07:57:35 +01:00
ptitSeb f107612753 Force PROT_REAT when PROT_WRITE is set, as it's implicit on i386 2020-12-28 07:40:45 +01:00
ptitSeb 2295f7bb8b Added 66 0F D0 opcode ([DYNAREC] too) 2020-12-28 05:48:57 +01:00
ptitSeb cc0845a9d3 Added wrapped function glib_check_version 2020-12-27 15:22:31 +01:00
ptitSeb e9019461b7 [DYNAREC] Added 0F E1/E2/E3 opcodes 2020-12-27 15:22:07 +01:00
ptitSeb a19e3ed3dd [DYNAREC] Small optim on new memory protection tracker 2020-12-27 16:11:37 +01:00
ptitSeb 10ec424e96 More separation between POWERPC and ARM 2020-12-27 15:58:15 +01:00
ptitSeb b838c8a7d0 [DYNAREC] Fixed new memory protection tracking 2020-12-27 15:15:24 +01:00
ptitSeb 0331af0643 Track memory protection also on mmap/munmap/mprotect syscall 2020-12-27 12:38:24 +01:00
ptitSeb 24561fc37c [WINE] Removed wine_prereserve handling, it seems to be working better without it 2020-12-27 11:41:35 +01:00
ptitSeb d4ad5334b8 [DYNAREC] Some fixes to new memory protection tracking 2020-12-26 18:30:34 +01:00
ptitSeb 7fe3299282 Refined POWERPC support to less impact ARM 2020-12-26 18:27:21 +01:00
ptitSeb 23fef75ed5 [DYNAREC] Fixed FISTTP opcode 2020-12-26 09:55:10 +01:00
ptitSeb 62722b0618 Merge pull request #279 from eerykitty/master
Basic support for little-endian PowerPC and POWER9.
2020-12-25 09:29:10 +01:00
Joseph Allen e810dba2c9 Fixes semctl and a number of variadic functions. 2020-12-24 22:47:23 -06:00
Joseph Allen 7dfe545161 Basic support for little-endian PowerPC and POWER9. 2020-12-24 15:14:50 -06:00
ptitSeb a5f3966b44 Merge pull request #275 from SpacingBat3/master
Updated the PKGBUILDS
2020-12-24 09:38:53 +01:00
ptitSeb 886573ed8b Merge pull request #276 from RickAndTired/patch-1
Typo fix
2020-12-24 09:38:27 +01:00
RickAndTired 2758c1c955 Typo fix
Line 105 typo: kernle
2020-12-23 21:56:13 -08:00
ptitSeb 591bafe8c3 [DYNAREC] Try to improve the marking mecanism to include blocks that are shadowed by others 2020-12-23 09:21:50 +01:00
ptitSeb 211a8f42db Small cosmetic changes to wrapped libsdl2 2020-12-22 22:01:44 +01:00
ptitSeb fbc9029a8e [DYNAREC] Removed unused fiel in dynablocklist structure 2020-12-22 20:01:57 +01:00
ptitSeb ceb4b8b06d Removed a debug leftover 2020-12-22 15:13:29 +01:00
ptitSeb b88dda442f [DYNAREC] Improved block extender mecanism 2020-12-22 14:42:57 +01:00
ptitSeb 6e8163bded [DYNAREC] Moved fakeed function for helper to functions 2020-12-22 13:32:36 +01:00
ptitSeb 9b253abb53 More jpeg62 compress function wrapping (should help #271) 2020-12-22 11:31:09 +01:00
ptitSeb e5e51e3ea3 [DYNAREC] Fix a potential SIGBUS on 66 0F 12 opcode 2020-12-21 17:37:29 +01:00
ptitSeb 6a2d9d7663 Try to avoid a segfault on quit with libpulse 2020-12-21 17:36:51 +01:00
ptitSeb 0546b1e212 Try to fix wrapped Compress functions of libjpeg62 (for #271) 2020-12-21 11:17:03 +01:00
ptitSeb 320e6dae72 [DYNAREC] Reworked a bit the unaligned stack handling workaround to limit console spam 2020-12-21 10:47:16 +01:00
ptitSeb 96f944c804 More fixes to build new memory tracking whithout dynarec 2020-12-20 23:53:40 +01:00
ptitSeb fd0e2195f7 Fix build of memory tracking whithout dynarec 2020-12-20 23:49:31 +01:00
ptitSeb d2f130a834 Memory protection tracking is not only with Dynarec ON now 2020-12-20 23:38:32 +01:00
ptitSeb a3459712ce Fix 66 F0 0F B1 opcode 2020-12-20 23:37:57 +01:00
ptitSeb 8bf2e49164 Reorganised 8F POP Ed opcode to better handle Ed referencing ESP ([DYNAREC] too) 2020-12-20 15:35:57 +01:00
ptitSeb 0f5cd39a64 [DYNAREC] Refined the SIGBUS recovery to limit to push/pop/call/ret opcode (as FPU/SIMD regs are not saved/restored from Signal for now) 2020-12-20 14:13:24 +01:00
ptitSeb e0ed0076f2 [DYNAREC] When a SIGBUS occurs in a dynablock, invalidate the block at that address and try again with interpretor (fix MapleLegends Setup with its strangely aligned stack) 2020-12-20 12:09:51 +01:00
ptitSeb bfd4ad39af [DYNAREC] Fixed some issue with the memory protection mecanism 2020-12-20 11:06:31 +01:00
ptitSeb a8ff7d8769 [DYNAREC] Improved Memory Protection Tracking 2020-12-20 10:30:37 +01:00
ptitSeb 39c77beb1c Fixed Signal handling for PAGEFAULT with Write Error (helps Wine) 2020-12-20 10:11:59 +01:00
ptitSeb d576f7af39 Cleaner version of TEST Eb, Ib and TEST Ed, Id opcodes 2020-12-20 10:10:10 +01:00
ptitSeb 74c3f43f75 [DYNAREC] Better hanling of memory protection for elf memory 2020-12-20 10:09:12 +01:00
ptitSeb ecacace01d [DYNAREC] Added some handlng of protection for malloc'd memory 2020-12-20 10:08:21 +01:00
ptitSeb a3b0149a84 Added 66 1F opcode 2020-12-19 18:18:04 +01:00
ptitSeb 63111577ec Added 64 66 8B opcode 2020-12-19 17:45:55 +01:00
ptitSeb eb68520709 [DYNAREC] Some fixes to improved Memory protection tracker 2020-12-19 17:09:35 +01:00
ptitSeb a7bf2c6cc3 Fixed a potential SIGBUS on 66 0F 13 ocpode 2020-12-19 14:46:57 +01:00
ptitSeb 190788efd9 Added gss_wrap_iov function to wraped libgssapi_krb5 (still for wine) 2020-12-19 13:42:47 +01:00
ptitSeb 2592a6a342 Added gss_wrap function to wraped libgssapi_krb5 (still for wine) 2020-12-19 12:17:01 +01:00
ptitSeb 16ee4c348d [RK3399] Fixed a warning 2020-12-19 12:02:37 +01:00
ptitSeb 8389097cd3 [DYNAREC] Improved memory protection tractick 2020-12-19 11:44:02 +01:00
ptitSeb 79a885c15e Set theme jekyll-theme-hacker 2020-12-19 10:24:18 +01:00
ptitSeb eb7c683a6d Also added gss_verify_mic to libgssapi_krb5 2020-12-18 16:42:26 +01:00
ptitSeb 95b2b314f6 Wrapped libkrb5 and libgssapi_krb5 (minimum functions for wine) 2020-12-18 15:55:34 +01:00
ptitSeb 07eb0aa5cd [DYNAREC] Don't free dynarec elf memory durring elf unloading, it will be free later anyway 2020-12-18 13:56:09 +01:00
ptitSeb fdce28590a Added alternate way to handle some vaarg wrapped functions 2020-12-18 12:24:10 +01:00
ptitSeb 572613e377 Fixed wrapping of Compress structure on libjpeg62 (for #271) 2020-12-18 11:14:42 +01:00
ptitSeb 29e597b4ed Fixed another potential SIGBUS, in CMPXCHG this time 2020-12-17 21:39:23 +01:00
ptitSeb 981c464c36 Fixed a potential SIGBUS with XADD Gd, Ed opcode 2020-12-17 20:52:48 +01:00
ptitSeb d406c5717c Wrapping Compress functions callbacks for libjpeg.so.62 (shoudl help #271) 2020-12-17 10:44:37 +01:00
ptitSeb 92208efd24 Start of a new dev. cycle 2020-12-17 10:43:31 +01:00
SpacingBat3 edef6d7f99 Updated the PKGBUILDS
Improved old PKGBUILDs and added the PKGBUILD for the RK3399 targets.
2020-12-05 16:43:47 +01:00
343 changed files with 16736 additions and 7101 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
-102
View File
@@ -1,102 +0,0 @@
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
+98 -29
View File
@@ -5,22 +5,30 @@ option(PYRA "Set to ON if targeting an OpenPandora device" ${PYRA})
option(RPI2 "Set to ON if targeting an RaspberryPI2 device" ${RPI2})
option(RPI3 "Set to ON if targeting an RaspberryPI3 device" ${RPI3})
option(RPI4 "Set to ON if targeting an RaspberryPI4 device" ${RPI4})
option(RPI4ARM64 "Set to ON if targeting an RaspberryPI4 device with multiarch arm64 and armhf" ${RPI4ARM64})
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})
option(NOGETCLOCK "Set to ON to avoid using clock_gettime with CLOCK_MONOTONIC_COARSE for RDTSC opcode (use gltimeofday instead)" ${NOGETCLOCK})
option(NOGIT "Set to ON if not building from a git clone repo (like when building from a zip download from github)" ${NOGIT})
if(PANDORA OR PYRA OR RPI2 OR RPI3 OR RPI4 OR GAMESHELL OR ODROID OR RK3399)
if(PANDORA OR PYRA OR RPI2 OR RPI3 OR RPI4 OR GAMESHELL OR ODROID OR RK3399 OR RPI4ARM64)
set(LD80BITS OFF CACHE BOOL "")
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})
if(${CMAKE_VERSION} VERSION_LESS "3.12.2")
find_package(PythonInterp 3)
@@ -38,7 +46,7 @@ else()
set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE} CACHE INTERNAL "The Python3 executable" FORCE)
endif()
if(RK3399)
if(RK3399 OR RPI4ARM64)
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
#set(CMAKE_ASM_COMPILER arm-linux-gnueabihf-as) #will use gcc in fact
set(CMAKE_C_COMPILER_TARGET arm-linux-gnueabihf)
@@ -87,6 +95,12 @@ if(RPI4)
add_definitions(-marm -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
set(CMAKE_ASM_FLAGS "-marm -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
endif()
if(RPI4ARM64)
add_definitions(-DRPI)
add_definitions(-DRPI4ARM64)
add_definitions(-marm -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
set(CMAKE_ASM_FLAGS "-marm -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
endif()
if(ODROID)
add_definitions(-DODROID)
add_definitions(-mcpu=cortex-a9 -mfpu=neon-vfpv4 -mfloat-abi=hard -marm)
@@ -98,6 +112,10 @@ if(RK3399)
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a72+crypto")
endif()
if(POWER9)
add_definitions(-mcpu=power9 -mtune=power9)
endif()
if(NOGIT)
add_definitions(-DNOGIT)
endif()
@@ -132,6 +150,14 @@ if(ARM_DYNAREC)
enable_language(ASM)
endif()
if(POWERPCLE)
add_definitions(-DPOWERPCLE)
endif()
if(SYSV_VARARG)
add_definitions(-DSYSV_VARARG)
endif()
if(NOGETCLOCK)
add_definitions(-DNOGETCLOCK)
endif()
@@ -176,6 +202,7 @@ set(ELFLOADER_SRC
"${BOX86_ROOT}/src/main.c"
"${BOX86_ROOT}/src/box86context.c"
"${BOX86_ROOT}/src/build_info.c"
"${BOX86_ROOT}/src/custommem.c"
"${BOX86_ROOT}/src/tools/bridge.c"
"${BOX86_ROOT}/src/tools/pathcoll.c"
"${BOX86_ROOT}/src/tools/fileutils.c"
@@ -205,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"
@@ -214,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"
@@ -227,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"
@@ -247,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"
@@ -271,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"
@@ -283,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"
@@ -292,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"
@@ -316,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"
@@ -335,14 +369,28 @@ set(WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedxslt.c"
"${BOX86_ROOT}/src/wrapped/wrappedldapr.c"
"${BOX86_ROOT}/src/wrapped/wrappedlber.c"
"${BOX86_ROOT}/src/wrapped/wrappedlcms2.c"
"${BOX86_ROOT}/src/wrapped/wrappednsl.c"
"${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()
@@ -351,7 +399,10 @@ set(WRAPPER "${BOX86_ROOT}/src/wrapped/generated/wrapper.c" "${BOX86_ROOT}/src/w
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" "--" ${WRAPPEDS_HEAD}
COMMAND "${PYTHON_EXECUTABLE}" "${BOX86_ROOT}/rebuild_wrappers.py"
"${BOX86_ROOT}"
"PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "POWERPCLE" "ANDROID" "--"
${WRAPPEDS_HEAD}
MAIN_DEPENDENCY "${BOX86_ROOT}/rebuild_wrappers.py"
DEPENDS ${WRAPPEDS} ${WRAPPEDS_HEAD}
BYPRODUCTS ${WRAPPER}
@@ -378,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"
)
@@ -460,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)
@@ -478,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()
@@ -519,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)
-112
View File
@@ -1,112 +0,0 @@
# box86
![Official logo](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).
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.
Most x86 Games need OpenGL, so on ARM platforms a solution like [gl4es](https://github.com/ptitSeb/gl4es) is usually necessary.
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)
If you are serious about developing Box86, you should install ccache and activate its support in the cmake project (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
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.
[![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).
Compatibility list is there: https://github.com/ptitSeb/box86-compatibility-list/issues
<img src="Box86Icon.png" width="96" height="96">
Logo and Icon made by @grayduck, thanks!
Note that this project is not to be mystaken with [86box](https://github.com/86Box/86Box), a nice "Full system" emulator specialized in early (to fairly recent) PC hardware.
----
Discord
----
If you want to discuss about box86 on Discord, there is a frendly server there: [PI Lab Discord](https://discord.gg/Fh8sjmu)
----
Compiling
----
Compilation instructions can be found [here](COMPILE.md)
----
Usage
----
There are a few environment variables avaiable to control the behaviour of Box86.
See [here](USAGE.md) for all variables and what they do.
Note that now the Dynarec of Box86 uses a mecanism with Memory Protection and a SegFault signal handler to handle JIT code. That means if you want to use gdb to debug running a program that use JIT'd code (like mono/Unity3D), you will have many "normal" segfaults triggering. I suggest you use something like `handle SIGSEGV nostop` in gdb to not stop at each segfault, and maybe put a breakpoint inside `my_memprotectionhandler` in `signals.c` if you want to trap SegFaults.
----
Version history
----
The change log is available [here](CHANGELOG.md)
----
A note about 64-bit platforms
----
Because Box86 works by directly translating function calls from x86 to host system, the host system (the one Box86 is running on) needs to have 32-bit libraries. Box86 doesn't include any 32-bit <-> 64-bit translation. So basically, to run Box86 on, for example, an ARM64 platform, you will need to build Box86 for ARM 32-bit, and also need to have a chroot with 32-bit libraries.
Also note that, even if, on day, there is a Box86_64, this one will only be able to run x86_64 binaries on 64-bit platforms. You will still need Box86 (and see 32-bit chroot) to run x86 binaries (in fact, the same is the case on actual x86_64 Linux).
----
A note about Unity game emulation
----
Running Unity games is a hit or miss for now. Unity uses Mono (which uses signals that are not well emulated enough), and a runtime embedded in the main binary. A solution would be to use a native version of the libmono library used by Unity (it can be found here: https://github.com/Unity-Technologies/mono and needs to be built from source). But the wrapping of this lib is tricky, and not done for now, so the only solution is to emulate everything. The tricky part is to emulate the "JIT" code emitted by Mono, however with he new "protected memory" mechanism implemented it is running with correct performance now.
You should also note that some Unity3D games require OpenGL 3+ which can be tricky to provide on ARM SBC (single-board computers) for now.
TL;DR: Not all Unity games work and can require a high OpenGL profile, but the speed, for the ones running, should be correct now.
----
A note about Steam
----
Linux Steam can run now with box86. But it's still a bit unstable., and not everything works. First is steam crashes after the Sign in, you may need to add libappindicator. On debian it's `sudo apt install libappindicator1`.
Once open, Steam will only work on "Small mode" and in "Big Picture", not in the regular "Browser mode". So go in the "View" menu and witch to Small view (or Compact view?), else the list will stay empty (this is because some steam component used in the browser view are only 64bits now).
Final word, to avoid the "libc.so.6 is absent" message, you can use `STEAMOS=1` and `STEAM_RUNTIME=1` export.
(Steam for Windows install fine but doesn't work yet)
Some steam games (most of Source engine one, like "Portal" or "Half-Life 2") use libtcmalloc. Box86 will detect it's use and will try to LD_PRELOAD it, for better compatibility. While it should work without, it is better to add it to your system if you intend to play those game (something like `sudo apt install libtcmalloc-minimal4` on debian familly)
----
A note about Wine
----
Wine is now partly supported. Wine integreted program all runs, annd some windows program and games now run fine. Don't forget most Windows games use Direct3D, that 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.
A not if you plan to use box86 with wine on Raspberry PI 3 or earlier: those model use a default OS that have a kernle with a 2/2 Split (meaning 2G of space for user program, and 2G of space for Kernel). This is not compatible with wine, that need to access memory > 2Gb address. So you'll need to reconfigure your kernel for a 3G/1G split. Use your favorite search engine to find tutos on how to do that.
----
Final words
----
(If you use Box86 in your project, please don't forget to mention Box86)
-157
View File
@@ -1,157 +0,0 @@
Usage
----
There are many environment variable to control Box86 behaviour.
#### BOX86_LOG
Controls the Verbose level of the log
* 0
* NONE : No message (except some fatal error)
* 1
* INFO : Current default. Show some log
* 2
* DEBUG : Verbose a lot of stuffs (like relocations or function called)
* 3
* DUMP : All DEBUG plus DUMP of all ELF Info
#### BOX86_NOBANNER
Control Box86 printing it's version and build
* 0 : Enabled the printing
* 1 : Diable the printing
#### BOX86_LD_LIBRARY_PATH
Controls the folder scanned 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
Controls the folder scanned 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 actual PID of box86 instance
#### BOX86_TRACE
Only on build with trace enabled. Trace allow the logging of all instruction execute, along with register dump
* 0 : No trace
* 1 : Trace enabled. The trace start after the init of all depending libs 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 init of Libs and main 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 x87 registers
* 1 : Dump the XMM registers
#### BOX86_LOAD_ADDR
Try to load at 0xXXXXXX main binaray (if binary is a PIE)
* 0xXXXXXXXX the load address (only active on PIE programs)
#### BOX86_NOSIGSEGV
To disable handling of SigSEGV (to ease debugging mainly)
* 0 : default, let x86 program set sighandler for SEGV
* 1 : disable handling of SigSEGV
#### BOX86_NOSIGILL
To 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: to try convert 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
To 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
To Force libX11 GLX extension to be present
* 0 : Disable the force.
* 1 : default, GLX will always be present when using XQueryExtension
#### BOX86_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
* 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 use old version of some lib, 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 lib is missing
* 0 : default, stop if a lib cannot be loaded
* 1 : continue even if a needed lib cannot be loaded. Unadvised, this will, in most cases, crash later on.
#### BOX86_NOPULSE
Disable the load of pulseaudio libs
* 0 : default, load pulseaudio libs if present
* 1 : disable the load of pulse audio libs (libpulse and libpulse-simple), both native and x86 version
#### BOX86_NOGTK
Disable the load of wrapped gtk libs
* 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_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 don'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.
+1
View File
@@ -0,0 +1 @@
theme: jekyll-theme-hacker
+14 -8
View File
@@ -1,5 +1,5 @@
# Maintainer: SpacingBat3 <youremail@domain.com>
# Contributor: Sebastien Chevalier
# Maintainer: SpacingBat3 <[email protected].com>
# Contributor: Sebastien Chevalier <[email protected]>
pkgname=box86-arm-git
pkgver=r2798.0edc0374
pkgrel=1
@@ -9,18 +9,18 @@ url="https://github.com/ptitSeb/box86"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}")
conflicts=("${pkgname%-git}")
provides=("${pkgname%-git}" "${_pkgname%-arm-git}-git" "${_pkgname%-arm-git}")
conflicts=("${pkgname%-git}" "${_pkgname%-arm-git}-git" "${_pkgname%-arm-git}")
source=('git+https://github.com/ptitSeb/box86')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-git}"
cd "$srcdir/${pkgname%-arm-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-git}"
cd "${srcdir}/${pkgname%-arm-git}"
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo
@@ -28,11 +28,17 @@ prepare() {
}
build() {
cd "$srcdir/${pkgname%-git}/build"
cd "$srcdir/${pkgname%-arm-git}/build"
make -j$(nproc)
}
package() {
cd "$srcdir/${pkgname%-git}/build"
cd "$srcdir/${pkgname%-arm-git}/build"
make DESTDIR="${pkgdir}/" install
# /usr/local/bin isn't in PATH by the default,
# we should move it to /usr/bin
cd ${pkgdir}
mv usr/local/bin/ usr/bin/
# cleanup when dir is empty
rmdir usr/local || exit 0
}
+14 -8
View File
@@ -1,5 +1,5 @@
# Maintainer: SpacingBat3 <youremail@domain.com>
# Contributor: Sebastien Chevalier
# Maintainer: SpacingBat3 <[email protected].com>
# Contributor: Sebastien Chevalier <[email protected]>
pkgname=box86-gameshell-git
pkgver=r2798.0edc0374
pkgrel=1
@@ -9,18 +9,18 @@ url="https://github.com/ptitSeb/box86"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}")
conflicts=("${pkgname%-git}")
provides=("${pkgname%-git}" "${pkgname%-gameshell-git}-git" "${pkgname%-gameshell-git}")
conflicts=("${pkgname%-git}" "${pkgname%-gameshell-git}-git" "${pkgname%-gameshell-git}")
source=('git+https://github.com/ptitSeb/box86')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-git}"
cd "$srcdir/${pkgname%-gameshell-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-git}"
cd "${srcdir}/${pkgname%-gameshell-git}"
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DGAMESHELL=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
@@ -28,11 +28,17 @@ prepare() {
}
build() {
cd "$srcdir/${pkgname%-git}/build"
cd "$srcdir/${pkgname%-gameshell-git}/build"
make -j$(nproc)
}
package() {
cd "$srcdir/${pkgname%-git}/build"
cd "$srcdir/${pkgname%-gameshell-git}/build"
make DESTDIR="${pkgdir}/" install
# /usr/local/bin isn't in PATH by the default,
# we should move it to /usr/bin
cd ${pkgdir}
mv usr/local/bin/ usr/bin/
# cleanup when dir is empty
rmdir usr/local || exit 0
}
+14 -8
View File
@@ -1,5 +1,5 @@
# Maintainer: SpacingBat3 <youremail@domain.com>
# Contributor: Sebastien Chevalier
# Maintainer: SpacingBat3 <[email protected].com>
# Contributor: Sebastien Chevalier <[email protected]>
pkgname=box86-odroid-git
pkgver=r2798.0edc0374
pkgrel=1
@@ -9,18 +9,18 @@ url="https://github.com/ptitSeb/box86"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}")
conflicts=("${pkgname%-git}")
provides=("${pkgname%-git}" "${_pkgname%-odroid-git}-git" "${_pkgname%-odroid-git}")
conflicts=("${pkgname%-git}" "${_pkgname%-odroid-git}-git" "${_pkgname%-odroid-git}")
source=('git+https://github.com/ptitSeb/box86')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-git}"
cd "$srcdir/${pkgname%-odroid-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-git}"
cd "${srcdir}/${pkgname%-odroid-git}"
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DODROID=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
@@ -28,11 +28,17 @@ prepare() {
}
build() {
cd "$srcdir/${pkgname%-git}/build"
cd "$srcdir/${pkgname%-odroid-git}/build"
make -j$(nproc)
}
package() {
cd "$srcdir/${pkgname%-git}/build"
cd "$srcdir/${pkgname%-odroid-git}/build"
make DESTDIR="${pkgdir}/" install
# /usr/local/bin isn't in PATH by the default,
# we should move it to /usr/bin
cd ${pkgdir}
mv usr/local/bin/ usr/bin/
# cleanup when dir is empty
rmdir usr/local || exit 0
}
+14 -7
View File
@@ -1,6 +1,7 @@
# Maintainer: SpacingBat3 <youremail@domain.com>
# Contributor: Sebastien Chevalier
# Maintainer: SpacingBat3 <[email protected].com>
# Contributor: Sebastien Chevalier <[email protected]>
pkgname=box86-pandora-git
_pkgname=box86-git
pkgver=r2798.0edc0374
pkgrel=1
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
@@ -9,18 +10,18 @@ url="https://github.com/ptitSeb/box86"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}")
conflicts=("${pkgname%-git}")
provides=("${pkgname%-git}" "${pkgname%-pandora-git}"-git "${pkgname%-pandora-git}")
conflicts=("${pkgname%-git}" "${pkgname%-pandora-git}"-git "${pkgname%-pandora-git}")
source=('git+https://github.com/ptitSeb/box86')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-git}"
cd "$srcdir/${pkgname%-pandora-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-git}"
cd "${srcdir}/${pkgname%-pandora-git}"
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DPANDORA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
@@ -28,11 +29,17 @@ prepare() {
}
build() {
cd "$srcdir/${pkgname%-git}/build"
cd "$srcdir/${pkgname%-pandora-git}/build"
make -j$(nproc)
}
package() {
cd "$srcdir/${pkgname%-git}/build"
make DESTDIR="${pkgdir}/" install
# /usr/local/bin isn't in PATH by the default,
# we should move it to /usr/bin
cd ${pkgdir}
mv usr/local/bin/ usr/bin/
# cleanup when dir is empty
rmdir usr/local || exit 0
}
+15 -8
View File
@@ -1,6 +1,7 @@
# Maintainer: SpacingBat3 <youremail@domain.com>
# Contributor: Sebastien Chevalier
# Maintainer: SpacingBat3 <[email protected].com>
# Contributor: Sebastien Chevalier <[email protected]>
pkgname=box86-pyra-git
_pkgname=box86-git
pkgver=r2798.0edc0374
pkgrel=1
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
@@ -9,18 +10,18 @@ url="https://github.com/ptitSeb/box86"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}")
conflicts=("${pkgname%-git}")
provides=("${pkgname%-git}" "${pkgname%-pyra-git}-git" "${pkgname%-pyra-git}")
conflicts=("${pkgname%-git}" "${pkgname%-pyra-git}-git" "${pkgname%-pyra-git}")
source=('git+https://github.com/ptitSeb/box86')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-git}"
cd "$srcdir/${pkgname%-pyra-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-git}"
cd "${srcdir}/${pkgname%-pyra-git}"
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DPYRA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
@@ -28,11 +29,17 @@ prepare() {
}
build() {
cd "$srcdir/${pkgname%-git}/build"
cd "$srcdir/${pkgname%-pyra-git}/build"
make -j$(nproc)
}
package() {
cd "$srcdir/${pkgname%-git}/build"
cd "$srcdir/${pkgname%-pyra-git}/build"
make DESTDIR="${pkgdir}/" install
# /usr/local/bin isn't in PATH by the default,
# we should move it to /usr/bin
cd ${pkgdir}
mv usr/local/bin/ usr/bin/
# cleanup when dir is empty
rmdir usr/local || exit 0
}
+21 -13
View File
@@ -1,6 +1,7 @@
# Maintainer: SpacingBat3 <youremail@domain.com>
# Contributor: Sebastien Chevalier
# Maintainer: SpacingBat3 <[email protected].com>
# Contributor: Sebastien Chevalier <[email protected]>
pkgname=box86-rpi-git
_pkgname=box86-git
pkgver=r2798.0edc0374
pkgrel=1
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
@@ -9,29 +10,30 @@ url="https://github.com/ptitSeb/box86"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}")
conflicts=("${pkgname%-git}")
provides=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%--rpi-git}")
conflicts=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%--rpi-git}")
source=('git+https://github.com/ptitSeb/box86')
md5sums=('SKIP')
_pimodel=`tr -d '\0' < /sys/firmware/devicetree/base/model`
pkgver() {
cd "$srcdir/${pkgname%-git}"
cd "$srcdir/${pkgname%-rpi-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-git}"
cd "${srcdir}/${pkgname%-rpi-git}"
# Check for Pi version number
if [[ ${_pimodel} ~= "Raspberry Pi 4" ]]; then
if [[ ${_pimodel} =~ "Raspberry Pi 4" ]]; then
_piversion=4
elif [[ ${_pimodel} ~= "Raspberry Pi 3" ]]; then
elif [[ ${_pimodel} =~ "Raspberry Pi 3" ]]; then
_piversion=3
elif [[ ${_pimodel} ~= "Raspberry Pi 2" ]]; then
elif [[ ${_pimodel} =~ "Raspberry Pi 2" ]]; then
_piversion=2
else
# Your RPI is not supported or this device is not a pi, cancel build then
echo -e "\033[01m\033[01;31m==> ERROR:\033[00;01m Your device is not supported! This script is for RPi model 4/3/2 (1/0 not supported).\033[00m"
# This RPI is not supported or this device is not a pi.
# We should cancel then the build.
echo -e "\033[01m\033[01;31m==> ERROR:\033[00;01m Your device is not supported! This script is for RPi model 4/3/2 (1/0 isn't supported yet).\033[00m"
exit 1
fi
echo -e "\033[01m\033[01;34m==> INFO:\033[00;01m Your detected Pi verion number is: \033[01;31m${_piversion}\033[01m.\033[00m"
@@ -42,11 +44,17 @@ prepare() {
}
build() {
cd "$srcdir/${pkgname%-git}/build"
cd "$srcdir/${pkgname%-rpi-git}/build"
make -j$(nproc)
}
package() {
cd "$srcdir/${pkgname%-git}/build"
cd "$srcdir/${pkgname%-rpi-git}/build"
make DESTDIR="${pkgdir}/" install
# /usr/local/bin isn't in PATH by the default,
# we should move it to /usr/bin
cd ${pkgdir}
mv usr/local/bin/ usr/bin/
# cleanup when dir is empty
rmdir usr/local || exit 0
}
+39
View File
@@ -0,0 +1,39 @@
# Maintainer: SpacingBat3 <[email protected]>
# Contributor: Sebastien Chevalier <[email protected]>
pkgname=box86-rk3399-git
_pkgname=box86-git
pkgver=r2798.0edc0374
pkgrel=1
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
arch=('armv7h')
url="https://github.com/ptitSeb/box86"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
conflicts=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
source=('git+https://github.com/ptitSeb/box86')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-rk3399-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-rk3399-git}"
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
fi
}
build() {
cd "$srcdir/${pkgname%-rk3399-git}/build"
make -j$(nproc)
}
package() {
cd "$srcdir/${pkgname%-rk3399-git}/build"
make DESTDIR="${pkgdir}/" install
}
+15 -8
View File
@@ -1,6 +1,7 @@
# Maintainer: SpacingBat3 <youremail@domain.com>
# Contributor: Sebastien Chevalier
# Maintainer: SpacingBat3 <[email protected].com>
# Contributor: Sebastien Chevalier <[email protected]>
pkgname=box86-x86-git
_pkgname=box86-git
pkgver=r2798.0edc0374
pkgrel=1
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
@@ -8,18 +9,18 @@ arch=('i386')
url="https://github.com/ptitSeb/box86"
license=('MIT')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}")
conflicts=("${pkgname%-git}")
provides=("${pkgname%-x86-git}")
conflicts=("${pkgname%-x86-git}")
source=('git+https://github.com/ptitSeb/box86')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-git}"
cd "$srcdir/${pkgname%-x86-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-git}"
cd "${srcdir}/${pkgname%-x86-git}"
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
@@ -27,11 +28,17 @@ prepare() {
}
build() {
cd "$srcdir/${pkgname%-git}/build"
cd "$srcdir/${pkgname%-x86-git}/build"
make -j$(nproc)
}
package() {
cd "$srcdir/${pkgname%-git}/build"
cd "$srcdir/${pkgname%-x86-git}/build"
make DESTDIR="${pkgdir}/" install
# /usr/local/bin isn't in PATH by the default,
# we should move it to /usr/bin
cd ${pkgdir}
mv usr/local/bin/ usr/bin/
# cleanup when dir is empty
rmdir usr/local || exit 0
}
+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.
+11 -11
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,25 +25,25 @@ 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
`mkdir build; cd build; cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j4`
As most RK3399 device run AARCH64 OS, you'll need an `armhf` multiarch env, and an armhf gcc: use `sudo apt install gcc-arm-linux-gnueabihf` to install it.
As most RK3399 device run AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
#### for Other ARM Linux
#### 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
@@ -57,19 +57,19 @@ Add `-DUSE_CCACHE=1` if you have ccache (it's better if you plan to touch the so
*have some debug info*
The `-DCMAKE_BUILD_TYPE=RelWithDebInfo` argument make a build that is both optimized for speed, and have debug information embedded. That way, if you have a crash or try to analyse performances, you'll have some symbols.
The `-DCMAKE_BUILD_TYPE=RelWithDebInfo` argument makes a build that is both optimized for speed, and has debug information embedded. That way, if you have a crash or try to analyse performance, you'll have some symbols.
*to have a Trace Enabled build*
To have a trace enabled build (warning, it will be slower), add `-DHAVE_TRACE=1` but you will need, at runtime, to have the [Zydis library](https://github.com/zyantific/zydis) library in your `LD_LIBRARY_PATH` or in the system lib folders.
To have a trace enabled build ( ***it will be slower***), add `-DHAVE_TRACE=1` but you will need, at runtime, to have the [Zydis library](https://github.com/zyantific/zydis) library in your `LD_LIBRARY_PATH` or in the system library folders.
*to have ARM Dynarec*
The Dynarec is only avaiable on ARM Cpu. Notes also that VFPv3 and NEON are required for the Dynarec. Activate it by using `-DARM_DYNAREC=1`. Also, be sure to use `-marm` in compilation flags (because many compileur use Thumb as default, and the dynarec will not work in this mode).
The Dynarec is only available on the ARM architecture(Right now, anyways.). Notes also that VFPv3 and NEON are required for the Dynarec. Activate it by using `-DARM_DYNAREC=1`. Also, be sure to use `-marm` in compilation flags (because many compileur use Thumb as default, and the dynarec will not work in this mode).
*not building from a git clone*
If you are not building from a git clone (for example downloading a release sources Zipped from github), you need to activate `-DNOGIT=1` from cmake to be able to build (normal process include git sha1 of HEAD in the version that box86 print).
If you are not building from a git clone (for example, downloading a release source zipped from github), you need to activate `-DNOGIT=1` from cmake to be able to build (normal process include git sha1 of HEAD in the version that box86 print).
----
+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
Executable
+114
View File
@@ -0,0 +1,114 @@
# box86
![Official logo](img/Box86Logo.png "Official Logo")
Linux Userspace x86 Emulator with a twist
----
Compiling/Installation
----
> Compilation instructions can be found [here](COMPILE.md)
> Instructions for installing Wine for Box86 can be found [here](X86WINE.md)
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).
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 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 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/emu/x86primop.c) for copyright details
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 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="img/Box86Icon.png" width="96" height="96">
Logo and Icon made by @grayduck, thanks!
Note that this project is not to be mistaken with [86box](https://github.com/86Box/86Box), a nice "Full system" emulator specialized in early (to fairly recent) PC hardware.
----
Discord
----
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.
See [here](USAGE.md) for all environment variables and what they do.
Note: Box86's Dynarec uses a mechanism with Memory Protection and a SegFault signal handler to handle JIT code. In simpler terms, if you want to use GDB to debug a running program that use JIT'd code (like mono/Unity3D), you will still have many "normal" segfaults triggering. It is suggested to use something like `handle SIGSEGV nostop` in GDB to not stop at each segfault, and maybe put a breakpoint inside `my_memprotectionhandler` in `signals.c` if you want to trap SegFaults.
----
Version history
----
The change log is available [here](CHANGELOG.md)
----
Notes about 64-bit platforms
----
Because Box86 works by directly translating function calls from x86 to host system, the host system (the one Box86 is running on) needs to have 32-bit libraries. Box86 doesn't include any 32-bit <-> 64-bit translation. So basically, to run Box86 on, for example, an ARM64 platform, you will need to build Box86 for ARM 32-bit, and also need to have a chroot with 32-bit libraries.
Also note that, even if, on day, there is a Box86_64, this one will only be able to run x86_64 binaries on 64-bit platforms. You will still need Box86 (and a 32-bit chroot) to run x86 binaries (in fact, the same is the case on actual x86_64 Linux).
----
A note about Unity game emulation
----
Running Unity games is a hit or miss for now. Unity uses Mono (which uses signals that are not well emulated enough), and a runtime embedded in the main binary. A solution would be to use a native version of the libmono library used by Unity (it can be found here: https://github.com/Unity-Technologies/mono and needs to be built from source). But the wrapping of this lib is tricky, and not done for now, so the only solution is to emulate everything. The tricky part is to emulate the "JIT" code emitted by Mono, however with the new "protected memory" mechanism implemented it should be running with correct performance now.
You should also note that some Unity3D games require OpenGL 3+ which can be tricky to provide on ARM SBC (single-board computers) for now.
TL;DR: Not all Unity games work and can require a high OpenGL profile, but the speed, for the ones running, should be correct now.
----
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. 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.
----
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.
----
Final words
----
(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))
+311 -77
View File
@@ -3,7 +3,60 @@
import os
import sys
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']
"""
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:
ret = [len(s), values.index(s[0])]
@@ -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_
@@ -312,58 +510,52 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
// 2 = struct of 2 uint
// P = Vulkan struture pointer
// G = a single GValue pointer
// 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
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
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")
@@ -385,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
@@ -393,12 +585,14 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
"(void*)(R_ESP + {p}), ", # V
"of_convert(*(int32_t*)(R_ESP + {p})), ", # O
"io_convert(*(void**)(R_ESP + {p})), ", # S
"(_2uint_struct_t){{*(uintptr_t*)(R_ESP + {p}),*(uintptr_t*)(R_ESP + {p} + 4)}}, ", #2
"(_2uint_struct_t){{*(uintptr_t*)(R_ESP + {p}),*(uintptr_t*)(R_ESP + {p} + 4)}}, ", # 2
"arg{p}, ", # P
"&arg{p}, ", # G
"*(void**)(R_ESP + {p}), ", # N
"*(void**)(R_ESP + {p}),*(void**)(R_ESP + {p} + 4), ", # M
]
# E e v c w i I C W u U f d D K l L p V O S 2 P G
deltas = [0, 0, 4, 4, 4, 4, 8, 4, 4, 4, 8, 4, 8, 12, 12, 4, 4, 4, 0, 4, 4, 8, 4, 4]
# 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
deltas = [0, 0, 4, 4, 4, 4, 8, 4, 4, 4, 8, 4, 8, 12, 12, 4, 4, 4, 0, 4, 4, 8, 4, 4, 0, 0]
vals = [
"\n#error Invalid return type: emulator\n", # E
"\n#error Invalid return type: &emulator\n", # e
@@ -424,6 +618,8 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
"\n#error Invalid return type: _2uint_struct\n", # 2
"\n#error Invalid return type: Vulkan Struct\n", # P
"\n#error Invalid return type: GValue Pointer\n", # G
"\n#error Invalid return type: ... with 1 arg\n", # N
"\n#error Invalid return type: ... with 2 args\n", # M
]
# Asserts
if len(values) != len(arg):
@@ -487,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 )
+93 -404
View File
@@ -19,334 +19,15 @@
#include "threads.h"
#include "x86trace.h"
#include "signals.h"
#ifdef DYNAREC
#include <sys/mman.h>
#include "custommem.h"
#ifdef DYNAREC
#include "dynablock.h"
#include "khash.h"
#define MMAPSIZE (256*1024) // allocate 256kb sized blocks
// init inside dynablocks.c
KHASH_MAP_INIT_INT(dynablocks, dynablock_t*)
typedef union mark_s {
struct {
unsigned int fill:1;
unsigned int size:31;
};
uint32_t x32;
} mark_t;
typedef struct blockmark_s {
mark_t prev;
mark_t next;
} blockmark_t;
typedef struct mmaplist_s {
void* block;
int maxfree;
kh_dynablocks_t* dblist;
} mmaplist_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
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;
return m;
}
m = (blockmark_t*)((uintptr_t)m + m->next.size);
}
return NULL;
}
static int getMaxFreeBlock(void* block)
{
// get start of block
blockmark_t *m = (blockmark_t*)((uintptr_t)block+MMAPSIZE-sizeof(blockmark_t)); // styart 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...
}
m = (blockmark_t*)((uintptr_t)m - m->prev.size);
}
return maxsize;
}
static void* allocBlock(void* block, void *sub, int size)
{
blockmark_t *s = (blockmark_t*)sub;
blockmark_t *n = (blockmark_t*)((uintptr_t)s + s->next.size);
s->next.fill = 1;
s->next.size = size+sizeof(blockmark_t);
blockmark_t *m = (blockmark_t*)((uintptr_t)s + s->next.size); // this is new n
m->prev.fill = 1;
m->prev.size = s->next.size;
if(n!=m) {
// new mark
m->prev.fill = 1;
m->prev.size = s->next.size;
m->next.fill = 0;
m->next.size = (uintptr_t)n - (uintptr_t)m;
n->prev.fill = 0;
n->prev.size = m->next.size;
}
return (void*)((uintptr_t)sub + sizeof(blockmark_t));
}
static void freeBlock(void *block, void* sub, int size)
{
blockmark_t *m = (blockmark_t*)block;
blockmark_t *s = (blockmark_t*)sub;
blockmark_t *n = (blockmark_t*)((uintptr_t)s + s->next.size);
if(block!=sub)
m = (blockmark_t*)((uintptr_t)s - s->prev.size);
s->next.fill = 0;
n->prev.fill = 0;
// check if merge with previous
if (s->prev.x32 && !s->prev.fill) {
// remove s...
m->next.size += s->next.size;
n->prev.size = m->next.size;
s = m;
}
// check if merge with next
if(n->next.x32 && !n->next.fill) {
blockmark_t *n2 = (blockmark_t*)((uintptr_t)n + n->next.size);
//remove n
s->next.size += n->next.size;
n2->prev.size = s->next.size;
}
}
uintptr_t FindFreeDynarecMap(dynablock_t* db, int size)
{
// look for free space
void* sub = NULL;
for(int i=0; i<my_context->mmapsize; ++i) {
if(my_context->mmaplist[i].maxfree>=size) {
int rsize = 0;
sub = getFirstBlock(my_context->mmaplist[i].block, size, &rsize);
if(sub) {
uintptr_t ret = (uintptr_t)allocBlock(my_context->mmaplist[i].block, sub, size);
if(rsize==my_context->mmaplist[i].maxfree)
my_context->mmaplist[i].maxfree = getMaxFreeBlock(my_context->mmaplist[i].block);
kh_dynablocks_t *blocks = my_context->mmaplist[i].dblist;
if(!blocks) {
blocks = my_context->mmaplist[i].dblist = kh_init(dynablocks);
kh_resize(dynablocks, blocks, 64);
}
khint_t k;
int r;
k = kh_put(dynablocks, blocks, (uintptr_t)db, &r);
kh_value(blocks, k) = db;
return ret;
}
}
}
return 0;
}
uintptr_t AddNewDynarecMap(dynablock_t* db, int size)
{
int i = my_context->mmapsize++; // yeah, useful post incrementation
dynarec_log(LOG_DEBUG, "Ask for DynaRec Block Alloc #%d\n", my_context->mmapsize);
my_context->mmaplist = (mmaplist_t*)realloc(my_context->mmaplist, my_context->mmapsize*sizeof(mmaplist_t));
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);
--my_context->mmapsize;
return 0;
}
mprotect(p, MMAPSIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
my_context->mmaplist[i].block = p;
// setup marks
blockmark_t* m = (blockmark_t*)p;
m->prev.x32 = 0;
m->next.fill = 0;
m->next.size = MMAPSIZE-sizeof(blockmark_t);
m = (blockmark_t*)(p+MMAPSIZE-sizeof(blockmark_t));
m->next.x32 = 0;
m->prev.fill = 0;
m->prev.size = MMAPSIZE-sizeof(blockmark_t);
// alloc 1st block
uintptr_t sub = (uintptr_t)allocBlock(my_context->mmaplist[i].block, p, size);
my_context->mmaplist[i].maxfree = getMaxFreeBlock(my_context->mmaplist[i].block);
kh_dynablocks_t *blocks = my_context->mmaplist[i].dblist = kh_init(dynablocks);
kh_resize(dynablocks, blocks, 64);
khint_t k;
int ret;
k = kh_put(dynablocks, blocks, (uintptr_t)db, &ret);
kh_value(blocks, k) = db;
return sub;
}
void ActuallyFreeDynarecMap(dynablock_t* db, uintptr_t addr, int size)
{
if(!addr || !size)
return;
for(int i=0; i<my_context->mmapsize; ++i) {
if ((addr>(uintptr_t)my_context->mmaplist[i].block)
&& (addr<((uintptr_t)my_context->mmaplist[i].block+MMAPSIZE))) {
void* sub = (void*)(addr-sizeof(blockmark_t));
freeBlock(my_context->mmaplist[i].block, sub, size);
my_context->mmaplist[i].maxfree = getMaxFreeBlock(my_context->mmaplist[i].block);
kh_dynablocks_t *blocks = my_context->mmaplist[i].dblist;
if(blocks) {
khint_t k = kh_get(dynablocks, blocks, (uintptr_t)db);
if(k!=kh_end(blocks))
kh_del(dynablocks, blocks, k);
}
return;
}
}
if(my_context->mmapsize)
dynarec_log(LOG_NONE, "Warning, block %p (size %d) not found in mmaplist for Free\n", (void*)addr, size);
}
dynablock_t* FindDynablockFromNativeAddress(void* addr)
{
// look in actual list
for(int i=0; i<my_context->mmapsize; ++i) {
if ((uintptr_t)addr>=(uintptr_t)my_context->mmaplist[i].block
&& ((uintptr_t)addr<(uintptr_t)my_context->mmaplist[i].block+MMAPSIZE))
return FindDynablockDynablocklist(addr, my_context->mmaplist[i].dblist);
}
// look in oversized
return FindDynablockDynablocklist(addr, my_context->dblist_oversized);
}
uintptr_t AllocDynarecMap(dynablock_t* db, int size)
{
if(!size)
return 0;
if(size>MMAPSIZE-2*sizeof(blockmark_t)) {
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);
kh_dynablocks_t *blocks = my_context->dblist_oversized;
if(!blocks) {
blocks = my_context->dblist_oversized = kh_init(dynablocks);
kh_resize(dynablocks, blocks, 64);
}
khint_t k;
int ret;
k = kh_put(dynablocks, blocks, (uintptr_t)db, &ret);
kh_value(blocks, k) = db;
return (uintptr_t)p;
}
if(pthread_mutex_trylock(&my_context->mutex_mmap)) {
sched_yield(); // give it a chance
if(pthread_mutex_trylock(&my_context->mutex_mmap))
return 0; // cannot lock, baillout
}
uintptr_t ret = FindFreeDynarecMap(db, size);
if(!ret)
ret = AddNewDynarecMap(db, size);
pthread_mutex_unlock(&my_context->mutex_mmap);
return ret;
}
void FreeDynarecMap(dynablock_t* db, uintptr_t addr, uint32_t size)
{
if(size>MMAPSIZE) {
munmap((void*)addr, size);
kh_dynablocks_t *blocks = my_context->dblist_oversized;
if(blocks) {
khint_t k = kh_get(dynablocks, blocks, (uintptr_t)db);
if(k!=kh_end(blocks))
kh_del(dynablocks, blocks, k);
}
return;
}
pthread_mutex_lock(&my_context->mutex_mmap);
ActuallyFreeDynarecMap(db, addr, size);
pthread_mutex_unlock(&my_context->mutex_mmap);
}
// each dynmap is 64k of size
void addDBFromAddressRange(box86context_t* context, uintptr_t addr, uintptr_t size, int nolinker)
{
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(!context->dynmap[i]) {
context->dynmap[i] = NewDynablockList(i<<DYNAMAP_SHIFT, i<<DYNAMAP_SHIFT, 1<<DYNAMAP_SHIFT, nolinker, 0);
}
}
}
void cleanDBFromAddressRange(box86context_t* context, 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 end = ((addr+size-1)>>DYNAMAP_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
dynablocklist_t* dblist = context->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(startaddr==startdb && endaddr==enddb) {
if(destroy) {
context->dynmap[i] = NULL;
FreeDynablockList(&dblist);
} else
MarkDynablockList(&dblist);
} else
if(destroy)
FreeRangeDynablock(dblist, startaddr, endaddr-startaddr+1);
else
MarkRangeDynablock(dblist, startaddr, endaddr-startaddr+1);
}
}
}
// 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 start = (addr)&~(box86_pagesize-1);
uintptr_t end = (addr+size+(box86_pagesize-1))&~(box86_pagesize-1);
// should get "end" according to last block inside the window
mprotect((void*)start, end-start, PROT_READ|PROT_EXEC);
}
// 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 start = (addr)&~(box86_pagesize-1);
uintptr_t end = (addr+size+(box86_pagesize-1))&~(box86_pagesize-1);
// should get "end" according to last block inside the window
mprotect((void*)start, end-start, PROT_READ|PROT_WRITE|PROT_EXEC);
cleanDBFromAddressRange(my_context, start, end-start, 0);
}
#include "dynarec/arm_lock_helper.h"
#endif
EXPORTDYN
void initAllHelpers(box86context_t* context)
{
@@ -356,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;
}
@@ -372,6 +49,7 @@ void finiAllHelpers(box86context_t* context)
fini_pthread_helper(context);
fini_signal_helper();
cleanAlternate();
fini_custommem_helper(context);
finied = 1;
}
@@ -382,11 +60,11 @@ int getrand(int maxval)
{
if(maxval<1024) {
return ((random()&0x7fff)*maxval)/0x7fff;
} else {
}
uint64_t r = random();
r = (r*maxval) / RAND_MAX;
return r;
}
}
void free_tlsdatasize(void* p)
@@ -398,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)
{
@@ -408,7 +156,7 @@ box86context_t *NewBox86Context(int argc)
}
#endif
// init and put default values
box86context_t *context = (box86context_t*)calloc(1, sizeof(box86context_t));
box86context_t *context = my_context = (box86context_t*)calloc(1, sizeof(box86context_t));
#ifdef BUILD_LIB
context->deferedInit = 0;
@@ -417,17 +165,13 @@ box86context_t *NewBox86Context(int argc)
#endif
context->sel_serial = 1;
#ifdef DYNAREC
pthread_mutex_init(&context->mutex_blocks, NULL);
pthread_mutex_init(&context->mutex_mmap, NULL);
context->dynmap = (dynablocklist_t**)calloc(DYNAMAP_SIZE, sizeof(dynablocklist_t*));
#endif
init_custommem_helper(context);
context->maplib = NewLibrarian(context, 1);
context->local_maplib = NewLibrarian(context, 1);
context->system = NewBridge();
// create vsyscall
context->vsyscall = AddBridge(context->system, context, vFv, x86Syscall, 0);
context->vsyscall = AddBridge(context->system, vFv, x86Syscall, 0);
#ifdef BUILD_LIB
context->box86lib = RTLD_DEFAULT; // not ideal
#else
@@ -438,23 +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);
#endif
pthread_mutex_init(&context->mutex_tls, NULL);
pthread_mutex_init(&context->mutex_thread, NULL);
#ifdef DYNAREC
pthread_mutex_init(&context->mutex_dyndump, NULL);
#endif
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);
@@ -477,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]);
}
@@ -484,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);
@@ -518,28 +254,6 @@ void FreeBox86Context(box86context_t** context)
signal(i, SIG_DFL);
}
#ifdef DYNAREC
dynarec_log(LOG_DEBUG, "Free global Dynarecblocks\n");
for (int i=0; i<ctx->mmapsize; ++i) {
if(ctx->mmaplist[i].block)
free(ctx->mmaplist[i].block);
if(ctx->mmaplist[i].dblist) {
kh_destroy(dynablocks, ctx->mmaplist[i].dblist);
ctx->mmaplist[i].dblist = NULL;
}
}
if(ctx->dblist_oversized) {
kh_destroy(dynablocks, ctx->dblist_oversized);
ctx->dblist_oversized = NULL;
}
ctx->mmapsize = 0;
dynarec_log(LOG_DEBUG, "Free dynamic Dynarecblocks\n");
cleanDBFromAddressRange(ctx, 0, 0xffffffff, 1);
pthread_mutex_destroy(&ctx->mutex_blocks);
pthread_mutex_destroy(&ctx->mutex_mmap);
free(ctx->mmaplist);
#endif
*context = NULL; // bye bye my_context
CleanStackSize(ctx);
@@ -551,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);
@@ -583,14 +297,11 @@ void FreeBox86Context(box86context_t** context)
pthread_mutex_destroy(&ctx->mutex_trace);
#ifndef DYNAREC
pthread_mutex_destroy(&ctx->mutex_lock);
#else
pthread_mutex_destroy(&ctx->mutex_dyndump);
#endif
pthread_mutex_destroy(&ctx->mutex_tls);
pthread_mutex_destroy(&ctx->mutex_thread);
#ifdef DYNAREC
pthread_mutex_destroy(&ctx->mutex_dyndump);
free(ctx->dynmap);
ctx->dynmap = NULL;
#endif
free_neededlib(&ctx->neededlibs);
@@ -630,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;
}
+2 -2
View File
@@ -2,7 +2,7 @@
#define __BOX86_VERSION_H_
#define BOX86_MAJOR 0
#define BOX86_MINOR 1
#define BOX86_REVISION 8
#define BOX86_MINOR 2
#define BOX86_REVISION 2
#endif //__BOX86_VERSION_H_
+774
View File
@@ -0,0 +1,774 @@
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <signal.h>
#include "box86context.h"
#include "elfloader.h"
#include "debug.h"
#include "x86trace.h"
#include "x86emu.h"
#include "librarian.h"
#include "bridge.h"
#include "library.h"
#include "callback.h"
#include "wrapper.h"
#include "myfts.h"
#include "threads.h"
#include "x86trace.h"
#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[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;
int maxfree;
size_t size;
} blocklist_t;
#define MMAPSIZE (256*1024) // allocate 256kb sized blocks
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
typedef union mark_s {
struct {
unsigned int fill:1;
unsigned int size:31;
};
uint32_t x32;
} mark_t;
typedef struct blockmark_s {
mark_t prev;
mark_t next;
} blockmark_t;
// 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-sizeof(blockmark_t);
return m;
}
m = (blockmark_t*)((uintptr_t)m + m->next.size);
}
return NULL;
}
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)); // 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>=sizeof(blockmark_t))?(maxsize-sizeof(blockmark_t)):0; // no block large enough left...
}
m = (blockmark_t*)((uintptr_t)m - m->prev.size);
}
return (maxsize>=sizeof(blockmark_t))?(maxsize-sizeof(blockmark_t)):0;
}
static void* allocBlock(void* block, void *sub, int size)
{
blockmark_t *s = (blockmark_t*)sub;
blockmark_t *n = (blockmark_t*)((uintptr_t)s + s->next.size);
s->next.fill = 1;
s->next.size = size+sizeof(blockmark_t);
blockmark_t *m = (blockmark_t*)((uintptr_t)s + s->next.size); // this is new n
m->prev.fill = 1;
m->prev.size = s->next.size;
if(n!=m) {
// new mark
m->prev.fill = 1;
m->prev.size = s->next.size;
m->next.fill = 0;
m->next.size = (uintptr_t)n - (uintptr_t)m;
n->prev.fill = 0;
n->prev.size = m->next.size;
}
return (void*)((uintptr_t)sub + sizeof(blockmark_t));
}
static void freeBlock(void *block, void* sub)
{
blockmark_t *m = (blockmark_t*)block;
blockmark_t *s = (blockmark_t*)sub;
blockmark_t *n = (blockmark_t*)((uintptr_t)s + s->next.size);
if(block!=sub)
m = (blockmark_t*)((uintptr_t)s - s->prev.size);
s->next.fill = 0;
n->prev.fill = 0;
// check if merge with previous
if (s->prev.x32 && !s->prev.fill) {
// remove s...
m->next.size += s->next.size;
n->prev.size = m->next.size;
s = m;
}
// check if merge with next
if(n->next.x32 && !n->next.fill) {
blockmark_t *n2 = (blockmark_t*)((uintptr_t)n + n->next.size);
//remove n
s->next.size += n->next.size;
n2->prev.size = s->next.size;
}
}
// return 1 if block has been expanded to new size, 0 if not
static int expandBlock(void* block, void* sub, int newsize)
{
newsize = (newsize+3)&~3;
blockmark_t *s = (blockmark_t*)sub;
blockmark_t *n = (blockmark_t*)((uintptr_t)s + s->next.size);
if(s->next.fill)
return 0; // next block is filled
if(s->next.size + n->next.size < newsize)
return 0; // free space too short
// ok, doing the alloc!
s->next.size = newsize+sizeof(blockmark_t);
blockmark_t *m = (blockmark_t*)((uintptr_t)s + s->next.size); // this is new n
m->prev.fill = 1;
m->prev.size = s->next.size;
if(n!=m) {
// new mark
m->prev.fill = 1;
m->prev.size = s->next.size;
m->next.fill = 0;
m->next.size = (uintptr_t)n - (uintptr_t)m;
n->prev.fill = 0;
n->prev.size = m->next.size;
}
return 1;
}
// return size of block
static int sizeBlock(void* sub)
{
blockmark_t *s = (blockmark_t*)sub;
return s->next.size;
}
void* customMalloc(size_t size)
{
// look for free space
void* sub = NULL;
pthread_mutex_lock(&mutex_blocks);
for(int i=0; i<n_blocks; ++i) {
if(p_blocks[i].maxfree>=size) {
int rsize = 0;
sub = getFirstBlock(p_blocks[i].block, size, &rsize);
if(sub) {
void* ret = allocBlock(p_blocks[i].block, sub, size);
if(rsize==p_blocks[i].maxfree)
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size);
pthread_mutex_unlock(&mutex_blocks);
return ret;
}
}
}
// add a new block
int i = n_blocks++;
p_blocks = (blocklist_t*)realloc(p_blocks, n_blocks*sizeof(blocklist_t));
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
blockmark_t* m = (blockmark_t*)p;
m->prev.x32 = 0;
m->next.fill = 0;
m->next.size = allocsize-sizeof(blockmark_t);
m = (blockmark_t*)(p+allocsize-sizeof(blockmark_t));
m->next.x32 = 0;
m->prev.fill = 0;
m->prev.size = allocsize-sizeof(blockmark_t);
// alloc 1st block
void* ret = allocBlock(p_blocks[i].block, p, size);
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size);
pthread_mutex_unlock(&mutex_blocks);
return ret;
}
void* customCalloc(size_t n, size_t size)
{
size_t newsize = n*size;
void* ret = customMalloc(newsize);
memset(ret, 0, newsize);
return ret;
}
void* customRealloc(void* p, size_t size)
{
if(!p)
return customMalloc(size);
uintptr_t addr = (uintptr_t)p;
pthread_mutex_lock(&mutex_blocks);
for(int i=0; i<n_blocks; ++i) {
if ((addr>(uintptr_t)p_blocks[i].block)
&& (addr<((uintptr_t)p_blocks[i].block+p_blocks[i].size))) {
void* sub = (void*)(addr-sizeof(blockmark_t));
if(expandBlock(p_blocks[i].block, sub, size)) {
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size);
pthread_mutex_unlock(&mutex_blocks);
return p;
}
pthread_mutex_unlock(&mutex_blocks);
void* newp = customMalloc(size);
memcpy(newp, p, sizeBlock(sub));
customFree(p);
return newp;
}
}
pthread_mutex_unlock(&mutex_blocks);
if(n_blocks)
dynarec_log(LOG_NONE, "Warning, block %p not found in p_blocks for Realloc, Malloc'ng again without free\n", (void*)addr);
return customMalloc(size);
}
void customFree(void* p)
{
if(!p)
return;
uintptr_t addr = (uintptr_t)p;
pthread_mutex_lock(&mutex_blocks);
for(int i=0; i<n_blocks; ++i) {
if ((addr>(uintptr_t)p_blocks[i].block)
&& (addr<((uintptr_t)p_blocks[i].block+p_blocks[i].size))) {
void* sub = (void*)(addr-sizeof(blockmark_t));
freeBlock(p_blocks[i].block, sub);
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size);
pthread_mutex_unlock(&mutex_blocks);
return;
}
}
pthread_mutex_unlock(&mutex_blocks);
if(n_blocks)
dynarec_log(LOG_NONE, "Warning, block %p not found in p_blocks for Free\n", (void*)addr);
}
#ifdef DYNAREC
typedef struct mmaplist_s {
void* block;
int maxfree;
size_t size;
kh_dynablocks_t* dblist;
uint8_t* helper;
} mmaplist_t;
uintptr_t FindFreeDynarecMap(dynablock_t* db, int size)
{
// look for free space
void* sub = NULL;
for(int i=0; i<mmapsize; ++i) {
if(mmaplist[i].maxfree>=size) {
int rsize = 0;
sub = getFirstBlock(mmaplist[i].block, size, &rsize);
if(sub) {
uintptr_t ret = (uintptr_t)allocBlock(mmaplist[i].block, sub, size);
if(rsize==mmaplist[i].maxfree)
mmaplist[i].maxfree = getMaxFreeBlock(mmaplist[i].block, mmaplist[i].size);
kh_dynablocks_t *blocks = mmaplist[i].dblist;
if(!blocks) {
blocks = mmaplist[i].dblist = kh_init(dynablocks);
kh_resize(dynablocks, blocks, 64);
}
khint_t k;
int 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;
}
}
}
return 0;
}
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);
--mmapsize;
return 0;
}
mprotect(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;
m->next.fill = 0;
m->next.size = MMAPSIZE-sizeof(blockmark_t);
m = (blockmark_t*)(p+MMAPSIZE-sizeof(blockmark_t));
m->next.x32 = 0;
m->prev.fill = 0;
m->prev.size = MMAPSIZE-sizeof(blockmark_t);
// alloc 1st block
uintptr_t sub = (uintptr_t)allocBlock(mmaplist[i].block, p, size);
mmaplist[i].maxfree = getMaxFreeBlock(mmaplist[i].block, mmaplist[i].size);
kh_dynablocks_t *blocks = mmaplist[i].dblist = kh_init(dynablocks);
kh_resize(dynablocks, blocks, 64);
khint_t k;
int 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;
}
void ActuallyFreeDynarecMap(dynablock_t* db, uintptr_t addr, int size)
{
if(!addr || !size)
return;
for(int i=0; i<mmapsize; ++i) {
if ((addr>(uintptr_t)mmaplist[i].block)
&& (addr<((uintptr_t)mmaplist[i].block+mmaplist[i].size))) {
void* sub = (void*)(addr-sizeof(blockmark_t));
freeBlock(mmaplist[i].block, sub);
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)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;
}
}
if(mmapsize)
dynarec_log(LOG_NONE, "Warning, block %p (size %d) not found in mmaplist for Free\n", (void*)addr, size);
}
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)) {
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);
}
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);
#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);
kh_resize(dynablocks, blocks, 64);
}
khint_t k;
int ret;
k = kh_put(dynablocks, blocks, (uintptr_t)p, &ret);
kh_value(blocks, k) = db;
pthread_mutex_unlock(&mutex_mmap);
return (uintptr_t)p;
}
pthread_mutex_lock(&mutex_mmap);
uintptr_t ret = FindFreeDynarecMap(db, size);
if(!ret)
ret = AddNewDynarecMap(db, size);
pthread_mutex_unlock(&mutex_mmap);
return ret;
}
void FreeDynarecMap(dynablock_t* db, uintptr_t addr, uint32_t size)
{
if(!addr || !size)
return;
if(size>MMAPSIZE-2*sizeof(blockmark_t)) {
pthread_mutex_lock(&mutex_mmap);
#ifndef USE_MMAP
free((void*)addr);
#else
munmap((void*)addr, size);
#endif
kh_dynablocks_t *blocks = dblist_oversized;
if(blocks) {
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);
ActuallyFreeDynarecMap(db, addr, size);
pthread_mutex_unlock(&mutex_mmap);
}
dynablocklist_t* getDB(uintptr_t idx)
{
return dynmap[idx];
}
// each dynmap is 64k of size
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]) {
dynablocklist_t* p = NewDynablockList(i<<DYNAMAP_SHIFT, 1<<DYNAMAP_SHIFT, 0);
if(arm_lock_storeifnull(&dynmap[i], p)!=p)
FreeDynablockList(&p);
}
}
}
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>>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) {
if(destroy)
FreeRangeDynablock(dblist, addr, size);
else
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)
{
if(inited) // already initialized
return;
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);
dblist_oversized = NULL;
}
mmapsize = 0;
dynarec_log(LOG_DEBUG, "Free dynamic Dynarecblocks\n");
uintptr_t idx = 0;
uintptr_t end = ((0xFFFFFFFF)>>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 = 0;
if(startaddr<startdb) startaddr = startdb;
uintptr_t endaddr = 0xFFFFFFFF;
if(endaddr>enddb) endaddr = enddb;
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);
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);
}
+59 -13
View File
@@ -21,12 +21,13 @@ Op is 20-27
#define xEBP 9
#define xESI 10
#define xEDI 11
#define xEIP 12
#define xFlags 12
#define xEIP 14
// scratch registers
#define x1 1
#define x2 2
#define x3 3
#define x12 12
#define x14 14
// emu is r0
#define xEmu 0
// ARM SP is r13
@@ -77,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) )
@@ -96,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
@@ -109,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
@@ -234,13 +247,22 @@ Op is 20-27
// orr.s dst, src1, src2, lsl #imm
#define ORRS_REG_LSL_IMM5(dst, src1, src2, imm5) \
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
// orr dst, src1, src2, lsr #imm
#define ORR_REG_LSR_IMM5(dst, src1, src2, imm5) \
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
// orr.s dst, src1, src2, lsr #imm
#define ORRS_REG_LSR_IMM5(dst, src1, src2, imm5) \
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
// orr dst, src1, #imm8
#define ORR_IMM8(dst, src, imm8, rot) \
EMIT(0xe3800000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
// orr.s dst, src1, #imm8
#define ORRS_IMM8(dst, src, imm8, rot) \
EMIT(0xe3900000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
// orr dst, src1, src2, lsl #rs
// 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
#define ORR_REG_LSL_REG(dst, src1, src2, rs) \
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brRLSL(rs, src2) )
// xor dst, src1, src2, lsl #imm
@@ -256,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) )
@@ -265,12 +290,18 @@ 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
#define BIC_IMM8_COND(cond, dst, src, imm8, rot) \
EMIT((cond) | 0x03c00000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
// bic.s dst, src1, #imm ror rot*2
#define BICS_IMM8_ROR(dst, src, imm8, rot) \
EMIT(0xe3d00000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
@@ -281,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) )
@@ -327,6 +358,8 @@ Op is 20-27
#define STR_IMM9(reg, addr, imm9) EMIT(0xe5000000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
// str with cond reg, [addr, #+/-imm9]
#define STR_IMM9_COND(cond, reg, addr, imm9) EMIT(cond | 0x05000000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
// str reg, [addr, #+/-imm9]!
#define STR_IMM9_W(reg, addr, imm9) EMIT(0xe5200000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
// strb reg, [addr, #+/-imm9]
#define STRB_IMM9(reg, addr, imm9) EMIT(0xe5400000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
// str reg, [addr], #+/-imm9
@@ -364,10 +397,16 @@ Op is 20-27
// all | const |pre-index| subs | no PSR |writeback| store | base |reg list
#define PUSH(reg, list) EMIT(c__ | (0b100<<25) | (1<<24) | (0<<23) | (0<<22) | (1<<21) | (0<<20) | ((reg)<<16) | (list))
// push reg to xESP
#define PUSH1(reg) STR_IMM9_W(reg, xESP, -4)
// pop reg!, {list}
// all | const |postindex| add | no PSR |writeback| load | base |reg list
#define POP(reg, list) EMIT(c__ | (0b100<<25) | (0<<24) | (1<<23) | (0<<22) | (1<<21) | (1<<20) | ((reg)<<16) | (list))
// pop reg from xESP
#define POP1(reg) LDRAI_IMM9_W(reg, xESP, 4)
// STMDB reg, {list}
// all | const |pre-index| subs | no PSR | no wb | store | base |reg list
#define STMDB(reg, list) EMIT(c__ | (0b100<<25) | (1<<24) | (0<<23) | (0<<22) | (0<<21) | (0<<20) | ((reg)<<16) | (list))
@@ -433,8 +472,15 @@ Op is 20-27
// BFI_COND: Bit Field Insert with condition: copy any number of low order bit from Rn to any position of Rd
#define BFI_COND(cond, rd, rn, lsb, width) EMIT(cond | (0b0111110<<21) | (((lsb)+(width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b001<<4) | (rn))
// BFC: Bit Field Clear: clear any number of adjacent bit from Rd
#define BFC(rd, lsb, width) EMIT(c__ | (0b0111110<<21) | (((lsb)+(width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b001<<4) | 0b1111)
// BFC_COND: Bit Field Clear with condition: clear any number of adjacent bit from Rd
#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
+3 -3
View File
@@ -10,9 +10,9 @@
arm_epilog:
//update register -> emu
//pop {r0}
stm r0, {r4-r12} // put back reg value in emu, including EIP (so r12 must be EIP now)
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>}
-25
View File
@@ -1,25 +0,0 @@
//arm update linker table for dynarec
//called with pointer to emu as 1st parameter
//and address of table to as 2nd parameter
//ip is at r12
.text
.align 4
.extern UpdateLinkTable
.global arm_linker
arm_linker:
// emu is r0
stm r0, {r4-r12} // put back reg value in emu, including EIP (easier debugging, and safer)
// table offset is r1
// IP address is r12
push {r0, r1, r12}
mov r2, r12
// call the function
bl UpdateLinkTable
// return offset is jump address
mov r3, r0
pop {r0, r1, r12}
bx r3
+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__
+23
View File
@@ -0,0 +1,23 @@
//arm update linker table for dynarec
//called with pointer to emu as 1st parameter
//and address of table to as 2nd parameter
//ip is at r12
.text
.align 4
.extern LinkNext
.global arm_next
arm_next:
// emu is r0
//stm r0, {r4-r12,r14} // don't put put back reg value in emu, faster but more tricky to debug
// IP address is r1
push {r0, r1, r12, r14}
// call the function
bl LinkNext
// return offset is jump address
mov r3, r0
pop {r0, r1, r12, r14}
bx r3
+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;
+2 -2
View File
@@ -10,10 +10,10 @@
arm_prolog:
//save all used register
push {r4-r11, lr}
//vpush {d8-d15}
vpush {d8-d15}
//setup emu -> register
//push {r0}
ldm r0, {r4-r11} // all 8 register in direct access, no EIP (so r12 can be used as scratch)
ldm r0, {r4-r12} // all 8 register in direct access, plus flags, no EIP (so r14 can be used as scratch)
//TODO
//jump to function
bx r1
-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
+96 -98
View File
@@ -24,7 +24,7 @@
#else
#error Unsupported architecture!
#endif
#include "custommem.h"
#include "khash.h"
KHASH_MAP_INIT_INT(dynablocks, dynablock_t*)
@@ -38,28 +38,27 @@ uint32_t X31_hash_code(void* addr, int len)
return (uint32_t)h;
}
dynablocklist_t* NewDynablockList(uintptr_t base, 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");
return NULL;
}
dynablocklist_t* ret = (dynablocklist_t*)calloc(1, sizeof(dynablocklist_t));
ret->base = base;
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;
@@ -72,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);
@@ -83,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);
}
@@ -95,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)
@@ -114,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);
}
}
@@ -176,41 +135,34 @@ uintptr_t EndDynablockList(dynablocklist_t* db)
return db->text+db->textsz-1;
return 0;
}
int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2, uintptr_t end2)
{
if(start1 > end2 || start2 > end1)
return 0;
return 1;
}
void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
{
if(!dynablocks)
return;
if(!dynablocks->nolinker)
if(!dynablocks->direct)
return;
uintptr_t startdb = dynablocks->text;
uintptr_t enddb = startdb + dynablocks->textsz;
uintptr_t enddb = startdb + dynablocks->textsz -1;
uintptr_t start = addr;
uintptr_t end = addr+size;
uintptr_t end = addr+size-1;
if(start<startdb)
start = startdb;
if(end>enddb)
end = enddb;
dynablock_t *db;
if(end>startdb && start<enddb)
for(uintptr_t i = start; i<end; ++i)
if(dynablocks->direct[i-startdb]) {
MarkDynablock(dynablocks->direct[i-startdb]);
}
}
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
if((db=dynablocks->direct[i-startdb]))
if(IntervalIntersects((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr+db->x86_size-1, addr, addr+size+1))
MarkDynablock(db);
}
void FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
@@ -239,8 +191,10 @@ void FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t s
if(db) {
if(db->father)
db = db->father;
k = kh_put(dynablocks, blocks, (uintptr_t)db, &ret);
kh_value(blocks, k) = db;
if(db->parent==dynablocks) {
k = kh_put(dynablocks, blocks, (uintptr_t)db, &ret);
kh_value(blocks, k) = db;
}
}
}
}
@@ -255,10 +209,14 @@ 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);
if(dynablocks->direct) {
uintptr_t new_addr = addr - dynablocks->maxsz;
uintptr_t new_size = size + dynablocks->maxsz;
MarkDirectDynablock(dynablocks, new_addr, new_size);
// the blocks check before
for(int idx=(new_addr)>>DYNAMAP_SHIFT; idx<(addr>>DYNAMAP_SHIFT); ++idx)
MarkDirectDynablock(getDB(idx), new_addr, new_size);
}
}
dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks)
@@ -267,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;
)
@@ -278,7 +236,7 @@ dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks)
static dynablocklist_t* getDBFromAddress(uintptr_t addr)
{
const int idx = (addr>>DYNAMAP_SHIFT);
return (my_context->dynmap[idx])?my_context->dynmap[idx]:NULL;
return getDB(idx);
}
dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* created)
@@ -309,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!
@@ -324,8 +286,6 @@ dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* c
return tmp;
}
block->parent = dynablocks;
*created = 1;
return block;
}
@@ -363,19 +323,49 @@ 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)) {
dynablocks->direct[addr-dynablocks->text] = NULL;
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 && block->x86_size) {
int blocksz = block->x86_size;
if(dynablocks->maxsz<blocksz) {
dynablocks->maxsz = blocksz;
for(int idx=(addr>>DYNAMAP_SHIFT)+1; idx<=((addr+blocksz)>>DYNAMAP_SHIFT); ++idx) {
dynablocklist_t* dblist;
if((dblist = getDB(idx)))
if(dblist->maxsz<blocksz)
dblist->maxsz = blocksz;
}
}
protectDB((uintptr_t)block->x86_addr, block->x86_size);
// 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);
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);
return block;
}
@@ -383,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;
@@ -398,6 +388,10 @@ dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t**
} else {
father->need_test = 0;
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;
@@ -408,11 +402,11 @@ 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)
@@ -420,6 +414,10 @@ dynablock_t* DBAlternateBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr)
} else {
father->need_test = 0;
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;
+4 -7
View File
@@ -13,14 +13,12 @@ typedef struct dynablock_s {
void* block;
int size;
void* x86_addr;
int x86_size;
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;
@@ -31,9 +29,8 @@ typedef struct dynablock_s {
typedef struct dynablocklist_s {
uintptr_t text;
int textsz;
uintptr_t base;
int nolinker; // in case this dynablock can disapear (also, block memory are allocated with a temporary scheme)
dynablock_t** direct; // direct mapping (waste of space, so not always there)
int maxsz; // maxblock size (for this block or previous block)
dynablock_t** direct; // direct mapping (waste of space, so the array is created at first write)
} dynablocklist_t;
#endif //__DYNABLOCK_PRIVATE_H_
+43 -52
View File
@@ -25,64 +25,43 @@
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;
#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);
}
#endif
dynablock_t* current = NULL;
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;
}
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_fast;
return arm_epilog;
}
if(!block->done) {
// not finished yet... leave linker
//tableupdate(arm_linker, addr, table);
return arm_epilog_fast;
return arm_epilog;
}
if(!(jblock=block->block)) {
// null block, but done: go to epilog, no linker here
tableupdate(arm_epilog, addr, table);
return arm_epilog_fast;
return arm_epilog;
}
//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;
}
#endif
@@ -98,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
}
}
}
@@ -123,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
@@ -147,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;
}
@@ -177,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
@@ -198,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);
@@ -221,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]);
}
}
+150 -25
View File
@@ -6,6 +6,7 @@
#include "debug.h"
#include "box86context.h"
#include "custommem.h"
#include "dynarec.h"
#include "emu/x86emu_private.h"
#include "tools/bridge_private.h"
@@ -19,6 +20,7 @@
#include "dynablock_private.h"
#include "dynarec_arm.h"
#include "dynarec_arm_private.h"
#include "dynarec_arm_functions.h"
#include "elfloader.h"
void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const char* name) {
@@ -81,9 +83,9 @@ uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr) {
}
return best;
}
#define PK(A) (*((uint8_t*)(addr+(A))))
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n)
{
#define PK(A) (*((uint8_t*)(addr+(A))))
if(!n)
return 1;
if(PK(0)==0x90)
@@ -109,7 +111,122 @@ int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n)
if(n>7 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x84 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00 && PK(6)==0x00 && PK(7)==0x00)
return is_nops(dyn, addr+8, n-8);
return 0;
#undef PK
}
// return size of next instuciton, -1 is unknown
// not all instrction are setup
int next_instruction(dynarec_arm_t *dyn, uintptr_t addr)
{
uint8_t opcode = PK(0);
uint8_t nextop;
switch (opcode) {
case 0x66:
opcode = PK(1);
switch(opcode) {
case 0x90:
return 2;
}
break;
case 0x81:
nextop = PK(1);
return fakeed(dyn, addr+2, 0, nextop)-addr + 4;
case 0x83:
nextop = PK(1);
return fakeed(dyn, addr+2, 0, nextop)-addr + 1;
case 0x84:
case 0x85:
case 0x88:
case 0x89:
case 0x8A:
case 0x8B:
case 0x8C:
case 0x8D:
case 0x8E:
case 0x8F:
nextop = PK(1);
return fakeed(dyn, addr+2, 0, nextop)-addr;
case 0x50:
case 0x51:
case 0x52:
case 0x53:
case 0x54:
case 0x55:
case 0x56:
case 0x57:
case 0x58:
case 0x59:
case 0x5A:
case 0x5B:
case 0x5C:
case 0x5D:
case 0x5E:
case 0x5F:
case 0x90:
case 0x91:
case 0x92:
case 0x93:
case 0x94:
case 0x95:
case 0x96:
case 0x97:
case 0x98:
case 0x99:
case 0x9B:
case 0x9C:
case 0x9D:
case 0x9E:
case 0x9F:
return 1;
case 0xA0:
case 0xA1:
case 0xA2:
case 0xA3:
return 5;
case 0xB0:
case 0xB1:
case 0xB2:
case 0xB3:
case 0xB4:
case 0xB5:
case 0xB6:
case 0xB7:
return 2;
case 0xB8:
case 0xB9:
case 0xBA:
case 0xBB:
case 0xBC:
case 0xBD:
case 0xBE:
case 0xBF:
return 5;
case 0xFF:
nextop = PK(1);
switch((nextop>>3)&7) {
case 0: // INC Ed
case 1: //DEC Ed
case 2: // CALL Ed
case 4: // JMP Ed
case 6: // Push Ed
return fakeed(dyn, addr+2, 0, nextop)-addr;
}
break;
default:
break;
}
return -1;
}
#undef PK
int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n)
{
int i = 0;
while(i<n) {
int j=next_instruction(dyn, addr+i);
if(j<=0) return 0;
i+=j;
}
return (i==n)?1:0;
}
uint32_t needed_flags(dynarec_arm_t *dyn, int ninst, uint32_t setf, int recurse)
@@ -188,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;
@@ -207,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;
@@ -249,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":"");
}
@@ -292,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;
@@ -314,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;
@@ -332,8 +459,6 @@ void* FillBlock(dynablock_t* block, uintptr_t addr) {
} else
free(sons);
}
if(block->parent->nolinker)
protectDB((uintptr_t)block->x86_addr, block->x86_size);
free(helper.sons_x86);
free(helper.sons_arm);
block->done = 1;
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+42 -44
View File
@@ -38,41 +38,41 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0x03:
INST_NAME("ADD Gd, FS:Ed");
SETFLAGS(X_ALL, SF_SET);
grab_fsdata(dyn, addr, ninst, x12);
grab_fsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO(x12);
emit_add32(dyn, ninst, gd, ed, x3, x12);
GETEDO(x14);
emit_add32(dyn, ninst, gd, ed, x3, x14);
break;
case 0x2B:
INST_NAME("SUB Gd, FS:Ed");
SETFLAGS(X_ALL, SF_SET);
grab_fsdata(dyn, addr, ninst, x12);
grab_fsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO(x12);
emit_sub32(dyn, ninst, gd, ed, x3, x12);
GETEDO(x14);
emit_sub32(dyn, ninst, gd, ed, x3, x14);
break;
case 0x33:
INST_NAME("XOR Gd, FS:Ed");
SETFLAGS(X_ALL, SF_SET);
grab_fsdata(dyn, addr, ninst, x12);
grab_fsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO(x12);
emit_xor32(dyn, ninst, gd, ed, x3, x12);
GETEDO(x14);
emit_xor32(dyn, ninst, gd, ed, x3, x14);
break;
case 0x3B:
INST_NAME("CMP Gd, FS:Ed");
SETFLAGS(X_ALL, SF_SET);
grab_fsdata(dyn, addr, ninst, x12);
grab_fsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO(x12);
emit_cmp32(dyn, ninst, gd, ed, x3, x12);
GETEDO(x14);
emit_cmp32(dyn, ninst, gd, ed, x3, x14);
break;
case 0x67:
@@ -82,7 +82,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0x89:
INST_NAME("MOV FS:Ew16, Gw");
nextop = F8;
grab_fsdata(dyn, addr, ninst, x12);
grab_fsdata(dyn, addr, ninst, x14);
GETGD; // don't need GETGW here
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
@@ -91,33 +91,33 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
}
} else {
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
STRH_REG(gd, x12, ed);
STRH_REG(gd, x14, ed);
}
break;
case 0x8B:
INST_NAME("MOV Gd, FS:Ew16");
nextop=F8;
grab_fsdata(dyn, addr, ninst, x12);
grab_fsdata(dyn, addr, ninst, x14);
GETGD;
if((nextop&0xC0)==0xC0) { // reg <= reg
MOV_REG(gd, xEAX+(nextop&7));
} else { // mem <= reg
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
LDR_REG_LSL_IMM5(gd, ed, x12, 0);
LDR_REG_LSL_IMM5(gd, ed, x14, 0);
}
break;
case 0x8F:
INST_NAME("POP FS:Ew16");
nextop=F8;
grab_fsdata(dyn, addr, ninst, x12);
grab_fsdata(dyn, addr, ninst, x14);
if((nextop&0xC0)==0xC0) {
POP(xESP, (1<<(xEAX+(nextop&7)))); // 67 ignored
POP1(xEAX+(nextop&7)); // 67 ignored
} else {
addr = geted16(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
POP(xESP, (1<<x2));
STR_REG_LSL_IMM5(x2, x1, x12, 0);
POP1(x2);
STR_REG_LSL_IMM5(x2, x1, x14, 0);
}
break;
@@ -145,7 +145,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xFF:
nextop = F8;
grab_fsdata(dyn, addr, ninst, x12);
grab_fsdata(dyn, addr, ninst, x14);
switch((nextop>>3)&7) {
case 6: // Push Ed
INST_NAME("PUSH FS:Ew");
@@ -153,8 +153,8 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
DEFAULT;
} else { // mem <= i32
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
LDR_REG_LSL_IMM5(x3, ed, x12, 0);
PUSH(xESP, 1<<x3);
LDR_REG_LSL_IMM5(x3, ed, x14, 0);
PUSH1(x3);
}
break;
default:
@@ -168,40 +168,40 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0x89:
INST_NAME("MOV FS:Ed, Gd");
grab_fsdata(dyn, addr, ninst, x12);
grab_fsdata(dyn, addr, ninst, x14);
nextop=F8;
GETGD;
if((nextop&0xC0)==0xC0) { // reg <= reg
MOV_REG(xEAX+(nextop&7), gd);
} else { // mem <= reg
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
STR_REG_LSL_IMM5(gd, ed, x12, 0);
STR_REG_LSL_IMM5(gd, ed, x14, 0);
}
break;
case 0x8B:
INST_NAME("MOV Gd, FS:Ed");
grab_fsdata(dyn, addr, ninst, x12);
grab_fsdata(dyn, addr, ninst, x14);
nextop=F8;
GETGD;
if((nextop&0xC0)==0xC0) { // reg <= reg
MOV_REG(gd, xEAX+(nextop&7));
} else { // mem <= reg
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
LDR_REG_LSL_IMM5(gd, ed, x12, 0);
LDR_REG_LSL_IMM5(gd, ed, x14, 0);
}
break;
case 0x8F:
INST_NAME("POP FS:Ed");
grab_fsdata(dyn, addr, ninst, x12);
grab_fsdata(dyn, addr, ninst, x14);
nextop = F8;
if((nextop&0xC0)==0xC0) {
POP(xESP, (1<<(xEAX+(nextop&7))));
POP1(xEAX+(nextop&7));
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
POP(xESP, (1<<x2));
STR_REG_LSL_IMM5(x2, ed, x12, 0);
POP1(x2);
STR_REG_LSL_IMM5(x2, ed, x14, 0);
}
break;
@@ -252,7 +252,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xC7:
INST_NAME("MOV FS:Ed, Id");
grab_fsdata(dyn, addr, ninst, x12);
grab_fsdata(dyn, addr, ninst, x14);
nextop=F8;
if((nextop&0xC0)==0xC0) { // reg <= i32
i32 = F32S;
@@ -262,7 +262,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
i32 = F32S;
MOV32(x3, i32);
STR_REG_LSL_IMM5(x3, ed, x12, 0);
STR_REG_LSL_IMM5(x3, ed, x14, 0);
}
break;
@@ -274,10 +274,10 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xFF:
nextop = F8;
grab_fsdata(dyn, addr, ninst, x12);
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 {
@@ -287,20 +287,18 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
MOV_REG(xEIP, xEAX+(nextop&7));
} else { // mem
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
LDR_REG_LSL_IMM5(xEIP, ed, x12, 0);
LDR_REG_LSL_IMM5(xEIP, ed, x14, 0);
}
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);
}
PUSH(xESP, 1<<x2);
jump_to_linker(dyn, 0, xEIP, ninst); // smart linker
MOV32(x2, addr);
PUSH1(x2);
jump_to_next(dyn, 0, xEIP, ninst);
break;
case 6: // Push Ed
INST_NAME("PUSH FS:Ed");
@@ -308,8 +306,8 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
DEFAULT;
} else { // mem <= i32
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
LDR_REG_LSL_IMM5(x3, ed, x12, 0);
PUSH(xESP, 1<<x3);
LDR_REG_LSL_IMM5(x3, ed, x14, 0);
PUSH1(x3);
}
break;
default:
+142 -35
View File
@@ -41,41 +41,60 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0x03:
INST_NAME("ADD Gd, GS:Ed");
SETFLAGS(X_ALL, SF_SET);
grab_tlsdata(dyn, addr, ninst, x12);
grab_tlsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO(x12);
emit_add32(dyn, ninst, gd, ed, x3, x12);
GETEDO(x14);
emit_add32(dyn, ninst, gd, ed, x3, x14);
break;
case 0x2B:
INST_NAME("SUB Gd, GS:Ed");
SETFLAGS(X_ALL, SF_SET);
grab_tlsdata(dyn, addr, ninst, x12);
grab_tlsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO(x12);
emit_sub32(dyn, ninst, gd, ed, x3, x12);
GETEDO(x14);
emit_sub32(dyn, ninst, gd, ed, x3, x14);
break;
case 0x33:
INST_NAME("XOR Gd, GS:Ed");
SETFLAGS(X_ALL, SF_SET);
grab_tlsdata(dyn, addr, ninst, x12);
grab_tlsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO(x12);
emit_xor32(dyn, ninst, gd, ed, x3, x12);
GETEDO(x14);
emit_xor32(dyn, ninst, gd, ed, x3, x14);
break;
case 0x3B:
INST_NAME("CMP Gd, GS:Ed");
SETFLAGS(X_ALL, SF_SET);
grab_tlsdata(dyn, addr, ninst, x12);
grab_tlsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO(x12);
emit_cmp32(dyn, ninst, gd, ed, x3, x12);
GETEDO(x14);
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:
@@ -88,7 +107,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
grab_tlsdata(dyn, addr, ninst, x1);
GETEBO(x1);
u8 = F8;
emit_add8c(dyn, ninst, x1, u8, x2, x12);
emit_add8c(dyn, ninst, x1, u8, x2, x14);
EBBACK;
break;
case 1: //OR
@@ -97,7 +116,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
grab_tlsdata(dyn, addr, ninst, x1);
GETEBO(x1);
u8 = F8;
emit_or8c(dyn, ninst, x1, u8, x2, x12);
emit_or8c(dyn, ninst, x1, u8, x2, x14);
EBBACK;
break;
case 2: //ADC
@@ -107,7 +126,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
grab_tlsdata(dyn, addr, ninst, x1);
GETEBO(x1);
u8 = F8;
emit_adc8c(dyn, ninst, x1, u8, x2, x12);
emit_adc8c(dyn, ninst, x1, u8, x2, x14);
EBBACK;
break;
case 3: //SBB
@@ -117,7 +136,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
grab_tlsdata(dyn, addr, ninst, x1);
GETEBO(x1);
u8 = F8;
emit_sbb8c(dyn, ninst, x1, u8, x2, x12);
emit_sbb8c(dyn, ninst, x1, u8, x2, x14);
EBBACK;
break;
case 4: //AND
@@ -126,7 +145,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
grab_tlsdata(dyn, addr, ninst, x1);
GETEBO(x1);
u8 = F8;
emit_and8c(dyn, ninst, x1, u8, x2, x12);
emit_and8c(dyn, ninst, x1, u8, x2, x14);
EBBACK;
break;
case 5: //SUB
@@ -135,7 +154,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
grab_tlsdata(dyn, addr, ninst, x1);
GETEBO(x1);
u8 = F8;
emit_sub8c(dyn, ninst, x1, u8, x2, x12);
emit_sub8c(dyn, ninst, x1, u8, x2, x14);
EBBACK;
break;
case 6: //XOR
@@ -144,7 +163,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
grab_tlsdata(dyn, addr, ninst, x1);
GETEBO(x1);
u8 = F8;
emit_xor8c(dyn, ninst, x1, u8, x2, x12);
emit_xor8c(dyn, ninst, x1, u8, x2, x14);
EBBACK;
break;
case 7: //CMP
@@ -155,50 +174,138 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
u8 = F8;
if(u8) {
MOVW(x2, u8);
emit_cmp8(dyn, ninst, x1, x2, x3, x12);
emit_cmp8(dyn, ninst, x1, x2, x3, x14);
} else {
emit_cmp8_0(dyn, ninst, x1, x3, x12);
emit_cmp8_0(dyn, ninst, x1, x3, x14);
}
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, x12);
grab_tlsdata(dyn, addr, ninst, x14);
nextop=F8;
GETGD;
if((nextop&0xC0)==0xC0) { // reg <= reg
MOV_REG(xEAX+(nextop&7), gd);
} else { // mem <= reg
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
STR_REG_LSL_IMM5(gd, ed, x12, 0);
STR_REG_LSL_IMM5(gd, ed, x14, 0);
}
break;
case 0x8B:
INST_NAME("MOV Gd, GS:Ed");
grab_tlsdata(dyn, addr, ninst, x12);
grab_tlsdata(dyn, addr, ninst, x14);
nextop=F8;
GETGD;
if((nextop&0xC0)==0xC0) { // reg <= reg
MOV_REG(gd, xEAX+(nextop&7));
} else { // mem <= reg
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
LDR_REG_LSL_IMM5(gd, ed, x12, 0);
LDR_REG_LSL_IMM5(gd, ed, x14, 0);
}
break;
case 0x8F:
INST_NAME("POP GS:Ed");
grab_tlsdata(dyn, addr, ninst, x12);
grab_tlsdata(dyn, addr, ninst, x14);
nextop = F8;
if((nextop&0xC0)==0xC0) {
POP(xESP, (1<<(xEAX+(nextop&7))));
POP1((xEAX+(nextop&7)));
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
POP(xESP, (1<<x2));
STR_REG_LSL_IMM5(x2, ed, x12, 0);
POP1(x2);
STR_REG_LSL_IMM5(x2, ed, x14, 0);
}
break;
@@ -226,7 +333,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xC7:
INST_NAME("MOV GS:Ed, Id");
grab_tlsdata(dyn, addr, ninst, x12);
grab_tlsdata(dyn, addr, ninst, x14);
nextop=F8;
if((nextop&0xC0)==0xC0) { // reg <= i32
i32 = F32S;
@@ -236,7 +343,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
i32 = F32S;
MOV32(x3, i32);
STR_REG_LSL_IMM5(x3, ed, x12, 0);
STR_REG_LSL_IMM5(x3, ed, x14, 0);
}
break;
@@ -248,7 +355,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xFF:
nextop = F8;
grab_tlsdata(dyn, addr, ninst, x12);
grab_tlsdata(dyn, addr, ninst, x14);
switch((nextop>>3)&7) {
case 6: // Push Ed
INST_NAME("PUSH GS:Ed");
@@ -256,8 +363,8 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
DEFAULT;
} else { // mem <= i32
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
LDR_REG_LSL_IMM5(x3, ed, x12, 0);
PUSH(xESP, 1<<x3);
LDR_REG_LSL_IMM5(x3, ed, x14, 0);
PUSH1(x3);
}
break;
default:
+98 -72
View File
@@ -47,7 +47,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETGW(x2);
GETEW(x1);
emit_add16(dyn, ninst, x1, x2, x12, x3, (wb1 && (wback==x3))?1:0);
emit_add16(dyn, ninst, x1, x2, x14, x3, (wb1 && (wback==x3))?1:0);
EWBACK;
break;
case 0x03:
@@ -56,7 +56,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETGW(x1);
GETEW(x2);
emit_add16(dyn, ninst, x1, x2, x3, x12, 0);
emit_add16(dyn, ninst, x1, x2, x3, x14, 0);
GWBACK;
break;
case 0x05:
@@ -64,7 +64,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SETFLAGS(X_ALL, SF_PENDING);
i32 = F16;
UXTH(x1, xEAX, 0);
emit_add16c(dyn, ninst, x1, i32, x3, x12);
emit_add16c(dyn, ninst, x1, i32, x3, x14);
BFI(xEAX, x1, 0, 16);
break;
case 0x06:
@@ -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, x12, 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, x12, x3, 0);
emit_or16(dyn, ninst, x1, x2, x14, x3);
GWBACK;
break;
case 0x0D:
@@ -109,7 +109,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SETFLAGS(X_ALL, SF_SET);
i32 = F16;
UXTH(x1, xEAX, 0);
emit_or16c(dyn, ninst, x1, i32, x3, x12);
emit_or16c(dyn, ninst, x1, i32, x3, x14);
BFI(xEAX, x1, 0, 16);
break;
@@ -123,7 +123,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETGW(x2);
GETEW(x1);
emit_adc16(dyn, ninst, x1, x2, x12, x3, (wb1 && (wback==x3))?1:0);
emit_adc16(dyn, ninst, x1, x2, x14, x3, (wb1 && (wback==x3))?1:0);
EWBACK;
break;
case 0x13:
@@ -133,7 +133,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETGW(x1);
GETEW(x2);
emit_adc16(dyn, ninst, x1, x2, x12, x3, 0);
emit_adc16(dyn, ninst, x1, x2, x14, x3, 0);
GWBACK;
break;
case 0x15:
@@ -142,7 +142,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SETFLAGS(X_ALL, SF_SET);
i32 = F16;
UXTH(x1, xEAX, 0);
emit_adc16c(dyn, ninst, x1, i32, x3, x12);
emit_adc16c(dyn, ninst, x1, i32, x3, x14);
BFI(xEAX, x1, 0, 16);
break;
@@ -153,7 +153,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETGW(x2);
GETEW(x1);
emit_sbb16(dyn, ninst, x1, x2, x12, x3, (wb1 && (wback==x3))?1:0);
emit_sbb16(dyn, ninst, x1, x2, x14, x3, (wb1 && (wback==x3))?1:0);
EWBACK;
break;
case 0x1B:
@@ -163,7 +163,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETGW(x1);
GETEW(x2);
emit_sbb16(dyn, ninst, x1, x2, x12, x3, 0);
emit_sbb16(dyn, ninst, x1, x2, x14, x3, 0);
GWBACK;
break;
case 0x1D:
@@ -172,7 +172,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SETFLAGS(X_ALL, SF_SET);
i16 = F16;
UXTH(x1, xEAX, 0);
emit_sbb16c(dyn, ninst, x1, i16, x3, x12);
emit_sbb16c(dyn, ninst, x1, i16, x3, x14);
BFI(xEAX, x1, 0, 16);
break;
@@ -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, x12, 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, x12, 0);
emit_and16(dyn, ninst, x1, x2, x3, x14);
GWBACK;
break;
case 0x25:
@@ -199,7 +199,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SETFLAGS(X_ALL, SF_SET);
i32 = F16;
UXTH(x1, xEAX, 0);
emit_and16c(dyn, ninst, x1, i32, x3, x12);
emit_and16c(dyn, ninst, x1, i32, x3, x14);
BFI(xEAX, x1, 0, 16);
break;
case 0x26:
@@ -213,7 +213,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETGW(x2);
GETEW(x1);
emit_sub16(dyn, ninst, x1, x2, x12, x3, (wb1 && (wback==x3))?1:0);
emit_sub16(dyn, ninst, x1, x2, x14, x3, (wb1 && (wback==x3))?1:0);
EWBACK;
break;
case 0x2B:
@@ -222,7 +222,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETGW(x1);
GETEW(x2);
emit_sub16(dyn, ninst, x1, x2, x3, x12, 0);
emit_sub16(dyn, ninst, x1, x2, x3, x14, 0);
GWBACK;
break;
case 0x2D:
@@ -230,7 +230,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SETFLAGS(X_ALL, SF_SET);
i32 = F16;
UXTH(x1, xEAX, 0);
emit_sub16c(dyn, ninst, x1, i32, x3, x12);
emit_sub16c(dyn, ninst, x1, i32, x3, x14);
BFI(xEAX, x1, 0, 16);
break;
@@ -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, x12, 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, x12, 0);
emit_xor16(dyn, ninst, x1, x2, x3, x14);
GWBACK;
break;
case 0x35:
@@ -257,7 +257,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SETFLAGS(X_ALL, SF_SET);
i32 = F16;
UXTH(x1, xEAX, 0);
emit_xor16c(dyn, ninst, x1, i32, x3, x12);
emit_xor16c(dyn, ninst, x1, i32, x3, x14);
BFI(xEAX, x1, 0, 16);
break;
@@ -267,7 +267,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETGW(x2);
GETEW(x1);
emit_cmp16(dyn, ninst, x1, x2, x3, x12);
emit_cmp16(dyn, ninst, x1, x2, x3, x14);
break;
case 0x3B:
INST_NAME("CMP Gw, Ew");
@@ -275,7 +275,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETGW(x1);
GETEW(x2);
emit_cmp16(dyn, ninst, x1, x2, x3, x12);
emit_cmp16(dyn, ninst, x1, x2, x3, x14);
break;
case 0x3D:
INST_NAME("CMP AX, Iw");
@@ -283,7 +283,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
i32 = F16;
MOVW(x2, i32);
UXTH(x1, xEAX, 0);
emit_cmp16(dyn, ninst, x1, x2, x3, x12);
emit_cmp16(dyn, ninst, x1, x2, x3, x14);
break;
case 0x40:
@@ -298,7 +298,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
gd = xEAX+(opcode&7);
UXTH(x1, gd, 0);
emit_inc16(dyn, ninst, x1, x3, x12);
emit_inc16(dyn, ninst, x1, x3, x14);
BFI(gd, x1, 0, 16);
break;
case 0x48:
@@ -313,7 +313,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
gd = xEAX+(opcode&7);
UXTH(x1, gd, 0);
emit_dec16(dyn, ninst, x1, x3, x12);
emit_dec16(dyn, ninst, x1, x3, x14);
BFI(gd, x1, 0, 16);
break;
case 0x50:
@@ -420,7 +420,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SETFLAGS(X_ALL, SF_SET);
GETEW(x1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
emit_add16c(dyn, ninst, ed, i16, x2, x12);
emit_add16c(dyn, ninst, ed, i16, x2, x14);
EWBACK;
break;
case 1: //OR
@@ -428,7 +428,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SETFLAGS(X_ALL, SF_SET);
GETEW(x1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
emit_or16c(dyn, ninst, x1, i16, x2, x12);
emit_or16c(dyn, ninst, x1, i16, x2, x14);
EWBACK;
break;
case 2: //ADC
@@ -437,7 +437,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SETFLAGS(X_ALL, SF_SET);
GETEW(x1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
emit_adc16c(dyn, ninst, x1, i16, x2, x12);
emit_adc16c(dyn, ninst, x1, i16, x2, x14);
EWBACK;
break;
case 3: //SBB
@@ -446,7 +446,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SETFLAGS(X_ALL, SF_SET);
GETEW(x1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
emit_sbb16c(dyn, ninst, x1, i16, x2, x12);
emit_sbb16c(dyn, ninst, x1, i16, x2, x14);
EWBACK;
break;
case 4: //AND
@@ -454,7 +454,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SETFLAGS(X_ALL, SF_SET);
GETEW(x1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
emit_and16c(dyn, ninst, x1, i16, x2, x12);
emit_and16c(dyn, ninst, x1, i16, x2, x14);
EWBACK;
break;
case 5: //SUB
@@ -462,7 +462,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SETFLAGS(X_ALL, SF_SET);
GETEW(x1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
emit_sub16c(dyn, ninst, x1, i16, x2, x12);
emit_sub16c(dyn, ninst, x1, i16, x2, x14);
EWBACK;
break;
case 6: //XOR
@@ -470,7 +470,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SETFLAGS(X_ALL, SF_SET);
GETEW(x1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
emit_xor16c(dyn, ninst, x1, i16, x2, x12);
emit_xor16c(dyn, ninst, x1, i16, x2, x14);
EWBACK;
break;
case 7: //CMP
@@ -480,9 +480,9 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
if(opcode==0x81) i16 = F16S; else i16 = F8S;
if(i16) {
MOVW(x2, i16);
emit_cmp16(dyn, ninst, x1, x2, x3, x12);
emit_cmp16(dyn, ninst, x1, x2, x3, x14);
} else
emit_cmp16_0(dyn, ninst, x1, x3, x12);
emit_cmp16_0(dyn, ninst, x1, x3, x14);
break;
}
break;
@@ -493,7 +493,36 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
GETEW(x1);
GETGW(x2);
emit_test16(dyn, ninst, x1, x2, x3, x12);
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:
@@ -580,23 +609,24 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0x99:
INST_NAME("CWD");
SXTH(x1, xEAX, 0);
BFI(xEDX, x1, 16, 16);
MOV_REG_LSR_IMM5(x1, x1, 16);
BFI(xEDX, x1, 0, 16);
break;
case 0x9C:
INST_NAME("PUSHF (16b)");
READFLAGS(X_ALL);
CALL(PackFlags, -1, 0);
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, packed_eflags.x32));
STRHB_IMM8(x1, xESP, -2);
STRHB_IMM8(xFlags, xESP, -2);
break;
case 0x9D:
INST_NAME("POPF (16b)");
SETFLAGS(X_ALL, SF_SET); // lower 16bits is all flags handled in dynarec
LDRHA_IMM8(x1, xESP, 2);
CALL(arm_popf16, -1, 0);
MOVW(x1, d_none);
STR_IMM9(x1, xEmu, offsetof(x86emu_t, df));
LDRHA_IMM8(x2, xESP, 2);
MOV32(x1, 0x7FD7);
AND_REG_LSL_IMM5(x2, x2, x1, 0);
ORR_IMM8(x2, x2, 2, 0);
BFI(xFlags, x2, 0, 16);
SET_DFNONE(x1);
break;
case 0xA1:
@@ -633,7 +663,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
u16 = F16;
MOVW(x2, u16);
UBFX(x1, xEAX, 0, 16);
emit_test16(dyn, ninst, x1, x2, x3, x12);
emit_test16(dyn, ninst, x1, x2, x3, x14);
break;
case 0xAB:
@@ -818,15 +848,15 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 6:
if(opcode==0xD1) {
INST_NAME("SHL Ew, 1");
MOVW(x12, 1);
MOVW(x14, 1);
} else {
INST_NAME("SHL Ew, CL");
AND_IMM8(x12, xECX, 0x1f);
AND_IMM8(x14, xECX, 0x1f);
}
SETFLAGS(X_ALL, SF_PENDING);
GETEW(x1);
UFLAG_OP12(ed, x12)
MOV_REG_LSL_REG(ed, ed, x12);
UFLAG_OP12(ed, x14)
MOV_REG_LSL_REG(ed, ed, x14);
EWBACK;
UFLAG_RES(ed);
UFLAG_DF(x3, d_shl16);
@@ -834,15 +864,15 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 5:
if(opcode==0xD1) {
INST_NAME("SHR Ew, 1");
MOVW(x12, 1);
MOVW(x14, 1);
} else {
INST_NAME("SHR Ew, CL");
AND_IMM8(x12, xECX, 0x1f);
AND_IMM8(x14, xECX, 0x1f);
}
SETFLAGS(X_ALL, SF_PENDING);
GETEW(x1);
UFLAG_OP12(ed, x12)
MOV_REG_LSR_REG(ed, ed, x12);
UFLAG_OP12(ed, x14)
MOV_REG_LSR_REG(ed, ed, x14);
EWBACK;
UFLAG_RES(ed);
UFLAG_DF(x3, d_shr16);
@@ -850,15 +880,15 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 7:
if(opcode==0xD1) {
INST_NAME("SAR Ew, 1");
MOVW(x12, 1);
MOVW(x14, 1);
} else {
INST_NAME("SAR Ew, CL");
AND_IMM8(x12, xECX, 0x1f);
AND_IMM8(x14, xECX, 0x1f);
}
SETFLAGS(X_ALL, SF_PENDING);
GETSEW(x1);
UFLAG_OP12(ed, x12)
MOV_REG_ASR_REG(ed, ed, x12);
UFLAG_OP12(ed, x14)
MOV_REG_ASR_REG(ed, ed, x14);
EWBACK;
UFLAG_RES(ed);
UFLAG_DF(x3, d_sar16);
@@ -916,7 +946,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
MARK2;
SUB_IMM8(xECX, xECX, 1);
MARK3;
emit_cmp16(dyn, ninst, x1, x2, x3, x12);
emit_cmp16(dyn, ninst, x1, x2, x3, x14);
break;
case 0xAB:
@@ -952,7 +982,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
MARK2;
SUB_IMM8(xECX, xECX, 1);
MARK3;
emit_cmp16(dyn, ninst, x1, x2, x3, x12);
emit_cmp16(dyn, ninst, x1, x2, x3, x14);
break;
default:
DEFAULT;
@@ -969,7 +999,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
GETEW(x1);
u16 = F16;
MOVW(x2, u16);
emit_test16(dyn, ninst, x1, x2, x3, x12);
emit_test16(dyn, ninst, x1, x2, x3, x14);
break;
case 2:
INST_NAME("NOT Ew");
@@ -981,7 +1011,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
INST_NAME("NEG Ew");
SETFLAGS(X_ALL, SF_SET);
GETEW(x1);
emit_neg16(dyn, ninst, ed, x2, x12);
emit_neg16(dyn, ninst, ed, x2, x14);
EWBACK;
break;
case 4:
@@ -1026,23 +1056,19 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
i32 = dyn->state_flags; //TODO: find a better way to do this
SETFLAGS(X_CF, SF_SUBSET);
if(i32!=SF_SET) {
MOVW(x1, d_none);
STR_IMM9(x1, xEmu, offsetof(x86emu_t, df));
} else {
MOVW(x1, 0);
}
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
SET_DFNONE(x1);
}
BFC(xFlags, F_CF, 1);
break;
case 0xF9:
INST_NAME("STC");
i32 = dyn->state_flags; //TODO: find a better way to do this
SETFLAGS(X_CF, SF_SUBSET);
if(i32!=SF_SET) {
MOVW(x1, d_none);
STR_IMM9(x1, xEmu, offsetof(x86emu_t, df));
SET_DFNONE(x1);
}
MOVW(x1, 1);
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
BFI(xFlags, x1, F_CF, 1);
break;
case 0xFF:
@@ -1052,14 +1078,14 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
INST_NAME("INC Ew");
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
GETEW(x1);
emit_inc16(dyn, ninst, x1, x2, x12);
emit_inc16(dyn, ninst, x1, x2, x14);
EWBACK;
break;
case 1:
INST_NAME("DEC Ew");
SETFLAGS(X_ALL&~X_CF, SF_SET);
GETEW(x1);
emit_dec16(dyn, ninst, x1, x2, x12);
emit_dec16(dyn, ninst, x1, x2, x14);
EWBACK;
break;
default:
+231 -84
View File
@@ -107,8 +107,16 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
DEFAULT;
return addr;
}
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
VLDR_64(v0, ed, fixedaddress);
parity = getedparity(dyn, ninst, addr, nextop, 3);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
VLDR_64(v0, ed, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-8, 0);
LDR_IMM9(x2, ed, fixedaddress);
LDR_IMM9(x3, ed, fixedaddress+4);
VMOVtoV_D(v0, x2, x3);
}
break;
case 0x13:
INST_NAME("MOVLPD Eq, Gx");
@@ -457,107 +465,93 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
case 0x40:
INST_NAME("CMOVO Gw, Ew");
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_OF]));
CMPS_IMM8(x2, 1)
, cNE, cEQ, X_OF)
GO( TSTS_IMM8_ROR(xFlags, 0b10, 0x0b)
, cEQ, cNE, X_OF)
break;
case 0x41:
INST_NAME("CMOVNO Gw, Ew");
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_OF]));
CMPS_IMM8(x2, 1)
, cEQ, cNE, X_OF)
GO( TSTS_IMM8_ROR(xFlags, 0b10, 0x0b)
, cNE, cEQ, X_OF)
break;
case 0x42:
INST_NAME("CMOVC Gw, Ew");
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_CF]));
CMPS_IMM8(x2, 1)
, cNE, cEQ, X_CF)
GO( TSTS_IMM8(xFlags, 1<<F_CF)
, cEQ, cNE, X_CF)
break;
case 0x43:
INST_NAME("CMOVNC Gw, Ew");
GO( LDR_IMM9(2, 0, offsetof(x86emu_t, flags[F_CF]));
CMPS_IMM8(2, 1)
, cEQ, cNE, X_CF)
GO( TSTS_IMM8(xFlags, 1<<F_CF)
, cNE, cEQ, X_CF)
break;
case 0x44:
INST_NAME("CMOVZ Gw, Ew");
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_ZF]));
CMPS_IMM8(x2, 1)
, cNE, cEQ, X_ZF)
GO( TSTS_IMM8(xFlags, 1<<F_ZF)
, cEQ, cNE, X_ZF)
break;
case 0x45:
INST_NAME("CMOVNZ Gw, Ew");
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_ZF]));
CMPS_IMM8(x2, 1)
, cEQ, cNE, X_ZF)
GO( TSTS_IMM8(xFlags, 1<<F_ZF)
, cNE, cEQ, X_ZF)
break;
case 0x46:
INST_NAME("CMOVBE Gw, Ew");
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_CF]));
LDR_IMM9(x3, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORRS_REG_LSL_IMM5(x2, x2, x3, 0);
GO( TSTS_IMM8(xFlags, (1<<F_CF)|(1<<F_ZF))
, cEQ, cNE, X_CF|X_ZF)
break;
case 0x47:
INST_NAME("CMOVNBE Gw, Ew");
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_CF]));
LDR_IMM9(x3, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORRS_REG_LSL_IMM5(x2, x2, x3, 0);
GO( TSTS_IMM8(xFlags, (1<<F_CF)|(1<<F_ZF))
, cNE, cEQ, X_CF|X_ZF)
break;
case 0x48:
INST_NAME("CMOVS Gw, Ew");
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_SF]));
CMPS_IMM8(x2, 1)
, cNE, cEQ, X_SF)
GO( TSTS_IMM8(xFlags, 1<<F_SF)
, cEQ, cNE, X_SF)
break;
case 0x49:
INST_NAME("CMOVNS Gw, Ew");
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_SF]));
CMPS_IMM8(x2, 1)
, cEQ, cNE, X_SF)
GO( TSTS_IMM8(xFlags, 1<<F_SF)
, cNE, cEQ, X_SF)
break;
case 0x4A:
INST_NAME("CMOVP Gw, Ew");
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_PF]));
CMPS_IMM8(x2, 1)
, cNE, cEQ, X_PF)
GO( TSTS_IMM8(xFlags, 1<<F_PF)
, cEQ, cNE, X_PF)
break;
case 0x4B:
INST_NAME("CMOVNP Gw, Ew");
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_PF]));
CMPS_IMM8(x2, 1)
, cEQ, cNE, X_PF)
GO( TSTS_IMM8(xFlags, 1<<F_PF)
, cNE, cEQ, X_PF)
break;
case 0x4C:
INST_NAME("CMOVL Gw, Ew");
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_SF]));
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_OF]));
GO( UBFX(x2, xFlags, F_SF, 1);
UBFX(x1, xFlags, F_OF, 1);
CMPS_REG_LSL_IMM5(x1, x2, 0)
, cEQ, cNE, X_OF|X_SF)
break;
case 0x4D:
INST_NAME("CMOVGE Gw, Ew");
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_SF]));
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_OF]));
GO( UBFX(x2, xFlags, F_SF, 1);
UBFX(x1, xFlags, F_OF, 1);
CMPS_REG_LSL_IMM5(x1, x2, 0)
, cNE, cEQ, X_OF|X_SF)
break;
case 0x4E:
INST_NAME("CMOVLE Gw, Ew");
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_SF]));
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_OF]));
GO( UBFX(x2, xFlags, F_SF, 1);
UBFX(x1, xFlags, F_OF, 1);
XOR_REG_LSL_IMM5(x1, x1, x2, 0);
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_ZF]));
UBFX(x2, xFlags, F_ZF, 1);
ORRS_REG_LSL_IMM5(x2, x1, x2, 0);
, cEQ, cNE, X_OF|X_SF|X_ZF)
break;
case 0x4F:
INST_NAME("CMOVG Gw, Ew");
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_SF]));
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_OF]));
GO( UBFX(x2, xFlags, F_SF, 1);
UBFX(x1, xFlags, F_OF, 1);
XOR_REG_LSL_IMM5(x1, x1, x2, 0);
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_ZF]));
UBFX(x2, xFlags, F_ZF, 1);
ORRS_REG_LSL_IMM5(x2, x1, x2, 0);
, cNE, cEQ, X_OF|X_SF|X_ZF)
break;
@@ -638,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:
@@ -656,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");
@@ -677,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");
@@ -1186,8 +1181,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
GETEW(x1);
AND_IMM8(x2, gd, 15);
MOV_REG_LSR_REG(x1, ed, x2);
AND_IMM8(x1, x1, 1);
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
BFI(xFlags, x1, F_CF, 1);
break;
case 0xA4:
case 0xA5:
@@ -1199,7 +1193,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
UXTB(x3, xECX, 0);
}
SETFLAGS(X_ALL, SF_SET);
GETEWW(x12, x1);
GETEWW(x14, x1);
GETGW(x2);
if(opcode==0xA4) {
u8 = F8;
@@ -1214,11 +1208,11 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
SETFLAGS(X_CF, SF_SET);
nextop = F8;
GETGD; // there is an AND below, to 32bits is the same
GETEW(x12);
GETEW(x14);
AND_IMM8(x2, gd, 15);
MOV_REG_LSR_REG(x1, ed, x2);
ANDS_IMM8(x1, x1, 1);
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
BFI(xFlags, x1, F_CF, 1);
B_NEXT(cNE);
MOVW(x1, 1);
ORR_REG_LSL_REG(ed, ed, x1, x2);
@@ -1234,7 +1228,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
UXTB(x3, xECX, 0);
}
SETFLAGS(X_ALL, SF_SET);
GETEWW(x12, x1);
GETEWW(x14, x1);
GETGW(x2);
if(opcode==0xAC) {
u8 = F8;
@@ -1267,11 +1261,11 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
SETFLAGS(X_CF, SF_SET);
nextop = F8;
GETGD; // there is an AND below, to 32bits is the same
GETEW(x12);
GETEW(x14);
AND_IMM8(x2, gd, 15);
MOV_REG_LSR_REG(x1, ed, x2);
ANDS_IMM8(x1, x1, 1);
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
BFI(xFlags, x1, F_CF, 1);
B_NEXT(cEQ);
MOVW(x1, 1);
XOR_REG_LSL_REG(ed, ed, x1, x2);
@@ -1307,23 +1301,123 @@ 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(x12);
GETEW(x14);
AND_IMM8(x2, gd, 15);
MOV_REG_LSR_REG(x1, ed, x2);
AND_IMM8(x1, x1, 1);
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
BFI(xFlags, x1, F_CF, 1);
MOVW(x1, 1);
XOR_REG_LSL_REG(ed, ed, x1, x2);
EWBACK;
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);
@@ -1334,13 +1428,12 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
BFI(xEAX+((nextop&0x38)>>3), x2, 0, 16);
XOR_REG_LSL_IMM5(x1, x1, x1, 0); //ZF not set
MARK;
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
MOVW(x1, d_none);
STR_IMM9(x1, xEmu, offsetof(x86emu_t, df));
BFI(xFlags, x1, F_ZF, 1);
SET_DFNONE(x1);
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);
@@ -1352,9 +1445,8 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
BFI(xEAX+((nextop&0x38)>>3), x2, 0, 16);
XOR_REG_LSL_IMM5(x1, x1, x1, 0); //ZF not set
MARK;
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
MOVW(x1, d_none);
STR_IMM9(x1, xEmu, offsetof(x86emu_t, df));
BFI(xFlags, x1, F_ZF, 1);
SET_DFNONE(x1);
break;
case 0xBE:
INST_NAME("MOVSX Gw, Eb");
@@ -1372,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;
@@ -1380,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);
@@ -1460,6 +1570,27 @@ 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;
GETGX(v0);
GETEX(v1);
VSUB_F64(v0+0, v0+0, v1+0);
VADD_F64(v0+1, v0+1, v1+1);
break;
case 0xD1:
INST_NAME("PSRLW Gx,Ex");
nextop = F8;
@@ -1853,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;
+14 -16
View File
@@ -45,7 +45,7 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0x89:
INST_NAME("MOV FS:Ew16, Gw");
nextop = F8;
grab_fsdata(dyn, addr, ninst, x12);
grab_fsdata(dyn, addr, ninst, x14);
GETGD; // don't need GETGW here
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
@@ -54,14 +54,14 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
}
} else {
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
STRH_REG(gd, x12, ed);
STRH_REG(gd, x14, ed);
}
break;
case 0x8B:
INST_NAME("MOV Gd, FS:Ew16");
nextop=F8;
grab_fsdata(dyn, addr, ninst, x12);
grab_fsdata(dyn, addr, ninst, x14);
GETGD;
if((nextop&0xC0)==0xC0) { // reg <= reg
ed = xEAX+(nextop&7);
@@ -70,20 +70,20 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
}
} else { // mem <= reg
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
LDR_REG_LSL_IMM5(gd, x12, ed, 0);
LDR_REG_LSL_IMM5(gd, x14, ed, 0);
}
break;
case 0x8F:
INST_NAME("POP FS:Ew16");
nextop=F8;
grab_fsdata(dyn, addr, ninst, x12);
grab_fsdata(dyn, addr, ninst, x14);
if((nextop&0xC0)==0xC0) {
POP(xESP, (1<<(xEAX+(nextop&7)))); // 67 ignored
POP1(xEAX+(nextop&7)); // 67 ignored
} else {
addr = geted16(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
POP(xESP, (1<<x2));
STR_REG_LSL_IMM5(x2, x12, ed, 0);
POP1(x2);
STR_REG_LSL_IMM5(x2, x14, ed, 0);
}
break;
@@ -111,7 +111,7 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xFF:
nextop = F8;
grab_fsdata(dyn, addr, ninst, x12);
grab_fsdata(dyn, addr, ninst, x14);
switch((nextop>>3)&7) {
case 6: // Push Ed
INST_NAME("PUSH FS:Ew");
@@ -119,8 +119,8 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
DEFAULT;
} else { // mem <= i32
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
LDR_REG_LSL_IMM5(x3, ed, x12, 0);
PUSH(xESP, 1<<x3);
LDR_REG_LSL_IMM5(x3, ed, x14, 0);
PUSH1(x3);
}
break;
default:
@@ -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); \
@@ -155,8 +155,7 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SUBS_IMM8(x1, x1, 1);
BFI(xECX, x1, 0, 16);
B_NEXT(cEQ); // CX is 0, no LOOP
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
TSTS_REG_LSL_IMM5(x1, x1, 0);
TSTS_IMM8(xFlags, 1<<F_ZF);
GO(cNE, cEQ);
break;
case 0xE1:
@@ -167,8 +166,7 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SUBS_IMM8(x1, x1, 1);
BFI(xECX, x1, 0, 16);
B_NEXT(cEQ); // CX is 0, no LOOP
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
TSTS_REG_LSL_IMM5(x1, x1, 0);
TSTS_IMM8(xFlags, 1<<F_ZF);
GO(cEQ, cNE);
break;
case 0xE2:
+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]");
+21 -21
View File
@@ -23,13 +23,13 @@
#include "dynarec_arm_functions.h"
#include "dynarec_arm_helper.h"
static double d_1 = 1.0;
static double d_l2t = L2T;
static double d_l2e = L2E;
static double d_pi = PI;
static double d_lg2 = LG2;
static double d_ln2 = LN2;
static double d_0 = 0.0;
static const double d_1 = 1.0;
static const double d_l2t = L2T;
static const double d_l2e = L2E;
static const double d_pi = PI;
static const double d_lg2 = LG2;
static const double d_ln2 = LN2;
static const double d_0 = 0.0;
uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
{
@@ -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");
+7 -12
View File
@@ -54,8 +54,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
READFLAGS(X_CF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
TSTS_REG_LSL_IMM5(x1, x1, 0);
TSTS_IMM8(xFlags, 1<<F_CF);
VMOVcond_64(cNE, v1, v2); // F_CF==1
break;
case 0xC8:
@@ -70,8 +69,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
READFLAGS(X_ZF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
TSTS_REG_LSL_IMM5(x1, x1, 0);
TSTS_IMM8(xFlags, 1<<F_ZF);
VMOVcond_64(cNE, v1, v2); // F_ZF==1
break;
case 0xD0:
@@ -86,9 +84,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
READFLAGS(X_CF|X_ZF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_CF]));
ORRS_REG_LSL_IMM5(x1, x1, x2, 0);
TSTS_IMM8(xFlags, (1<<F_CF)|(1<<F_ZF));
VMOVcond_64(cNE, v1, v2); // F_CF==1 | F_ZF==1
break;
case 0xD8:
@@ -103,8 +99,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
READFLAGS(X_PF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_PF]));
TSTS_REG_LSL_IMM5(x1, x1, 0);
TSTS_IMM8(xFlags, 1<<F_PF);
VMOVcond_64(cNE, v1, v2); // F_PF==1
break;
case 0xE9:
@@ -113,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:
@@ -173,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");
+34 -24
View File
@@ -52,8 +52,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
READFLAGS(X_CF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
TSTS_REG_LSL_IMM5(x1, x1, 0);
TSTS_IMM8(xFlags, 1<<F_CF);
VMOVcond_64(cEQ, v1, v2); // F_CF==0
break;
case 0xC8:
@@ -68,8 +67,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
READFLAGS(X_ZF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
TSTS_REG_LSL_IMM5(x1, x1, 0);
TSTS_IMM8(xFlags, 1<<F_ZF);
VMOVcond_64(cEQ, v1, v2); // F_ZF==0
break;
case 0xD0:
@@ -84,10 +82,8 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
READFLAGS(X_CF|X_ZF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_CF]));
ORRS_REG_LSL_IMM5(x1, x1, x2, 0);
VMOVcond_64(cEQ, v1, v2); // F_CF==0 | F_ZF==0
TSTS_IMM8(xFlags, (1<<F_CF)|(1<<F_ZF));
VMOVcond_64(cEQ, v1, v2); // F_CF==0 & F_ZF==0
break;
case 0xD8:
case 0xD9:
@@ -101,8 +97,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
READFLAGS(X_PF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_PF]));
TSTS_REG_LSL_IMM5(x1, x1, 0);
TSTS_IMM8(xFlags, 1<<F_PF);
VMOVcond_64(cEQ, v1, v2); // F_PF==0
break;
case 0xE1:
@@ -110,8 +105,8 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 0xE2:
INST_NAME("FNCLEX");
MOVW(x1, 0);
LDRH_IMM8(x2, xEmu, offsetof(x86emu_t, sw));
MOVW(x1, 0);
BFI(x2, x1, 0, 8); // IE .. PE, SF, ES
BFI(x2, x1, 15, 1); // B
STRH_IMM8(x2, xEmu, offsetof(x86emu_t, sw));
@@ -164,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) {
@@ -188,8 +183,8 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
}
s0 = fpu_get_scratch_single(dyn);
MSR_nzcvq_0();
VMRS(x12); // Get FPCSR reg to clear exceptions flags
ORR_IMM8(x3, x12, 0b001, 6); // enable exceptions
VMRS(x14); // Get FPCSR reg to clear exceptions flags
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
BIC_IMM8(x3, x3, 0b10011111, 0);
VMSR(x3);
VCVT_S32_F64(s0, v1);
@@ -198,13 +193,13 @@ 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;
VMSR(x12); // put back values
x87_do_pop(dyn, ninst);
VMSR(x14); // put back values
x87_do_pop(dyn, ninst, x3);
break;
case 2:
INST_NAME("FIST Ed, ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
u8 = x87_setround(dyn, ninst, x1, x2, x12); // x1 have the modified RPSCR reg
u8 = x87_setround(dyn, ninst, x1, x2, x14); // x1 have the modified RPSCR reg
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
wback = 0;
@@ -229,7 +224,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 3:
INST_NAME("FISTP Ed, ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
u8 = x87_setround(dyn, ninst, x1, x2, x12); // x1 have the modified RPSCR reg
u8 = x87_setround(dyn, ninst, x1, x2, x14); // x1 have the modified RPSCR reg
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
wback = 0;
@@ -249,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");
@@ -269,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]");
+8 -8
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");
@@ -210,7 +210,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 7:
INST_NAME("FNSTSW m2byte");
fpu_purgecache(dyn, ninst, x1, x2, x3);
addr = geted(dyn, addr, ninst, nextop, &ed, x12, &fixedaddress, 0, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x14, &fixedaddress, 0, 0);
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, top));
MOVW(x2, offsetof(x86emu_t, sw));
ADD_REG_LSL_IMM5(x2, xEmu, x2, 0);
+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:
+13 -12
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);
@@ -155,8 +154,9 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
ed = x1;
s0 = fpu_get_scratch_single(dyn);
MSR_nzcvq_0();
VMRS(x14); // get fpscr
// x1 already have FPCSR reg to clear exceptions flags
ORR_IMM8(x3, x1, 0b001, 6); // enable exceptions
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
BIC_IMM8(x3, x3, 0b10011111, 0);
VMSR(x3);
VCVTR_S32_F64(s0, v1);
@@ -167,12 +167,13 @@ 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:
INST_NAME("FIST Ew, ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
u8 = x87_setround(dyn, ninst, x1, x2, x12);
u8 = x87_setround(dyn, ninst, x1, x2, x14);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0);
ed = x1;
s0 = fpu_get_scratch_single(dyn);
@@ -194,7 +195,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 3:
INST_NAME("FISTP Ew, ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
u8 = x87_setround(dyn, ninst, x1, x2, x12);
u8 = x87_setround(dyn, ninst, x1, x2, x14);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0);
ed = x1;
s0 = fpu_get_scratch_single(dyn);
@@ -211,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:
@@ -234,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");
@@ -242,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;
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+270 -90
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)
{
@@ -30,17 +87,13 @@ void emit_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
MOVW(s3, c);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
MOVW(s4, d_shl32);
SET_DF(s4, d_shl32);
} else IFX(X_ALL) {
MOVW(s4, d_none);
}
IFX(X_PEND|X_ALL) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
SET_DFNONE(s4);
}
if(c==0) {
IFX(F_OF) {
MOVW(s4, 0);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
@@ -48,10 +101,8 @@ void emit_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
return;
}
IFX(X_CF) {
if(c<31) {
UBFX(s3, s1, 32-c, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
}
MOV_REG_LSR_IMM5(s3, s1, 32-c);
BFI(xFlags, s3, F_CF, 1);
}
IFX(X_ZF|X_OF) {
MOVS_REG_LSL_IMM5(s1, s1, c);
@@ -62,33 +113,76 @@ void emit_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF) {
MOVW_COND(cNE, s3, 0);
MOVW_COND(cEQ, s3, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
UBFX(s3, s1, 31, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_SF]));
MOV_REG_LSR_IMM5(s3, s1, 31);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_OF) {
if(c==1) {
IFX(X_SF) {} else {UBFX(s3, s1, 31, 1);}
IFX(X_SF) {} else {MOV_REG_LSR_IMM5(s3, s1, 31);}
XOR_IMM8_COND(cCS, s3, s3, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_OF]));
BFI(xFlags, s3, F_OF, 1);
} else {
MOVW(s4, 0);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
BFC(xFlags, F_OF, 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);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit SHR32 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s2 can be same as s3
void emit_shr32(dynarec_arm_t* dyn, int ninst, 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);
}
}
@@ -99,12 +193,9 @@ void emit_shr32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
MOVW(s3, c);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
MOVW(s4, d_shr32);
SET_DF(s4, d_shr32);
} else IFX(X_ALL) {
MOVW(s4, d_none);
}
IFX(X_PEND|X_ALL) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
SET_DFNONE(s4);
}
if(!c) {
IFX(X_PEND) {
@@ -120,37 +211,28 @@ 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) {
MOVW_COND(cNE, s3, 0);
MOVW_COND(cEQ, s3, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_CF) {
MOVW_COND(cCC, s3, 0);
MOVW_COND(cCS, s3, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_SF) {
UBFX(s3, s1, 31, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_SF]));
MOV_REG_LSR_IMM5(s3, s1, 31);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_OF) {
if(c==1) {
MOV_REG_LSR_IMM5(s4, s1, 30);
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
BFI(xFlags, s4, F_OF, 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);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -161,12 +243,9 @@ void emit_sar32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
MOVW(s3, c);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
MOVW(s4, d_sar32);
SET_DF(s4, d_sar32);
} else IFX(X_ALL) {
MOVW(s4, d_none);
}
IFX(X_PEND|X_ALL) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
SET_DFNONE(s4);
}
if(!c) {
IFX(X_PEND) {
@@ -182,29 +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) {
MOVW_COND(cNE, s3, 0);
MOVW_COND(cEQ, s3, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_CF) {
MOVW_COND(cCC, s3, 0);
MOVW_COND(cCS, s3, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_SF) {
UBFX(s3, s1, 31, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_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);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -214,12 +285,9 @@ void emit_rol32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
IFX(X_PEND) {
MOVW(s3, c);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
MOVW(s4, d_rol32);
SET_DF(s4, d_rol32);
} else IFX(X_ALL) {
MOVW(s4, d_none);
}
IFX(X_PEND|X_ALL) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
SET_DFNONE(s4);
}
if(!c) {
IFX(X_PEND) {
@@ -232,14 +300,12 @@ void emit_rol32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF) {
AND_IMM8(s3, s1, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
BFI(xFlags, s1, F_CF, 1);
}
IFX(X_OF) {
if(c==1) {
ADD_REG_LSR_IMM5(s3, s1, s1, 31);
AND_IMM8(s3, s3, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_OF]));
BFI(xFlags, s3, F_OF, 1);
}
}
}
@@ -250,12 +316,9 @@ void emit_ror32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
IFX(X_PEND) {
MOVW(s3, c);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
MOVW(s4, d_ror32);
SET_DF(s4, d_ror32);
} else IFX(X_ALL) {
MOVW(s4, d_none);
}
IFX(X_PEND|X_ALL) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
SET_DFNONE(s4);
}
if(!c) {
IFX(X_PEND) {
@@ -268,15 +331,132 @@ void emit_ror32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF) {
UBFX(s3, s1, 31, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
MOV_REG_LSR_IMM5(s3, s1, 31);
BFI(xFlags, s3, F_CF, 1);
}
IFX(X_OF) {
if(c==1) {
MOV_REG_LSR_IMM5(s4, s1, 30);
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
BFI(xFlags, s4, F_OF, 1);
}
}
}
// emit SHRD32 instruction, from s1, fill s2 , constant c, store result in s1 using s3 and s4 as scratch
void emit_shrd32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4)
{
c&=0x1f;
IFX(X_PEND) {
MOVW(s3, c);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
// same flags calc as shr32
SET_DF(s4, d_shr32);
} else IFX(X_ALL) {
SET_DFNONE(s4);
}
if(!c) {
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
return;
}
IFX(X_CF) {
MOVS_REG_LSR_IMM5(s1, s1, c);
} else {
MOV_REG_LSR_IMM5(s1, s1, c);
}
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
IFX(X_CF) {
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_ZF) {
ORRS_REG_LSL_IMM5(s1, s1, s2, 32-c);
} else {
ORR_REG_LSL_IMM5(s1, s1, s2, 32-c);
}
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 31);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_OF) {
if(c==1) {
MOV_REG_LSR_IMM5(s4, s1, 30);
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
BFI(xFlags, s4, F_OF, 1);
}
}
IFX(X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
}
void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4)
{
c&=0x1f;
IFX(X_PEND) {
MOVW(s3, c);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
// same flags computation as with shl32
SET_DF(s4, d_shl32);
} else IFX(X_ALL) {
SET_DFNONE(s4);
}
if(c==0) {
IFX(F_OF) {
BFC(xFlags, F_OF, 1);
}
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
return;
}
IFX(X_CF) {
MOV_REG_LSR_IMM5(s3, s1, 32-c);
BFI(xFlags, s3, F_CF, 1);
}
IFX(X_OF) {
MOVS_REG_LSL_IMM5(s1, s1, c);
} else {
MOV_REG_LSL_IMM5(s1, s1, c);
}
IFX(X_OF) {
if(c==1) {
UBFX(s3, s2, 0, 1);
XOR_IMM8_COND(cCS, s3, s3, 1);
BFI(xFlags, s3, F_OF, 1);
} else {
BFC(xFlags, F_OF, 1);
}
}
IFX(X_ZF) {
ORRS_REG_LSR_IMM5(s1, s1, s2, 32-c);
} else {
ORR_REG_LSR_IMM5(s1, s1, s2, 32-c);
}
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(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(s3, s1, 31);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
}
+122 -198
View File
@@ -26,43 +26,34 @@
// 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));
MOVW(s4, d_cmp32);
SET_DF(s4, d_cmp32);
} else {
MOVW(s4, 0);
SET_DFNONE(s4);
}
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
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) {
IFX(X_PEND) {
MOVW(s4, 0);
}
// first the easy flag, also found on ARM
MOVW_COND(cEQ, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_OF) {
IFX(X_ZF|X_PEND) {
MOVW(s4, 0);
}
MOVW_COND(cVS, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
ORR_IMM8_COND(cVS, xFlags, xFlags, 0b10, 0x0b);
BIC_IMM8_COND(cVC, xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_CF) {
IFX(X_ZF|X_OF|X_PEND) {
MOVW(s4, 0);
}
MOVW_COND(cCC, s4, 1); // Carry flags on ARM is reversed compared to x86 one
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF]));
// reversed carry
ORR_IMM8_COND(cCC, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_SF) {
UBFX(s4, s3, 31, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
MOV_REG_LSR_IMM5(s4, s3, 31);
BFI(xFlags, s4, F_SF, 1);
}
// and now the tricky ones (and mostly unused), PF and AF
IFX(X_AF) {
@@ -73,8 +64,8 @@ void emit_cmp32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
BIC_REG_LSL_IMM5(s3, s2, s1, 0); // loosing res... s3 = s & ~d
ORR_REG_LSL_IMM5(s3, s4, s3, 0); // s3 = (res & (~d | s)) | (s & ~d)
IFX(X_AF) {
UBFX(s4, s3, 3, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
MOV_REG_LSR_IMM5(s4, s3, 3);
BFI(xFlags, s4, F_AF, 1); // AF: bc & 0x08
}
}
IFX(X_PF) {
@@ -83,90 +74,71 @@ 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);
MVN_REG_LSR_REG(s4, s4, s3);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
BFI(xFlags, s4, F_PF, 1);
}
}
// 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)
{
MOVW(s4, 0);
IFX(X_PEND) {
IFX_PENDOR0 {
MOVW(s4, 0);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
STR_IMM9(s4, xEmu, offsetof(x86emu_t, op2));
MOVW(s4, d_cmp32);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
SET_DF(s4, d_cmp32);
} else {
SET_DFNONE(s4);
}
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
SUBS_IMM8(s3, s1, 0); // res = s1 - 0
IFX(X_PEND) {
IFX(X_ZF|X_OF|X_CF|X_AF) {
MOVW(s4, 0);
}
}
// and now the tricky ones (and mostly unused), PF and AF
// bc = (res & (~d | s)) | (~d & s) => is 0 here...
IFX(X_CF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF])); // CF : bc & 0x80000000
}
IFX(X_AF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
BFC(xFlags, F_OF, 1);
}
IFX(X_ZF) {
// first the easy flags, also found on ARM
MOVW_COND(cEQ, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
UBFX(s4, s3, 31, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_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);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit CMP16 instruction, from cmp s1 , s2, using s3 and s4 as scratch
void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
IFX(X_PEND) {
IFX_PENDOR0 {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
MOVW(s3, d_cmp16);
SET_DF(s3, d_cmp16);
} else {
MOVW(s3, 0);
SET_DFNONE(s3);
}
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df)); // reset flags
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) {
MOVW(s4, 0xffff);
TSTS_REG_LSL_IMM5(s3, s4, 0);
MOVW_COND(cNE, s4, 0);
MOVW_COND(cEQ, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
UBFX(s4, s3, 15, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
MOV_REG_LSR_IMM5(s4, s3, 15);
BFI(xFlags, s4, F_SF, 1);
}
// bc = (res & (~d | s)) | (~d & s)
IFX(X_CF|X_AF|X_OF) {
@@ -176,108 +148,87 @@ void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
BIC_REG_LSL_IMM5(s3, s2, s1, 0); // loosing res... s3 = s & ~d
ORR_REG_LSL_IMM5(s3, s4, s3, 0); // s3 = (res & (~d | s)) | (s & ~d)
IFX(X_CF) {
UBFX(s4, s3, 15, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF])); // CF : bc & 0x8000
MOV_REG_LSR_IMM5(s4, s3, 15);
BFI(xFlags, s4, F_CF, 1); // CF : bc & 0x8000
}
IFX(X_AF) {
UBFX(s4, s3, 3, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
MOV_REG_LSR_IMM5(s4, s3, 3);
BFI(xFlags, s4, F_AF, 1); // AF: bc & 0x08
}
IFX(X_OF) {
MOV_REG_LSR_IMM5(s4, s3, 14);
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF])); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
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);
MVN_REG_LSR_REG(s4, s4, s3);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
BFI(xFlags, s4, F_PF, 1);
}
}
// 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)
{
MOVW(s3, 0);
IFX(X_PEND) {
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
IFX_PENDOR0 {
MOVW(s3, 0);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
MOVW(s3, d_cmp16);
}
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df)); // reset flags
IFX(X_OF|X_CF|X_AF) {
MOVW(s4, 0);
SET_DF(s3, d_cmp16);
} else {
SET_DFNONE(s3);
}
// bc = (res & (~d | s)) | (~d & s) = 0
IFX(X_CF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF])); // CF : bc & 0x8000
}
IFX(X_AF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF])); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
BFC(xFlags, F_OF, 1);
}
IFX(X_ZF) {
MOVW(s4, 0xffff);
TSTS_REG_LSL_IMM5(s1, s4, 0);
MOVW(s4, 0);
MOVW_COND(cEQ, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
UBFX(s4, s1, 15, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_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);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit CMP8 instruction, from cmp s1 , s2, using s3 and s4 as scratch
void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
IFX(X_PEND) {
MOVW(s4, d_cmp8);
IFX_PENDOR0 {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
SET_DF(s4, d_cmp8);
} else {
MOVW(s4, 0);
SET_DFNONE(s4);
}
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
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) {
IFX(X_PEND) {
MOVW(s4, 0);
}
TSTS_IMM8(s3, 0xff);
MOVW_COND(cEQ, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
UBFX(s4, s3, 7, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
MOV_REG_LSR_IMM5(s4, s3, 7);
BFI(xFlags, s4, F_SF, 1);
}
// bc = (res & (~d | s)) | (~d & s)
IFX(X_CF|X_AF|X_OF) {
@@ -287,198 +238,171 @@ void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
BIC_REG_LSL_IMM5(s3, s2, s1, 0); // loosing res... s3 = s & ~d
ORR_REG_LSL_IMM5(s3, s4, s3, 0); // s3 = (res & (~d | s)) | (s & ~d)
IFX(X_CF) {
UBFX(s4, s3, 7, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF])); // CF : bc & 0x80
MOV_REG_LSR_IMM5(s4, s3, 7);
BFI(xFlags, s4, F_CF, 1); // CF : bc & 0x80
}
IFX(X_AF) {
UBFX(s4, s3, 3, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
MOV_REG_LSR_IMM5(s4, s3, 3);
BFI(xFlags, s4, F_AF, 1); // AF: bc & 0x08
}
IFX(X_OF) {
MOV_REG_LSR_IMM5(s4, s3, 6);
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF])); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
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);
MVN_REG_LSR_REG(s4, s4, s3);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
BFI(xFlags, s4, F_PF, 1);
}
}
// 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)
{
MOVW(s4, 0);
IFX(X_PEND) {
MOVW(s3, d_cmp8);
IFX_PENDOR0 {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
MOVW(s4, 0);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, op2));
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df));
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
SET_DF(s3, d_cmp8);
} else {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
SET_DFNONE(s4);
}
// bc = (res & (~d | s)) | (~d & s) = 0
IFX(X_CF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF])); // CF : bc & 0x80
}
IFX(X_AF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF])); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
BFC(xFlags, F_OF, 1);
}
IFX(X_ZF) {
TSTS_IMM8(s1, 0xff);
MOVW_COND(cEQ, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
UBFX(s4, s1, 7, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_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);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit TEST32 instruction, from test s1 , s2, using s3 and s4 as scratch
void emit_test32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
MOVW(s4, 0);
IFX(X_PEND) {
MOVW(s3, d_tst32);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df));
IFX_PENDOR0 {
SET_DF(s3, d_tst32);
} else {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
SET_DFNONE(s4);
}
IFX(X_OF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
BFC(xFlags, F_OF, 1);
}
IFX(X_CF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF]));
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) {
MOVW_COND(cEQ, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
UBFX(s4, s3, 31, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
MOV_REG_LSR_IMM5(s4, s3, 31);
BFI(xFlags, s4, F_SF, 1);
}
// 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);
MVN_REG_LSR_REG(s4, s4, s3);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
BFI(xFlags, s4, F_PF, 1);
}
}
// emit TEST16 instruction, from test s1 , s2, using s3 and s4 as scratch
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
MOVW(s4, 0);
IFX(X_PEND) {
MOVW(s3, d_tst16);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df));
IFX_PENDOR0 {
SET_DF(s3, d_tst16);
} else {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
SET_DFNONE(s4);
}
IFX(X_OF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
BFC(xFlags, F_OF, 1);
}
IFX(X_CF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF]));
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) {
MOVW_COND(cEQ, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
UBFX(s4, s3, 15, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
MOV_REG_LSR_IMM5(s4, s3, 15);
BFI(xFlags, s4, F_SF, 1);
}
// 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);
MVN_REG_LSR_REG(s4, s4, s3);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
BFI(xFlags, s4, F_PF, 1);
}
}
// 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)
{
MOVW(s4, 0);
IFX(X_PEND) {
MOVW(s3, d_tst8);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df));
IFX_PENDOR0 {
SET_DF(s3, d_tst8);
} else {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
SET_DFNONE(s4);
}
IFX(X_OF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
BFC(xFlags, F_OF, 1);
}
IFX(X_CF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF]));
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) {
MOVW_COND(cEQ, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
UBFX(s4, s3, 7, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
MOV_REG_LSR_IMM5(s4, s3, 7);
BFI(xFlags, s4, F_SF, 1);
}
// 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);
MVN_REG_LSR_REG(s4, s4, s3);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
BFI(xFlags, s4, F_PF, 1);
}
}
+182 -127
View File
@@ -46,15 +46,15 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
wb2 = (wback>>2);
wback = xEAX+(wback&3);
UXTB(x1, wback, wb2);
emit_add8(dyn, ninst, x1, x2, x12, x3, 0);
emit_add8(dyn, ninst, x1, x2, x14, x3, 0);
BFI(wback, ed, wb2*8, 8);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0);
MARKLOCK;
LDREXB(x1, wback);
emit_add8(dyn, ninst, x1, x2, x12, x3, (wback==x3)?1:0);
STREXB(x12, x1, wback);
CMPS_IMM8(x12, 0);
emit_add8(dyn, ninst, x1, x2, x14, x3, (wback==x3)?1:0);
STREXB(x14, x1, wback);
CMPS_IMM8(x14, 0);
B_MARKLOCK(cNE); // write failed, try again
}
break;
@@ -65,12 +65,12 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
GETGD;
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
emit_add32(dyn, ninst, ed, gd, x3, x12);
emit_add32(dyn, ninst, ed, gd, x3, x14);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
MARKLOCK;
LDREX(x1, wback);
emit_add32(dyn, ninst, x1, gd, x3, x12);
emit_add32(dyn, ninst, x1, gd, x3, x14);
STREX(x3, x1, wback);
CMPS_IMM8(x3, 0);
B_MARKLOCK(cNE);
@@ -80,21 +80,22 @@ 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, x12, 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, x12, x3, (wback==x3)?1:0);
STREXB(x12, x1, wback);
CMPS_IMM8(x12, 0);
emit_or8(dyn, ninst, x1, x2, x14, x2);
STREXB(x14, x1, wback);
CMPS_IMM8(x14, 0);
B_MARKLOCK(cNE); // write failed, try again
}
break;
@@ -105,12 +106,12 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
GETGD;
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
emit_or32(dyn, ninst, ed, gd, x3, x12);
emit_or32(dyn, ninst, ed, gd, x3, x14);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
MARKLOCK;
LDREX(x1, wback);
emit_or32(dyn, ninst, x1, gd, x3, x12);
emit_or32(dyn, ninst, x1, gd, x3, x14);
STREX(x3, x1, wback);
CMPS_IMM8(x3, 0);
B_MARKLOCK(cNE);
@@ -126,15 +127,15 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
wb2 = (wback>>2);
wback = xEAX+(wback&3);
UXTB(x1, wback, wb2);
emit_adc8(dyn, ninst, x1, x2, x12, x3, 0);
emit_adc8(dyn, ninst, x1, x2, x14, x3, 0);
BFI(wback, ed, wb2*8, 8);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0);
MARKLOCK;
LDREXB(x1, wback);
emit_adc8(dyn, ninst, x1, x2, x12, x3, (wback==x3)?1:0);
STREXB(x12, x1, wback);
CMPS_IMM8(x12, 0);
emit_adc8(dyn, ninst, x1, x2, x14, x3, (wback==x3)?1:0);
STREXB(x14, x1, wback);
CMPS_IMM8(x14, 0);
B_MARKLOCK(cNE); // write failed, try again
}
break;
@@ -145,12 +146,12 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
GETGD;
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
emit_adc32(dyn, ninst, ed, gd, x3, x12);
emit_adc32(dyn, ninst, ed, gd, x3, x14);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
MARKLOCK;
LDREX(x1, wback);
emit_adc32(dyn, ninst, x1, gd, x3, x12);
emit_adc32(dyn, ninst, x1, gd, x3, x14);
STREX(x3, x1, wback);
CMPS_IMM8(x3, 0);
B_MARKLOCK(cNE);
@@ -166,15 +167,15 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
wb2 = (wback>>2);
wback = xEAX+(wback&3);
UXTB(x1, wback, wb2);
emit_sbb8(dyn, ninst, x1, x2, x12, x3, 0);
emit_sbb8(dyn, ninst, x1, x2, x14, x3, 0);
BFI(wback, ed, wb2*8, 8);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0);
MARKLOCK;
LDREXB(x1, wback);
emit_sbb8(dyn, ninst, x1, x2, x12, x3, (wback==x3)?1:0);
STREXB(x12, x1, wback);
CMPS_IMM8(x12, 0);
emit_sbb8(dyn, ninst, x1, x2, x14, x3, (wback==x3)?1:0);
STREXB(x14, x1, wback);
CMPS_IMM8(x14, 0);
B_MARKLOCK(cNE); // write failed, try again
}
break;
@@ -185,12 +186,12 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
GETGD;
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
emit_sbb32(dyn, ninst, ed, gd, x3, x12);
emit_sbb32(dyn, ninst, ed, gd, x3, x14);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
MARKLOCK;
LDREX(x1, wback);
emit_sbb32(dyn, ninst, x1, gd, x3, x12);
emit_sbb32(dyn, ninst, x1, gd, x3, x14);
STREX(x3, x1, wback);
CMPS_IMM8(x3, 0);
B_MARKLOCK(cNE);
@@ -200,21 +201,22 @@ 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, x12, 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, x12, x3, (wback==x3)?1:0);
STREXB(x12, x1, wback);
CMPS_IMM8(x12, 0);
emit_and8(dyn, ninst, x1, x2, x14, x2);
STREXB(x14, x1, wback);
CMPS_IMM8(x14, 0);
B_MARKLOCK(cNE); // write failed, try again
}
break;
@@ -225,12 +227,12 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
GETGD;
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
emit_and32(dyn, ninst, ed, gd, x3, x12);
emit_and32(dyn, ninst, ed, gd, x3, x14);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
MARKLOCK;
LDREX(x1, wback);
emit_and32(dyn, ninst, x1, gd, x3, x12);
emit_and32(dyn, ninst, x1, gd, x3, x14);
STREX(x3, x1, wback);
CMPS_IMM8(x3, 0);
B_MARKLOCK(cNE);
@@ -246,15 +248,15 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
wb2 = (wback>>2);
wback = xEAX+(wback&3);
UXTB(x1, wback, wb2);
emit_sub8(dyn, ninst, x1, x2, x12, x3, 0);
emit_sub8(dyn, ninst, x1, x2, x14, x3, 0);
BFI(wback, ed, wb2*8, 8);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0);
MARKLOCK;
LDREXB(x1, wback);
emit_sub8(dyn, ninst, x1, x2, x12, x3, (wback==x3)?1:0);
STREXB(x12, x1, wback);
CMPS_IMM8(x12, 0);
emit_sub8(dyn, ninst, x1, x2, x14, x3, (wback==x3)?1:0);
STREXB(x14, x1, wback);
CMPS_IMM8(x14, 0);
B_MARKLOCK(cNE); // write failed, try again
}
break;
@@ -265,12 +267,12 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
GETGD;
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
emit_sub32(dyn, ninst, ed, gd, x3, x12);
emit_sub32(dyn, ninst, ed, gd, x3, x14);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
MARKLOCK;
LDREX(x1, wback);
emit_sub32(dyn, ninst, x1, gd, x3, x12);
emit_sub32(dyn, ninst, x1, gd, x3, x14);
STREX(x3, x1, wback);
CMPS_IMM8(x3, 0);
B_MARKLOCK(cNE);
@@ -280,21 +282,22 @@ 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, x12, 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, x12, x3, (wback==x3)?1:0);
STREXB(x12, x1, wback);
CMPS_IMM8(x12, 0);
emit_xor8(dyn, ninst, x1, x2, x14, x2);
STREXB(x14, x1, wback);
CMPS_IMM8(x14, 0);
B_MARKLOCK(cNE); // write failed, try again
}
break;
@@ -305,12 +308,12 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
GETGD;
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
emit_xor32(dyn, ninst, ed, gd, x3, x12);
emit_xor32(dyn, ninst, ed, gd, x3, x14);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
MARKLOCK;
LDREX(x1, wback);
emit_xor32(dyn, ninst, x1, gd, x3, x12);
emit_xor32(dyn, ninst, x1, gd, x3, x14);
STREX(x3, x1, wback);
CMPS_IMM8(x3, 0);
B_MARKLOCK(cNE);
@@ -331,7 +334,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
if((nextop&0xC0)==0xC0) {
if(opcode==0x81) i32 = F32S; else i32 = F8S;
ed = xEAX+(nextop&7);
emit_add32c(dyn, ninst, ed, i32, x3, x12);
emit_add32c(dyn, ninst, ed, i32, x3, x14);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
@@ -339,16 +342,16 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
B_MARK(cNE);
MARKLOCK;
LDREX(x1, wback);
emit_add32c(dyn, ninst, x1, i32, x3, x12);
emit_add32c(dyn, ninst, x1, i32, x3, x14);
STREX(x3, x1, wback);
CMPS_IMM8(x3, 0);
B_MARKLOCK(cNE);
B_NEXT(c__);
MARK; // unaligned! also, not enough
LDR_IMM9(x1, wback, 0);
LDREXB(x12, wback);
BFI(x1, x12, 0, 8); // re-inject
emit_add32c(dyn, ninst, x1, i32, x3, x12);
LDREXB(x14, wback);
BFI(x1, x14, 0, 8); // re-inject
emit_add32c(dyn, ninst, x1, i32, x3, x14);
STREXB(x3, x1, wback);
CMPS_IMM8(x3, 0);
B_MARK(cNE);
@@ -361,13 +364,13 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
if((nextop&0xC0)==0xC0) {
if(opcode==0x81) i32 = F32S; else i32 = F8S;
ed = xEAX+(nextop&7);
emit_or32c(dyn, ninst, ed, i32, x3, x12);
emit_or32c(dyn, ninst, ed, i32, x3, x14);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
MARKLOCK;
LDREX(x1, wback);
emit_or32c(dyn, ninst, x1, i32, x3, x12);
emit_or32c(dyn, ninst, x1, i32, x3, x14);
STREX(x3, x1, wback);
CMPS_IMM8(x3, 0);
B_MARKLOCK(cNE);
@@ -380,13 +383,13 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
if((nextop&0xC0)==0xC0) {
if(opcode==0x81) i32 = F32S; else i32 = F8S;
ed = xEAX+(nextop&7);
emit_adc32c(dyn, ninst, ed, i32, x3, x12);
emit_adc32c(dyn, ninst, ed, i32, x3, x14);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
MARKLOCK;
LDREX(x1, wback);
emit_adc32c(dyn, ninst, x1, i32, x3, x12);
emit_adc32c(dyn, ninst, x1, i32, x3, x14);
STREX(x3, x1, wback);
CMPS_IMM8(x3, 0);
B_MARKLOCK(cNE);
@@ -399,13 +402,13 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
if((nextop&0xC0)==0xC0) {
if(opcode==0x81) i32 = F32S; else i32 = F8S;
ed = xEAX+(nextop&7);
emit_sbb32c(dyn, ninst, ed, i32, x3, x12);
emit_sbb32c(dyn, ninst, ed, i32, x3, x14);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
MARKLOCK;
LDREX(x1, wback);
emit_sbb32c(dyn, ninst, x1, i32, x3, x12);
emit_sbb32c(dyn, ninst, x1, i32, x3, x14);
STREX(x3, x1, wback);
CMPS_IMM8(x3, 0);
B_MARKLOCK(cNE);
@@ -417,13 +420,13 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
if((nextop&0xC0)==0xC0) {
if(opcode==0x81) i32 = F32S; else i32 = F8S;
ed = xEAX+(nextop&7);
emit_and32c(dyn, ninst, ed, i32, x3, x12);
emit_and32c(dyn, ninst, ed, i32, x3, x14);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
MARKLOCK;
LDREX(x1, wback);
emit_and32c(dyn, ninst, x1, i32, x3, x12);
emit_and32c(dyn, ninst, x1, i32, x3, x14);
STREX(x3, x1, wback);
CMPS_IMM8(x3, 0);
B_MARKLOCK(cNE);
@@ -435,7 +438,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
if((nextop&0xC0)==0xC0) {
if(opcode==0x81) i32 = F32S; else i32 = F8S;
ed = xEAX+(nextop&7);
emit_sub32c(dyn, ninst, ed, i32, x3, x12);
emit_sub32c(dyn, ninst, ed, i32, x3, x14);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
@@ -443,16 +446,16 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
B_MARK(cNE);
MARKLOCK;
LDREX(x1, wback);
emit_sub32c(dyn, ninst, x1, i32, x3, x12);
emit_sub32c(dyn, ninst, x1, i32, x3, x14);
STREX(x3, x1, wback);
CMPS_IMM8(x3, 0);
B_MARKLOCK(cNE);
B_NEXT(c__);
MARK; // unaligned! also, not enough
LDR_IMM9(x1, wback, 0);
LDREXB(x12, wback);
BFI(x1, x12, 0, 8); // re-inject
emit_sub32c(dyn, ninst, x1, i32, x3, x12);
LDREXB(x14, wback);
BFI(x1, x14, 0, 8); // re-inject
emit_sub32c(dyn, ninst, x1, i32, x3, x14);
STREXB(x3, x1, wback);
CMPS_IMM8(x3, 0);
B_MARK(cNE);
@@ -465,13 +468,13 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
if((nextop&0xC0)==0xC0) {
if(opcode==0x81) i32 = F32S; else i32 = F8S;
ed = xEAX+(nextop&7);
emit_xor32c(dyn, ninst, ed, i32, x3, x12);
emit_xor32c(dyn, ninst, ed, i32, x3, x14);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
MARKLOCK;
LDREX(x1, wback);
emit_xor32c(dyn, ninst, x1, i32, x3, x12);
emit_xor32c(dyn, ninst, x1, i32, x3, x14);
STREX(x3, x1, wback);
CMPS_IMM8(x3, 0);
B_MARKLOCK(cNE);
@@ -485,9 +488,9 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
if(opcode==0x81) i32 = F32S; else i32 = F8S;
if(i32) {
MOV32(x2, i32);
emit_cmp32(dyn, ninst, ed, x2, x3, x12);
emit_cmp32(dyn, ninst, ed, x2, x3, x14);
} else {
emit_cmp32_0(dyn, ninst, ed, x3, x12);
emit_cmp32_0(dyn, ninst, ed, x3, x14);
}
break;
}
@@ -549,8 +552,8 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
// AL == Eb
GETGB(x1);
if(wb1) {
STREXB(x12, x1, wback);
CMPS_IMM8(x12, 0);
STREXB(x14, x1, wback);
CMPS_IMM8(x14, 0);
B_MARKLOCK(cNE); // write failed, try again
if(!(gb1==xEAX && gb2==0)) {
UXTB(x1, xEAX, 0); // readback AL if needed
@@ -565,7 +568,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
BFI(xEAX, ed, 0, 8);
MARK3;
// done, do the cmp now
emit_cmp8(dyn, ninst, x1, x2, x3, x12);
emit_cmp8(dyn, ninst, x1, x2, x3, x14);
break;
case 0xB1:
INST_NAME("LOCK CMPXCHG Ed, Gd");
@@ -589,22 +592,22 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
// EAX == Ed
if(wback) {
TSTS_IMM8(wback, 3);
STREX_COND(cEQ, x12, gd, wback);
STREXB_COND(cNE, x12, gd, wback);
CMPS_IMM8(x12, 0);
STREX_COND(cEQ, x14, gd, wback);
STREXB_COND(cNE, x14, gd, wback);
CMPS_IMM8(x14, 0);
B_MARKLOCK(cNE);
TSTS_IMM8(wback, 3); // anoying, all those test
STR_IMM9_COND(cNE, gd, wback, 0);
emit_cmp32(dyn, ninst, xEAX, ed, x1, x12);
emit_cmp32(dyn, ninst, xEAX, ed, x1, x14);
} else {
emit_cmp32(dyn, ninst, xEAX, ed, x1, x12);
emit_cmp32(dyn, ninst, xEAX, ed, x1, x14);
MOV_REG(ed, gd);
}
// done
B_MARK3(c__); // not next, in case its called with a LOCK prefix
MARK;
// EAX != Ed
emit_cmp32(dyn, ninst, xEAX, ed, x3, x12);
emit_cmp32(dyn, ninst, xEAX, ed, x3, x14);
MOV_REG(xEAX, ed);
MARK3
break;
@@ -626,15 +629,15 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
ed = x1;
}
AND_IMM8(x2, gd, 0x1f);
MOV_REG_LSR_REG(x12, ed, x2);
ANDS_IMM8(x12, x12, 1);
STR_IMM9(x12, xEmu, offsetof(x86emu_t, flags[F_CF]));
MOV_REG_LSR_REG(x14, ed, x2);
ANDS_IMM8(x14, x14, 1);
BFI(xFlags, x14, F_CF, 1);
B_MARK3(cEQ); // bit already clear, jump to end of instruction
MOVW(x12, 1);
XOR_REG_LSL_REG(ed, ed, x12, x2);
MOVW(x14, 1);
XOR_REG_LSL_REG(ed, ed, x14, x2);
if(wback) {
STREX(x12, ed, wback);
CMPS_IMM8(x12, 0);
STREX(x14, ed, wback);
CMPS_IMM8(x14, 0);
B_MARKLOCK(cNE);
}
MARK3;
@@ -662,8 +665,41 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
MOV_REG_LSR_IMM5(x1, ed, u8);
ed = x1;
}
AND_IMM8(x1, ed, 1);
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
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");
@@ -686,15 +722,15 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
wback = x3;
}
AND_IMM8(x2, gd, 0x1f);
MOV_REG_LSR_REG(x12, ed, x2);
ANDS_IMM8(x12, x12, 1);
STR_IMM9(x12, xEmu, offsetof(x86emu_t, flags[F_CF]));
MOV_REG_LSR_REG(x14, ed, x2);
ANDS_IMM8(x14, x14, 1);
BFI(xFlags, x14, F_CF, 1);
B_MARK3(cEQ); // bit already clear, jump to next instruction
//MOVW(x12, 1); // already 0x01
XOR_REG_LSL_REG(ed, ed, x12, x2);
//MOVW(x14, 1); // already 0x01
XOR_REG_LSL_REG(ed, ed, x14, x2);
if(wback) {
STREX(x12, ed, wback);
CMPS_IMM8(x12, 0);
STREX(x14, ed, wback);
CMPS_IMM8(x14, 0);
B_MARKLOCK(cNE);
}
MARK3;
@@ -721,14 +757,13 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
wback = x3;
}
AND_IMM8(x2, gd, 0x1f);
MOV_REG_LSR_REG(x12, ed, x2);
AND_IMM8(x12, x12, 1);
STR_IMM9(x12, xEmu, offsetof(x86emu_t, flags[F_CF]));
MOVW(x12, 1);
XOR_REG_LSL_REG(ed, ed, x12, x2);
MOV_REG_LSR_REG(x14, ed, x2);
BFI(xFlags, x14, F_CF, 1);
MOVW(x14, 1);
XOR_REG_LSL_REG(ed, ed, x14, x2);
if(wback) {
STREX(x12, ed, wback);
CMPS_IMM8(x12, 0);
STREX(x14, ed, wback);
CMPS_IMM8(x14, 0);
B_MARKLOCK(cNE);
}
break;
@@ -753,10 +788,10 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
ed = x2;
}
BFI(gb1, ed, gb2*8, 8); // gb <- eb
emit_add8(dyn, ninst, ed, gd, x12, x3, 1);
emit_add8(dyn, ninst, ed, gd, x14, x3, 1);
if(wb1) {
STREXB(x12, ed, wback);
CMPS_IMM8(x12, 0);
STREXB(x14, ed, wback);
CMPS_IMM8(x14, 0);
B_MARKLOCK(cNE);
} else {
BFI(wback, ed, wb2*8, 8);
@@ -774,35 +809,31 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
XOR_REG_LSL_IMM5(ed, gd, ed, 0);
XOR_REG_LSL_IMM5(gd, gd, ed, 0);
}
emit_add32(dyn, ninst, ed, gd, x3, x12);
emit_add32(dyn, ninst, ed, gd, 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);
ADD_REG_LSL_IMM5(x12, x1, gd, 0);
STREX(x3, x12, wback);
ADD_REG_LSL_IMM5(x14, x1, gd, 0);
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, x12);
}
MOV_REG(gd, x1);
B_NEXT(c__);
B_MARK2(c__);
MARK;
LDR_IMM9(x1, wback, 0);
LDREXB(x12, wback);
BFI(x1, x12, 0, 8);
ADD_REG_LSL_IMM5(x12, x1, gd, 0);
STREXB(x3, x12, wback);
LDREXB(x14, wback);
BFI(x1, x14, 0, 8);
ADD_REG_LSL_IMM5(x14, x1, gd, 0);
STREXB(x3, x14, wback);
CMPS_IMM8(x3, 0);
B_MARK(cNE);
STR_IMM9(x12, wback, 0);
STR_IMM9(x14, wback, 0);
MARK2;
IFX(X_ALL|X_PEND) {
MOV_REG(x2, x1);
emit_add32(dyn, ninst, x2, gd, x3, x12);
emit_add32(dyn, ninst, x2, gd, x3, x14);
}
MOV_REG(gd, x1);
}
@@ -825,9 +856,9 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
MOV_REG(x2, xEBX);
MOV_REG(x3, xECX);
TSTS_IMM8(wback, 7);
STREXD_COND(cEQ, x12, x2, wback);
STREX_COND(cNE, x12, x2, wback);
CMPS_IMM8(x12, 0);
STREXD_COND(cEQ, x14, x2, wback);
STREX_COND(cNE, x14, x2, wback);
CMPS_IMM8(x14, 0);
B_MARKLOCK(cNE);
TSTS_IMM8(wback, 7);
STR_IMM9_COND(cNE, x3, wback, 4);
@@ -838,7 +869,7 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
MOV_REG(xEDX, x3);
MOVW(x1, 0);
MARK3;
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
BFI(xFlags, x1, F_ZF, 1);
break;
default:
@@ -856,15 +887,27 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
emit_inc32(dyn, ninst, ed, x3, x12);
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, x12);
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
@@ -872,25 +915,37 @@ uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
emit_dec32(dyn, ninst, ed, x3, x12);
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, x12);
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, x12);
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);
+24 -19
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, x12);
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);
}
@@ -507,7 +507,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
VLD1Q_64(v1, ed);
}
u8 = F8;
// only high part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
// only high part need to be shuffled. VTBL only handle 8bits value, so the 16bits shuffles need to be changed in 8bits
u32 = 0;
for (int i=0; i<2; ++i) {
u32 |= (((u8>>(i*2))&3)*2+0)<<(i*16+0);
@@ -570,16 +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);
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
RSB_IMM8(x1, x1, 1);
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
MOVW(x1, d_none);
STR_IMM9(x1, xEmu, offsetof(x86emu_t, df));
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:
@@ -597,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);
+45 -25
View File
@@ -21,28 +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_popf(x86emu_t* emu, uint32_t f)
{
emu->packed_eflags.x32 = (f & 0x3F7FD7) | 0x2; // mask off res2 and res3 and on res1
UnpackFlags(emu);
RESET_FLAGS(emu);
}
void arm_popf16(x86emu_t* emu, uint32_t f)
{
emu->packed_eflags.x32 &= 0xffff0000;
emu->packed_eflags.x32 |= (f & 0x7FD7) | 0x2; // mask off res2 and res3 and on res1
UnpackFlags(emu);
RESET_FLAGS(emu);
}
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);
@@ -71,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;
@@ -121,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)
@@ -132,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;
@@ -144,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)
@@ -266,11 +259,11 @@ void fpu_reset_reg(dynarec_arm_t* dyn)
dyn->fpuused[i]=0;
}
#define F8 *(uint8_t*)(addr++)
#define F32 *(uint32_t*)(addr+=4, addr-4)
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity)
{
#define F8 *(uint8_t*)(addr++)
#define F32 *(uint32_t*)(addr+=4, addr-4)
uint32_t tested = (1<<parity)-1;
if((nextop&0xC0)==0xC0)
@@ -289,7 +282,7 @@ int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, i
return (tmp&tested)?0:1;
}
} else {
if(sib_reg==4)
if(sib_reg==4 && parity<3)
return 0; // simple [reg]
// don't try [reg1 + reg2<<N], unless reg1 is ESP
return ((sib&0x7)==4 && (sib>>6)>=parity)?1:0;
@@ -303,9 +296,36 @@ int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, i
} else {
return 0; //Form [reg1 + reg2<<N + XXXXXX]
}
}
// Do the GETED, but don't emit anything...
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop)
{
if((nextop&0xC0)==0xC0)
return addr;
if(!(nextop&0xC0)) {
if((nextop&7)==4) {
uint8_t sib = F8;
if((sib&0x7)==5) {
addr+=4;
}
} else if((nextop&7)==5) {
addr+=4;
}
} else {
if((nextop&7)==4) {
++addr;
}
if(nextop&0x80) {
addr+=4;
} else {
++addr;
}
}
return addr;
}
#undef F8
#undef F32
}
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn)
{
+3 -2
View File
@@ -3,8 +3,6 @@
typedef struct x86emu_s x86emu_t;
void arm_popf(x86emu_t* emu, uint32_t f);
void arm_popf16(x86emu_t* emu, uint32_t f);
void arm_fstp(x86emu_t* emu, void* p);
void arm_print_armreg(x86emu_t* emu, uintptr_t reg, uintptr_t n);
@@ -25,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);
@@ -53,6 +52,8 @@ void fpu_reset_reg(dynarec_arm_t* dyn);
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity);
// Do the GETED, but don't emit anything...
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
// Is what pointed at addr a native call? And if yes, to what function?
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn);
+159 -253
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"
@@ -153,31 +154,6 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
return addr;
}
// Do the GETED, but don't emit anything...
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop)
{
if(!(nextop&0xC0)) {
if((nextop&7)==4) {
uint8_t sib = F8;
if((sib&0x7)==5) {
addr+=4;
}
} else if((nextop&7)==5) {
addr+=4;
}
} else {
if((nextop&7)==4) {
++addr;
}
if(nextop&0x80) {
addr+=4;
} else {
++addr;
}
}
return addr;
}
/* setup r2 to address pointed by ED, r3 as scratch also fixaddress is an optionnal delta in the range [-absmax, +absmax], with delta&mask==0 to be added to ed for LDR/STR */
uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixaddress, uint32_t absmax, uint32_t mask)
{
@@ -268,181 +244,101 @@ 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)
void jump_to_next(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);
int j32;
MAYUSE(j32);
if(dyn->nolinker==2) {
jump_to_epilog(dyn, ip, reg, ninst);
MESSAGE(LOG_DUMP, "Jump to next\n");
if(reg) {
if(reg!=xEIP) {
MOV_REG(xEIP, reg);
}
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 {
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, x12);
STREXD(x12, x2, x1); // nope, putting back linker & IP in place
// x12 now contain success / falure for write
CMPS_IMM8(x12, 1);
MOV_REG(x12, 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, x12);
STRD_IMM8(x2, x1, 0);
BX(x2);
#endif
} else {
LDR_IMM9(x2, x1, 0);
BX(x2); // jump
}
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 epilog\n");
POP(xESP, 1<<xEIP);
cstack_pop(dyn, ninst, xEIP, x1, x2);
PASS3(void* epilog = arm_epilog);
MOV32_(x2, (uintptr_t)epilog);
BX(x2);
#if 0
} else {
MESSAGE(LOG_DUMP, "Ret epilog with linker\n");
POP(xESP, 1<<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, x12);
STREXD(x12, x2, x1); // nope, putting back linker & IP in place
// x12 now contain success / falure for write
CMPS_IMM8(x12, 1);
MOV_REG(x12, x3); // put back IP in place...
B_MARK(cEQ);
BX(x2); // go to linker
}
#endif
MESSAGE(LOG_DUMP, "Ret next\n");
POP1(xEIP);
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);
#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");
POP(xESP, 1<<xEIP);
POP1(xEIP);
if(n>0xff) {
MOVW(x1, n);
ADD_REG_LSL_IMM5(xESP, xESP, x1, 0);
} else {
ADD_IMM8(xESP, xESP, n);
}
cstack_pop(dyn, ninst, xEIP, x1, x2);
PASS3(void* epilog = arm_epilog);
MOV32_(x2, (uintptr_t)epilog);
BX(x2);
#if 0
} else {
MESSAGE(LOG_DUMP, "Retn epilog with linker\n");
POP(xESP, 1<<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, x12);
STREXD(x12, x2, x1); // nope, putting back linker & IP in place
// x12 now contain success / falure for write
CMPS_IMM8(x12, 1);
MOV_REG(x12, x3); // put back IP in place...
B_MARK(cEQ);
BX(x2); // go to linker
}
#endif
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);
#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)
{
MESSAGE(LOG_DUMP, "IRet epilog\n");
// POP IP
POP(xESP, 1<<xEIP);
POP1(xEIP);
// POP CS
MOVW(x1, offsetof(x86emu_t, segs[_CS]));
POP(xESP, 1<<x2);
POP1(x2);
STRH_REG(x2, xEmu, x1);
MOVW(x1, 0);
STR_IMM9(x1, xEmu, offsetof(x86emu_t, segs_serial[_CS]));
// POP EFLAGS
POP(xESP, (1<<x1));
CALL(arm_popf, -1, (1<<xEIP));
MOVW(x1, d_none);
STR_IMM9(x1, xEmu, offsetof(x86emu_t, df));
POP1(xFlags);
MOV32(x1, 0x3F7FD7);
AND_REG_LSL_IMM5(xFlags, xFlags, x1, 0);
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);
}
void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, uint32_t mask)
void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, uint32_t mask, int saveflags)
{
if(ret!=-2) {
PUSH(xSP, (1<<xEmu) | mask);
}
fpu_pushcache(dyn, ninst, reg);
if(saveflags) {
STR_IMM9(xFlags, xEmu, offsetof(x86emu_t, eflags));
}
MOV32(reg, (uintptr_t)fnc);
BLX(reg);
fpu_popcache(dyn, ninst, reg);
@@ -452,6 +348,10 @@ void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, uint32_t
if(ret!=-2) {
POP(xSP, (1<<xEmu) | mask);
}
if(saveflags) {
LDR_IMM9(xFlags, xEmu, offsetof(x86emu_t, eflags));
}
SET_NODF();
}
void grab_tlsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg)
@@ -460,13 +360,13 @@ void grab_tlsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg)
int32_t j32;
MAYUSE(j32);
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, context));
LDR_IMM9(x12, xEmu, offsetof(x86emu_t, segs_serial[_GS])); // complete check here
LDR_IMM9(x14, xEmu, offsetof(x86emu_t, segs_serial[_GS])); // complete check here
LDR_IMM9(x1, x1, offsetof(box86context_t, sel_serial));
CMPS_REG_LSL_IMM5(x12, x1, 0);
CMPS_REG_LSL_IMM5(x14, x1, 0);
LDR_IMM9_COND(cEQ, reg, xEmu, offsetof(x86emu_t, segs_offs[_GS]));
B_MARKSEG(cEQ);
MOVW(x1, _GS);
call_c(dyn, ninst, GetSegmentBaseEmu, 12, reg, 0);
call_c(dyn, ninst, GetSegmentBaseEmu, x14, reg, 0, 1);
MARKSEG;
MESSAGE(LOG_DUMP, "----TLSData\n");
}
@@ -476,12 +376,12 @@ void grab_fsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg)
int32_t j32;
MAYUSE(j32);
MESSAGE(LOG_DUMP, "Get FS: Offset\n");
LDR_IMM9(x12, xEmu, offsetof(x86emu_t, segs_serial[_FS]));// fast check here
CMPS_IMM8(x12, 0);
LDR_IMM9(x14, xEmu, offsetof(x86emu_t, segs_serial[_FS]));// fast check here
CMPS_IMM8(x14, 0);
LDR_IMM9_COND(cNE, reg, xEmu, offsetof(x86emu_t, segs_offs[_FS]));
B_MARKSEG(cNE);
MOVW(x1, _FS);
call_c(dyn, ninst, GetSegmentBaseEmu, 12, reg, 0);
call_c(dyn, ninst, GetSegmentBaseEmu, x14, reg, 0, 1);
MARKSEG;
MESSAGE(LOG_DUMP, "----FS: Offset\n");
}
@@ -490,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;
@@ -501,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
@@ -526,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;
@@ -547,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)
@@ -556,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)
@@ -569,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)
@@ -635,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
@@ -669,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
@@ -692,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)
@@ -705,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));
@@ -753,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
@@ -784,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
@@ -804,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));
@@ -845,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));
@@ -881,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)
{
@@ -891,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 {
@@ -916,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
@@ -928,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 {
@@ -967,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 {
@@ -1093,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;
@@ -1106,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);
@@ -1121,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) {
@@ -1192,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);
}
+90 -76
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) { \
@@ -179,18 +189,22 @@
#define GBBACK BFI(gb1, gd, gb2*8, 8);
// Get Direction with size Z and based of F_DF flag, on register r ready for LDR/STR fetching
// F_DF is 1<<10, so 1 ROR 11*2 (so F_OF)
#define GETDIR(r, A) \
LDR_IMM9(r, xEmu, offsetof(x86emu_t, flags[F_DF])); \
CMPS_IMM8(r, 1); \
MOVW(r, A); \
RSB_COND_IMM8(cEQ, r, r, 0)
TSTS_IMM8_ROR(xFlags, 1, 0x0b); \
MOVW(r, A); \
RSB_COND_IMM8(cNE, r, r, 0)
// CALL will use x12 for the call address. Return value can be put in ret (unless ret is -1)
// CALL will use x14 for the call address. Return value can be put in ret (unless ret is -1)
// R0 will not be pushed/popd if ret is -2
#define CALL(F, ret, M) call_c(dyn, ninst, F, x12, ret, M)
#define CALL(F, ret, M) call_c(dyn, ninst, F, x14, ret, M, 1)
// CALL_ will use x3 for the call address. Return value can be put in ret (unless ret is -1)
// R0 will not be pushed/popd if ret is -2
#define CALL_(F, ret, M) call_c(dyn, ninst, F, x3, ret, M)
#define CALL_(F, ret, M) call_c(dyn, ninst, F, x3, ret, M, 1)
// CALL_S will use x3 for the call address. Return value can be put in ret (unless ret is -1)
// R0 will not be pushed/popd if ret is -2. Flags are not save/restored
#define CALL_S(F, ret, M) call_c(dyn, ninst, F, x3, ret, M, 0)
#define MARK if(dyn->insts) {dyn->insts[ninst].mark = (uintptr_t)dyn->arm_size;}
#define GETMARK ((dyn->insts)?dyn->insts[ninst].mark:(dyn->arm_size+4))
#define MARK2 if(dyn->insts) {dyn->insts[ninst].mark2 = (uintptr_t)dyn->arm_size;}
@@ -230,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))))
@@ -237,49 +252,40 @@
// 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 */ \
XOR_REG_LSL_IMM5(s2, s2, s2, 0); \
MOVW_COND(cVS, s1, 0b111); /* unordered */ \
MOVW_COND(cEQ, s1, 0b100); /* zero */ \
MOVW_COND(cGT, s1, 0b000); /* greater than */ \
MOVW_COND(cLO, s1, 0b001); /* less than */ \
IFX(X_CF|X_PEND) { \
UBFX(s2, s1, 0, 1); \
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_CF]));\
} \
IFX(X_PF|X_PEND) { \
UBFX(s2, s1, 1, 1); \
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_PF]));\
} \
IFX(X_ZF|X_PEND) { \
UBFX(s2, s1, 2, 1); \
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_ZF]));\
} \
MOVW(s2, d_none); \
STR_IMM9(s2, xEmu, offsetof(x86emu_t, df)); \
IFX(X_OF|X_PEND) { \
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_OF]));\
} \
IFX(X_AF|X_PEND) { \
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_AF]));\
} \
IFX(X_SF|X_PEND) { \
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_SF]));\
} \
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;}
#define SET_DF(S, N) if(N) {MOVW(S, N); STR_IMM9(S, xEmu, offsetof(x86emu_t, df)); dyn->dfnone=0;} else SET_DFNONE(S)
#define SET_NODF() dyn->dfnone = 0
#define SET_DFOK() dyn->dfnone = 1
#ifndef READFLAGS
#define READFLAGS(A) \
@@ -293,6 +299,7 @@
CALL_(UpdateFlags, -1, 0); \
MARKF; \
dyn->state_flags = SF_SET; \
SET_DFOK(); \
}
#endif
#ifndef SETFLAGS
@@ -310,11 +317,11 @@
#ifndef BARRIER_NEXT
#define BARRIER_NEXT(A)
#endif
#define UFLAG_OP1(A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, 0, offsetof(x86emu_t, op1));}
#define UFLAG_OP2(A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, 0, offsetof(x86emu_t, op2));}
#define UFLAG_OP12(A1, A2) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A1, 0, offsetof(x86emu_t, op1));STR_IMM9(A2, 0, offsetof(x86emu_t, op2));}
#define UFLAG_RES(A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, 0, offsetof(x86emu_t, res));}
#define UFLAG_DF(r, A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {MOVW(r, A); STR_IMM9(r, 0, offsetof(x86emu_t, df));}
#define UFLAG_OP1(A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, op1));}
#define UFLAG_OP2(A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, op2));}
#define UFLAG_OP12(A1, A2) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A1, xEmu, offsetof(x86emu_t, op1));STR_IMM9(A2, 0, offsetof(x86emu_t, op2));}
#define UFLAG_RES(A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, res));}
#define UFLAG_DF(r, A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {SET_DF(r, A)}
#define UFLAG_IF if(dyn->insts && dyn->insts[ninst].x86.need_flags)
#ifndef DEFAULT
#define DEFAULT *ok = -1; BARRIER(2)
@@ -332,7 +339,7 @@
#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
#define STEPNAME3(N,M) N##M
@@ -362,10 +369,9 @@ void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
#define dynarecF30F STEPNAME(dynarecF30F)
#define geted STEPNAME(geted_)
#define fakeed STEPNAME(fakeed_)
#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_)
#define iret_to_epilog STEPNAME(iret_to_epilog_)
@@ -432,11 +438,17 @@ void* arm_linker(x86emu_t* emu, void** table, 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)
#define emit_ror32c STEPNAME(emit_ror32c)
#define emit_shrd32c STEPNAME(emit_shrd32c)
#define emit_shld32c STEPNAME(emit_shld32c)
#define emit_pf STEPNAME(emit_pf)
#define x87_do_push STEPNAME(x87_do_push)
#define x87_do_push_empty STEPNAME(x87_do_push_empty)
@@ -449,6 +461,7 @@ void* arm_linker(x86emu_t* emu, void** table, 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)
@@ -458,12 +471,11 @@ void* arm_linker(x86emu_t* emu, void** table, 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)
@@ -473,20 +485,17 @@ void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
/* setup r2 to address pointed by */
uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixedaddress, uint32_t absmax, uint32_t mask);
// Do the GETED, but don't emit anything...
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
/* setup r2 to address pointed by */
uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixedaddress, uint32_t absmax, uint32_t mask);
// 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);
void iret_to_epilog(dynarec_arm_t* dyn, int ninst);
void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, uint32_t mask);
void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, uint32_t mask, int saveflags);
void grab_fsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg);
void grab_tlsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg);
void emit_lock(dynarec_arm_t* dyn, uintptr_t addr, int ninst);
@@ -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,21 +560,27 @@ 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);
void emit_ror32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_shrd32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4);
void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4);
void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
// x87 helper
// cache of the local stack counter, to avoid upadte at every call
void x87_stackcount(dynarec_arm_t* dyn, int ninst, int scratch);
// fpu push. Return the Dd value to be used
int x87_do_push(dynarec_arm_t* dyn, int ninst);
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
@@ -580,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
@@ -598,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
@@ -628,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
+35 -13
View File
@@ -19,26 +19,27 @@
#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;
dyn->dfnone = 0;
fpu_reset(dyn, ninst);
// ok, go now
INIT;
while(ok) {
if(dyn->insts && (ninst>dyn->size)) {dynarec_log(LOG_NONE, "Warning, too many inst treated (%d / %d)\n",ninst, dyn->size);}
ip = addr;
if(dyn->insts && (dyn->insts[ninst].x86.barrier==1)) {
NEW_BARRIER_INST;
@@ -52,7 +53,7 @@ void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
MESSAGE(LOG_DUMP, "TRACE ----\n");
fpu_reflectcache(dyn, ninst, x1, x2, x3);
MOV32(x1, ip);
STM(xEmu, (1<<4)|(1<<5)|(1<<6)|(1<<7)|(1<<8)|(1<<9)|(1<<10)|(1<<11));
STM(xEmu, (1<<xEAX)|(1<<xEBX)|(1<<xECX)|(1<<xEDX)|(1<<xESI)|(1<<xEDI)|(1<<xESP)|(1<<xEBP));
STR_IMM9(x1, xEmu, offsetof(x86emu_t, ip));
MOVW(x2, 1);
CALL(PrintTrace, -1, 0);
@@ -67,23 +68,43 @@ void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
if(dyn->insts && dyn->insts[ninst+1].x86.barrier) {
fpu_purgecache(dyn, ninst, x1, x2, x3);
if(dyn->insts[ninst+1].x86.barrier!=2)
if(dyn->insts[ninst+1].x86.barrier!=2) {
dyn->state_flags = 0;
dyn->dfnone = 0;
}
}
if(!ok && !need_epilog && dyn->insts && (addr < (dyn->start+dyn->isize))) {
ok = 1;
}
if(!ok && !need_epilog && !dyn->insts) { // check if need to continue
uintptr_t next = get_closest_next(dyn, addr);
if(next && ((next-addr)<15) && is_nops(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)<15) {
dynarec_log(LOG_DEBUG, "Cannot extend block %p -> %p (%02X %02X %02X %02X %02X)\n", (void*)addr, (void*)next, PK(0), PK(1), PK(2), PK(3), PK(4));
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);
@@ -91,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;
}
+4 -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,12 @@ 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;
int next_cap;
@@ -54,5 +53,6 @@ typedef struct dynarec_arm_s {
void add_next(dynarec_arm_t *dyn, uintptr_t addr);
uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr);
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n);
int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n);
#endif //__DYNAREC_ARM_PRIVATE_H_
-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;
}
+214 -71
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,6 +28,8 @@
#include "callback.h"
#include "dynarec.h"
#include "box86stack.h"
#include "custommem.h"
#include "wine_tools.h"
#ifdef DYNAREC
#include "dynablock.h"
#endif
@@ -64,10 +67,10 @@ void FreeElfHeader(elfheader_t** head)
return;
elfheader_t *h = *head;
#ifdef DYNAREC
if(h->text) {
/*if(h->text) {
dynarec_log(LOG_INFO, "Free Dynarec block for %s\n", h->path);
cleanDBFromAddressRange(my_context, h->text, h->textsz, 1);
}
}*/ // will be free at the end, no need to free it now
#endif
free(h->name);
free(h->path);
@@ -180,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)
@@ -195,17 +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;
}
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;
@@ -215,12 +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;
}
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;
@@ -264,13 +293,14 @@ int LoadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
printf_log(LOG_NONE, "Fail to read PT_LOAD part #%d (size=%d)\n", i, e->p_filesz);
return 1;
}
}
#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(context, (uintptr_t)dest, e->p_memsz, 0);
}
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);
}
#endif
}
// zero'd difference between filesz and memsz
/*if(e->p_filesz != e->p_memsz)
memset(dest+e->p_filesz, 0, e->p_memsz - e->p_filesz);*/ //block is already 0'd at creation
@@ -303,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;
@@ -321,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)
{
@@ -334,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;
@@ -345,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:
@@ -381,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);
@@ -391,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:
@@ -464,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))
) {
@@ -476,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;
@@ -581,7 +691,7 @@ int RelocateElfPlt(lib_t *maplib, lib_t *local_maplib, elfheader_t* head)
return -1;
}
if(pltResolver==~0) {
pltResolver = AddBridge(my_context->system, my_context, vFE, PltResolver, 0);
pltResolver = AddBridge(my_context->system, vFE, PltResolver, 0);
}
if(head->pltgot) {
*(uintptr_t*)(head->pltgot+head->delta+8) = pltResolver;
@@ -610,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;
@@ -624,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;
@@ -688,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;
@@ -713,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;
@@ -745,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
@@ -765,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);
@@ -783,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...
@@ -862,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);
}
@@ -875,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)
@@ -1007,8 +1136,8 @@ dynablocklist_t* GetDynablocksFromAddress(box86context_t *context, uintptr_t add
return ret;
}*/
if(box86_dynarec_forced) {
addDBFromAddressRange(my_context, addr, 1, 1);
return my_context->dynmap[addr>>DYNAMAP_SHIFT];
addDBFromAddressRange(addr, 1);
return getDB(addr>>DYNAMAP_SHIFT);
}
//check if address is in an elf... if yes, grant a block (should I warn)
Dl_info info;
@@ -1159,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;
}
+4 -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,10 +141,11 @@
#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
#define GET_EW GET_ED
#define GET_EW_OFFS GET_ED_OFFS
#define EW ED
#define GW GD
+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;
+45 -7
View File
@@ -2,16 +2,29 @@
goto *opcodes66[opcode];
#define GO(B, OP) \
_66_##B##_0: \
nextop = F8; \
GET_EB; \
EB->byte[0] = OP##8(emu, EB->byte[0], GB); \
NEXT; \
_66_##B##_1: \
nextop = F8; \
GET_EW; \
EW->word[0] = OP##16(emu, EW->word[0], GW.word[0]); \
NEXT; \
_66_##B##_2: \
nextop = F8; \
GET_EB; \
GB = OP##8(emu, GB, EB->byte[0]); \
NEXT; \
_66_##B##_3: \
nextop = F8; \
GET_EW; \
GW.word[0] = OP##16(emu, GW.word[0], EW->word[0]); \
NEXT; \
_66_##B##_4: \
R_AL = OP##8(emu, R_AL, F8); \
NEXT; \
_66_##B##_5: \
R_AX = OP##16(emu, R_AX, F16); \
NEXT;
@@ -41,6 +54,11 @@
if(emu->quit) goto fini;
STEP
NEXT;
_66_0x1F: /* POP DS */
emu->segs[_DS] = Pop16(emu); // no check, no use....
emu->segs_serial[_DS] = 0;
NEXT;
_66_0x26: /* ES: */
// ignored
@@ -135,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
@@ -247,15 +272,12 @@
_66_0x9C: /* PUSHFW */
CHECK_FLAGS(emu);
PackFlags(emu);
Push16(emu, (uint16_t)emu->packed_eflags.x32);
Push16(emu, (uint16_t)emu->eflags.x32);
NEXT;
_66_0x9D: /* POPFW */
CHECK_FLAGS(emu);
PackFlags(emu);
emu->packed_eflags.x32 &=0xffff0000;
emu->packed_eflags.x32 |= (Pop16(emu) & 0x3F7FD7) | 0x2;
UnpackFlags(emu);
emu->eflags.x32 &=0xffff0000;
emu->eflags.x32 |= (Pop16(emu) & 0x3F7FD7) | 0x2;
NEXT;
_66_0xA1: /* MOV AX,Ow */
@@ -333,6 +355,22 @@
EW->word[0] = F16;
NEXT;
_66_0xCB: /* FAR RET */
ip = Pop(emu);
emu->segs[_CS] = Pop(emu); // no check, no use....
emu->segs_serial[_CS] = 0;
// need to check status of CS register!
STEP
NEXT;
_66_0xCC: /* INT3 */
emu->old_ip = R_EIP;
R_EIP = ip-1;
if(my_context->signals[SIGTRAP])
raise(SIGTRAP);
ip = R_EIP;
if(emu->quit) goto fini;
STEP
NEXT;
_66_0xD1: /* GRP2 Ew,1 */
_66_0xD3: /* GRP2 Ew,CL */
nextop = F8;
@@ -370,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;
+53 -35
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,13 @@
#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
typedef struct cleanup_s {
void* f;
@@ -34,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(context, (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)
@@ -60,8 +66,7 @@ static void internalX86Setup(x86emu_t* emu, box86context_t *context, uintptr_t s
emu->sbiidx[i] = &emu->regs[i];
emu->sbiidx[4] = &emu->zero;
emu->x86emu_parity_tab = x86emu_parity_tab;
emu->packed_eflags.x32 = 0x202; // default flags?
UnpackFlags(emu);
emu->eflags.x32 = 0x202; // default flags?
// own stack?
emu->stack2free = (ownstack)?(void*)stack:NULL;
emu->init_stack = (void*)stack;
@@ -76,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
@@ -165,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
@@ -177,7 +186,7 @@ void FreeX86Emu(x86emu_t **emu)
{
if(!emu)
return;
printf_log(LOG_DEBUG, "Free a X86 Emu (%p)\n", *emu);
printf_log(LOG_DEBUG, "%04d|Free a X86 Emu (%p)\n", GetTID(), *emu);
internalFreeX86(*emu);
@@ -189,7 +198,7 @@ void FreeX86EmuFromStack(x86emu_t **emu)
{
if(!emu)
return;
printf_log(LOG_DEBUG, "Free a X86 Emu from stack (%p)\n", *emu);
printf_log(LOG_DEBUG, "%04d|Free a X86 Emu from stack (%p)\n", GetTID(), *emu);
internalFreeX86(*emu);
}
@@ -198,12 +207,11 @@ void CloneEmu(x86emu_t *newemu, const x86emu_t* emu)
{
memcpy(newemu->regs, emu->regs, sizeof(emu->regs));
memcpy(&newemu->ip, &emu->ip, sizeof(emu->ip));
memcpy(&newemu->packed_eflags, &emu->packed_eflags, sizeof(emu->packed_eflags));
memcpy(&newemu->flags, &emu->flags, sizeof(emu->flags));
memcpy(&newemu->eflags, &emu->eflags, sizeof(emu->eflags));
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));
@@ -213,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;
@@ -301,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, " ");
}
@@ -317,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;
@@ -351,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)
@@ -360,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;
@@ -436,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)
@@ -456,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
}
@@ -473,4 +491,4 @@ void ResetSegmentsCache(x86emu_t *emu)
if(!emu)
return;
memset(emu->segs_serial, 0, sizeof(emu->segs_serial));
}
}
+8 -15
View File
@@ -25,22 +25,20 @@ typedef struct forkpty_s {
typedef struct x86emu_s {
// cpu
reg32_t regs[8],ip;
int flags[F_LAST];
x86flags_t packed_eflags;
reg32_t regs[8];
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];
+42 -21
View File
@@ -9,6 +9,7 @@
#include <sys/syscall.h>
#include <sys/types.h>
#include <pthread.h>
#include <signal.h>
#include "debug.h"
#include "box86stack.h"
@@ -120,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;
@@ -155,31 +156,34 @@ void x86Int3(x86emu_t* emu)
snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"), %i(%c))", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+4), *(int32_t*)(R_ESP+8), *(int32_t*)(R_ESP+8));
} else if(strstr(s, "rindex")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"), %i(%c))", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+4), *(int32_t*)(R_ESP+8), *(int32_t*)(R_ESP+8));
} else if(strstr(s, "__xstat64")==s) {
} else if(strstr(s, "my___xstat64")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p(\"%s\"), %p)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(char**)(R_ESP+8), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
perr = 1;
} else if(strcmp(s, "__xstat")==0) {
} else if(strcmp(s, "my___xstat")==0) {
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p(\"%s\"), %p)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(char**)(R_ESP+8), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
perr = 1;
} else if(strstr(s, "__lxstat64")==s) {
} else if(strstr(s, "my___lxstat64")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p(\"%s\"), %p)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(char**)(R_ESP+8), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
perr = 1;
} else if(strstr(s, "sem_timedwait")==s) {
pu32 = *(uint32_t**)(R_ESP+8);
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %p[%d sec %d ns])", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(void**)(R_ESP+8), pu32?pu32[0]:-1, pu32?pu32[1]:-1);
perr = 1;
} else if(strstr(s, "waitpid")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p, 0x%x)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(void**)(R_ESP+8), *(uint32_t*)(R_ESP+12));
perr = 1;
} else if(strstr(s, "clock_gettime")==s || strstr(s, "__clock_gettime")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(void**)(R_ESP+8));
post = 1;
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, "mmap64")) {
} 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));
perr = 1;
} else if(!strcmp(s, "mmap")) {
} else if(!strcmp(s, "my_mmap")) {
snprintf(buff, 255, "%04d|%p: Calling %s(%p, 0x%x, %d, 0x%x, %d, %d)", 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), *(int*)(R_ESP+24));
perr = 1;
} else if(strstr(s, "strcasecmp")==s || strstr(s, "__strcasecmp")==s) {
@@ -192,40 +196,54 @@ void x86Int3(x86emu_t* emu)
snprintf(buff, 255, "%04d|%p: Calling %s(\"%.127s\", \"%.127s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
} else if(strstr(s, "strlen")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"))", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), ((R_ESP+4))?(*(char**)(R_ESP+4)):"nil");
} else if(strstr(s, "vsnprintf")==s) {
} else if(strstr(s, "my_vsnprintf")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, %u, %08X...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(uint32_t*)(R_ESP+8), *(uint32_t*)(R_ESP+12));
pu32 = *(uint32_t**)(R_ESP+4);
post = 3;
} else if(strstr(s, "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));
} else if(strstr(s, "my_vsprintf")==s) {
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, "snprintf")==s) {
} 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) {
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, %u, %08X...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(uint32_t*)(R_ESP+8), *(uint32_t*)(R_ESP+12));
pu32 = *(uint32_t**)(R_ESP+4);
post = 3;
} else if(strstr(s, "sprintf")==s) {
} else if(strstr(s, "my_sprintf")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, %08X...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(uint32_t*)(R_ESP+8));
pu32 = *(uint32_t**)(R_ESP+4);
post = 3;
} else if(strstr(s, "printf")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\"...)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4));
} else if(strstr(s, "my_printf")==s) {
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) {
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, \"%s\"...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(char**)(R_ESP+8));
} else if(strstr(s, "fprintf")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %p...)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(void**)(R_ESP+8));
} else if(strstr(s, "my_fprintf")==s) {
pu32 = *(uint32_t**)(R_ESP+8);
if(((uintptr_t)pu32)<0x5) // probably a __fprint_chk
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, "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));
} else if(strstr(s, "my_vfprintf")==s) {
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, "sscanf")==s) {
} 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(!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));
@@ -245,7 +263,7 @@ void x86Int3(x86emu_t* emu)
} else if(strstr(s, "udev_monitor_new_from_netlink")==s) {
post = 5;
snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\")", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(char**)(R_ESP+8));
} else if(!strcmp(s, "syscall")) {
} else if(!strcmp(s, "my_syscall")) {
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p, %p, %p...)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(void**)(R_ESP+8), *(void**)(R_ESP+12), *(void**)(R_ESP+16));
perr = 1;
} else {
@@ -285,7 +303,10 @@ void x86Int3(x86emu_t* emu)
}
return;
}
printf_log(LOG_INFO, "Warning, ignoring unsupported Int 3 call\n");
if(0 && my_context->signals[SIGTRAP])
raise(SIGTRAP);
else
printf_log(LOG_INFO, "%04d|Warning, ignoring unsupported Int 3 call @%p\n", GetTID(), (void*)R_EIP);
//emu->quit = 1;
}
+60 -30
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,23 +131,23 @@ 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] = {
&&_default, &&_66_0x00_1, &&_default, &&_66_0x00_3, &&_default ,&&_66_0x00_5, &&_66_0x06, &&_66_0x07, //0x00-0x07
&&_default, &&_66_0x08_1, &&_default, &&_66_0x08_3, &&_default ,&&_66_0x08_5, &&_default, &&_66_0x0F, //0x08-0x0F
&&_default, &&_66_0x10_1, &&_default, &&_66_0x10_3, &&_default ,&&_66_0x10_5, &&_default, &&_default, //0x10-0x17
&&_default, &&_66_0x18_1, &&_default, &&_66_0x18_3, &&_default ,&&_66_0x18_5, &&_default, &&_default, //0x18-0x1F
&&_default, &&_66_0x20_1, &&_default, &&_66_0x20_3, &&_default ,&&_66_0x20_5, &&_66_0x26, &&_default, //0x20-0x27
&&_default, &&_66_0x28_1, &&_default, &&_66_0x28_3, &&_default ,&&_66_0x28_5, &&_66_0x2E, &&_default, //0x28-0x2F
&&_default, &&_66_0x30_1, &&_default, &&_66_0x30_3, &&_default ,&&_66_0x30_5, &&_66_0x36, &&_default, //0x30-0x37
&&_66_0x00_0, &&_66_0x00_1, &&_66_0x00_2, &&_66_0x00_3, &&_66_0x00_4 ,&&_66_0x00_5, &&_66_0x06, &&_66_0x07, //0x00-0x07
&&_66_0x08_0, &&_66_0x08_1, &&_66_0x08_2, &&_66_0x08_3, &&_66_0x08_4 ,&&_66_0x08_5, &&_default, &&_66_0x0F, //0x08-0x0F
&&_66_0x10_0, &&_66_0x10_1, &&_66_0x10_2, &&_66_0x10_3, &&_66_0x10_4 ,&&_66_0x10_5, &&_default, &&_default, //0x10-0x17
&&_66_0x18_0, &&_66_0x18_1, &&_66_0x18_2, &&_66_0x18_3, &&_66_0x18_4 ,&&_66_0x18_5, &&_default, &&_66_0x1F, //0x18-0x1F
&&_66_0x20_0, &&_66_0x20_1, &&_66_0x20_2, &&_66_0x20_3, &&_66_0x20_4 ,&&_66_0x20_5, &&_66_0x26, &&_default, //0x20-0x27
&&_66_0x28_0, &&_66_0x28_1, &&_66_0x28_2, &&_66_0x28_3, &&_66_0x28_4 ,&&_66_0x28_5, &&_66_0x2E, &&_default, //0x28-0x2F
&&_66_0x30_0, &&_66_0x30_1, &&_66_0x30_2, &&_66_0x30_3, &&_66_0x30_4 ,&&_66_0x30_5, &&_66_0x36, &&_default, //0x30-0x37
&&_default, &&_66_0x39, &&_default, &&_66_0x3B, &&_default, &&_66_0x3D, &&_default, &&_default, //0x38-0x3F
&&_66_0x40, &&_66_0x41, &&_66_0x42, &&_66_0x43, &&_66_0x44, &&_66_0x45, &&_66_0x46, &&_66_0x47,
&&_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
@@ -159,7 +160,7 @@ int Run(x86emu_t *emu, int step)
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xB0-0xB7
&&_66_0xB8, &&_66_0xB9, &&_66_0xBA, &&_66_0xBB, &&_66_0xBC, &&_66_0xBD, &&_66_0xBE, &&_66_0xBF,
&&_default, &&_66_0xC1, &&_default, &&_default, &&_default, &&_default, &&_default, &&_66_0xC7,
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xC8-0xCF
&&_default, &&_default, &&_default, &&_66_0xCB, &&_66_0xCC ,&&_default, &&_default, &&_default, //0xC8-0xCF
&&_default, &&_66_0xD1, &&_default, &&_66_0xD3, &&_default, &&_default, &&_default, &&_default, //0xD0-0xD7
&&_default, &&_66_0xD9, &&_default, &&_default, &&_default ,&&_66_0xDD, &&_default, &&_default, //0xD8-0xDF
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xE0-0xE7
@@ -170,7 +171,6 @@ int Run(x86emu_t *emu, int step)
x86emurun:
ip = R_EIP;
// UnpackFlags(emu);
#ifdef HAVE_TRACE
_trace:
__builtin_prefetch((void*)ip, 0, 0);
@@ -702,8 +702,15 @@ _trace:
NEXT;
_0x8F: /* POP Ed */
nextop = F8;
GET_ED;
ED->dword[0] = Pop(emu);
if((nextop&0xC0)==0xC0) {
emu->regs[(nextop&7)].dword[0] = Pop(emu);
} else {
tmp32u = Pop(emu); // this order allows handling POP [ESP] and variant
GET_ED;
R_ESP -= 4; // to prevent issue with SEGFAULT
ED->dword[0] = tmp32u;
R_ESP += 4;
}
NEXT;
_0x90: /* NOP */
NEXT;
@@ -730,12 +737,10 @@ _trace:
NEXT;
_0x9C: /* PUSHF */
CHECK_FLAGS(emu);
PackFlags(emu);
Push(emu, emu->packed_eflags.x32);
Push(emu, emu->eflags.x32);
NEXT;
_0x9D: /* POPF */
emu->packed_eflags.x32 = ((Pop(emu) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1
UnpackFlags(emu);
emu->eflags.x32 = ((Pop(emu) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1
RESET_FLAGS(emu);
NEXT;
_0x9E: /* SAHF */
@@ -749,8 +754,7 @@ _trace:
NEXT;
_0x9F: /* LAHF */
CHECK_FLAGS(emu);
PackFlags(emu);
R_AH = (uint8_t)emu->packed_eflags.x32;
R_AH = (uint8_t)emu->eflags.x32;
NEXT;
_0xA0: /* MOV AL,Ob */
@@ -917,7 +921,6 @@ _trace:
GET_ED;
ED->dword[0] = F32;
NEXT;
_0xC8: /* ENTER Iw,Ib */
tmp16u = F16;
tmp8u = (F8) & 0x1f;
@@ -933,7 +936,6 @@ _trace:
}
R_ESP -= tmp16u;
NEXT;
_0xC9: /* LEAVE */
R_ESP = R_EBP;
R_EBP = Pop(emu);
@@ -976,8 +978,7 @@ _trace:
ip = Pop(emu);
emu->segs[_CS] = Pop(emu);
emu->segs_serial[_CS] = 0;
emu->packed_eflags.x32 = ((Pop(emu) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1
UnpackFlags(emu);
emu->eflags.x32 = ((Pop(emu) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1
RESET_FLAGS(emu);
NEXT;
_0xD0: /* GRP2 Eb,1 */
@@ -1243,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:
@@ -1259,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:
@@ -1422,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);
@@ -1434,7 +1462,8 @@ _trace:
switch((nextop>>3)&7) {
case 0:
case 1: /* TEST Eb,Ib */
test8(emu, EB->byte[0], F8);
tmp8u = F8;
test8(emu, EB->byte[0], tmp8u);
break;
case 2: /* NOT Eb */
EB->byte[0] = not8(emu, EB->byte[0]);
@@ -1462,7 +1491,8 @@ _trace:
switch((nextop>>3)&7) {
case 0:
case 1: /* TEST Ed,Id */
test32(emu, ED->dword[0], F32);
tmp32u = F32;
test32(emu, ED->dword[0], tmp32u);
break;
case 2: /* NOT Ed */
ED->dword[0] = not32(emu, ED->dword[0]);
+267 -32
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;
@@ -288,16 +298,32 @@ void RunLock(x86emu_t *emu)
nextop = F8;
GET_ED;
#ifdef DYNAREC
do {
tmp32u = arm_lock_read_d(ED);
cmp32(emu, R_EAX, tmp32u);
if(ACCESS_FLAG(F_ZF)) {
tmp32s = arm_lock_write_d(ED, GD.dword[0]);
} else {
R_EAX = tmp32u;
tmp32s = 0;
}
} while(tmp32s);
if(((uintptr_t)ED)&3) {
do {
tmp32u = ED->dword[0] & ~0xff;
tmp32u |= arm_lock_read_b(ED);
cmp32(emu, R_EAX, tmp32u);
if(ACCESS_FLAG(F_ZF)) {
tmp32s = arm_lock_write_b(ED, GD.dword[0] & 0xff);
if(!tmp32s)
ED->dword[0] = GD.dword[0];
} else {
R_EAX = tmp32u;
tmp32s = 0;
}
} while(tmp32s);
} else {
do {
tmp32u = arm_lock_read_d(ED);
cmp32(emu, R_EAX, tmp32u);
if(ACCESS_FLAG(F_ZF)) {
tmp32s = arm_lock_write_d(ED, GD.dword[0]);
} else {
R_EAX = tmp32u;
tmp32s = 0;
}
} while(tmp32s);
}
#else
pthread_mutex_lock(&emu->context->mutex_lock);
cmp32(emu, R_EAX, ED->dword[0]);
@@ -365,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 */
@@ -400,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;
@@ -455,10 +513,19 @@ void RunLock(x86emu_t *emu)
nextop = F8;
GET_ED;
#ifdef DYNAREC
do {
tmp32u = arm_lock_read_d(ED);
tmp32u2 = add32(emu, tmp32u, GD.dword[0]);
} while(arm_lock_write_d(ED, tmp32u2));
if(((uintptr_t)ED)&3) {
do {
tmp32u = ED->dword[0] & ~0xff;
tmp32u |= arm_lock_read_b(ED);
tmp32u2 = add32(emu, tmp32u, GD.dword[0]);
} while(arm_lock_write_b(ED, tmp32u2&0xff));
ED->dword[0] = tmp32u2;
} else {
do {
tmp32u = arm_lock_read_d(ED);
tmp32u2 = add32(emu, tmp32u, GD.dword[0]);
} while(arm_lock_write_d(ED, tmp32u2));
}
GD.dword[0] = tmp32u;
#else
pthread_mutex_lock(&emu->context->mutex_lock);
@@ -529,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;
@@ -589,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]);
@@ -600,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]);
@@ -626,12 +718,16 @@ void RunLock(x86emu_t *emu)
void RunLock66(x86emu_t *emu)
{
uintptr_t ip = R_EIP+1;
uintptr_t ip = R_EIP+2;
uint8_t opcode = F8;
uint8_t nextop;
reg32_t *oped;
uint16_t tmp16u;
int16_t tmp16s;
#ifdef DYNAREC
uint16_t tmp16u2;
int32_t tmp32s;
#endif
switch(opcode) {
case 0x0f:
opcode = F8;
@@ -667,6 +763,41 @@ void RunLock66(x86emu_t *emu)
UnimpOpcode(emu);
}
break;
case 0x81: /* GRP Ed,Iw */
case 0x83: /* GRP Ed,Ib */
nextop = F8;
GET_EW;
if(opcode==0x83) {
tmp16s = F8S;
tmp16u = (uint32_t)tmp16s;
} else
tmp16u = F16;
#ifdef DYNAREC
switch((nextop>>3)&7) {
case 0: do { tmp16u2 = arm_lock_read_h(EW);} while(arm_lock_write_h(EW, add16(emu, tmp16u2, tmp16u))); break;
case 1: do { tmp16u2 = arm_lock_read_h(EW);} while(arm_lock_write_h(EW, or16(emu, tmp16u2, tmp16u))); break;
case 2: do { tmp16u2 = arm_lock_read_h(EW);} while(arm_lock_write_h(EW, adc16(emu, tmp16u2, tmp16u))); break;
case 3: do { tmp16u2 = arm_lock_read_h(EW);} while(arm_lock_write_h(EW, sbb16(emu, tmp16u2, tmp16u))); break;
case 4: do { tmp16u2 = arm_lock_read_h(EW);} while(arm_lock_write_h(EW, and16(emu, tmp16u2, tmp16u))); break;
case 5: do { tmp16u2 = arm_lock_read_h(EW);} while(arm_lock_write_h(EW, sub16(emu, tmp16u2, tmp16u))); break;
case 6: do { tmp16u2 = arm_lock_read_h(EW);} while(arm_lock_write_h(EW, xor16(emu, tmp16u2, tmp16u))); break;
case 7: cmp16(emu, ED->dword[0], tmp16u); break;
}
#else
pthread_mutex_lock(&emu->context->mutex_lock);
switch((nextop>>3)&7) {
case 0: EW->word[0] = add16(emu, EW->word[0], tmp16u); break;
case 1: EW->word[0] = or16(emu, EW->word[0], tmp16u); break;
case 2: EW->word[0] = adc16(emu, EW->word[0], tmp16u); break;
case 3: EW->word[0] = sbb16(emu, EW->word[0], tmp16u); break;
case 4: EW->word[0] = and16(emu, EW->word[0], tmp16u); break;
case 5: EW->word[0] = sub16(emu, EW->word[0], tmp16u); break;
case 6: EW->word[0] = xor16(emu, EW->word[0], tmp16u); break;
case 7: cmp16(emu, EW->word[0], tmp16u); break;
}
pthread_mutex_unlock(&emu->context->mutex_lock);
#endif
break;
default:
ip-=3; // unfetch nextop, F0 & 66
UnimpOpcode(emu);
@@ -698,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);
@@ -715,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
@@ -854,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;
@@ -871,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) {
@@ -893,7 +1067,7 @@ void RunGS(x86emu_t *emu)
}
break;
default:
ip--;
ip=R_EIP;
UnimpOpcode(emu);
}
R_EIP = ip;
@@ -964,9 +1138,19 @@ void RunFS(x86emu_t *emu)
--ip; // so ignore prefix and continue
break;
case 0x66:
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);
@@ -1001,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;
@@ -1080,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);
@@ -1140,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;
@@ -1157,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 {
@@ -1180,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;
}
+352 -349
View File
File diff suppressed because it is too large. Load diff
+23 -63
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)
{
@@ -685,64 +704,6 @@ void UpdateFlags(x86emu_t *emu)
RESET_FLAGS(emu);
}
void PackFlags(x86emu_t* emu)
{
#define GO(A) emu->packed_eflags.f.F__##A = emu->flags[F_##A];
#define GOC(A, C) emu->packed_eflags.f.F__##A = C;
GO(CF);
GOC(res1, 1);
GO(PF);
GOC(res2, 0);
GO(AF);
GOC(res3, 0);
GO(ZF);
GO(SF);
GO(TF);
GO(IF);
GO(DF);
GO(OF);
GO(IOPL);
GO(NT);
GOC(dummy, 0);
GO(RF);
GO(VM);
GO(AC);
GO(VIF);
GO(VIP);
GO(ID);
#undef GO
#undef GOC
}
void UnpackFlags(x86emu_t* emu)
{
#define GO(A) emu->flags[F_##A] = emu->packed_eflags.f.F__##A;
#define GOC(A, C) emu->flags[F_##A] = C;
GO(CF);
GOC(res1, 1);
GO(PF);
GOC(res2, 0);
GO(AF);
GOC(res3, 0);
GO(ZF);
GO(SF);
GO(TF);
GO(IF);
GO(DF);
GO(OF);
GO(IOPL);
GO(NT);
GOC(dummy, 0);
GO(RF);
GO(VM);
GO(AC);
GO(VIF);
GO(VIP);
GO(ID);
#undef GO
#undef GOC
}
uintptr_t GetSegmentBaseEmu(x86emu_t* emu, int seg)
{
if(emu->segs_serial[seg] != emu->context->sel_serial) {
@@ -807,7 +768,6 @@ void PrintTrace(x86emu_t* emu, uintptr_t ip, int dynarec)
my_context->trace_tid = tid;
}
#endif
trace_end = 0;
printf_log(LOG_NONE, "%s", DumpCPURegs(emu, ip));
if(PK(0)==0xcc && PK(1)=='S' && PK(2)=='C') {
uint32_t a = *(uint32_t*)(ip+3);
+8 -8
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);
@@ -208,13 +210,11 @@ void x86Syscall(x86emu_t *emu);
void x86Int3(x86emu_t* emu);
x86emu_t* x86emu_fork(x86emu_t* e, int forktype);
void PackFlags(x86emu_t* emu);
void UnpackFlags(x86emu_t* emu);
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);
+41 -5
View File
@@ -68,6 +68,10 @@ int32_t my_epoll_wait(x86emu_t* emu, int32_t epfd, void* events, int32_t maxeven
#endif
int my_sigaction(x86emu_t* emu, int signum, const x86_sigaction_t *act, x86_sigaction_t *oldact);
int32_t my_execve(x86emu_t* emu, const char* path, char* const argv[], char* const envp[]);
void* my_mmap(x86emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, int offset);
void* my_mmap64(x86emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, int64_t offset);
int my_munmap(x86emu_t* emu, void* addr, unsigned long length);
int my_mprotect(x86emu_t* emu, void *addr, unsigned long len, int prot);
// cannot include <fcntl.h>, it conflict with some asm includes...
#ifndef O_NONBLOCK
@@ -129,7 +133,7 @@ scwrap_t syscallwrap[] = {
{ 82, __NR_select, 5 },
#endif
{ 85, __NR_readlink, 3 },
{ 91, __NR_munmap, 2 },
//{ 91, __NR_munmap, 2 },
{ 94, __NR_fchmod, 2 },
{ 99, __NR_statfs, 2 },
#ifdef __NR_socketcall
@@ -166,7 +170,7 @@ scwrap_t syscallwrap[] = {
//{ 120, __NR_clone, 5 }, // need works
//{ 122, __NR_uname, 1 },
//{ 123, __NR_modify_ldt },
{ 125, __NR_mprotect, 3 },
//{ 125, __NR_mprotect, 3 },
{ 136, __NR_personality, 1 },
{ 140, __NR__llseek, 5 },
{ 141, __NR_getdents, 3 },
@@ -190,15 +194,24 @@ scwrap_t syscallwrap[] = {
{ 183, __NR_getcwd, 2 },
{ 186, __NR_sigaltstack, 2 }, // neeed wrap or something?
{ 191, __NR_ugetrlimit, 2 },
{ 192, __NR_mmap2, 6},
// { 192, __NR_mmap2, 6},
//{ 195, __NR_stat64, 2 }, // need proprer wrap because of structure size change
//{ 196, __NR_lstat64, 2 }, // need proprer wrap because of structure size change
//{ 197, __NR_fstat64, 2 }, // need proprer wrap because of structure size change
#ifndef POWERPCLE
{ 199, __NR_getuid32, 0 },
{ 200, __NR_getgid32, 0 },
{ 201, __NR_geteuid32, 0 },
{ 202, __NR_getegid32, 0 },
{ 208, __NR_setresuid32, 3 },
#else
// PowerPC uses the same syscalls for 32/64 bit processes.
{ 199, __NR_getuid, 0 },
{ 200, __NR_getgid, 0 },
{ 201, __NR_geteuid, 0 },
{ 202, __NR_getegid, 0 },
{ 208, __NR_setresuid, 3 },
#endif
{ 220, __NR_getdents64, 3 },
//{ 221, __NR_fcntl64, 3 },
{ 224, __NR_gettid, 0 },
@@ -215,11 +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
@@ -396,9 +415,12 @@ void EXPORT x86Syscall(x86emu_t *emu)
case 90: // old_mmap
{
struct mmap_arg_struct *st = (struct mmap_arg_struct*)R_EBX;
R_EAX = (uintptr_t)mmap((void*)st->addr, st->len, st->prot, st->flags, st->fd, st->offset);
R_EAX = (uintptr_t)my_mmap(emu, (void*)st->addr, st->len, st->prot, st->flags, st->fd, st->offset);
}
break;
case 91: // munmap
R_EAX = my_munmap(emu, (void*)R_EBX, (unsigned long)R_ECX);
break;
#ifndef __NR_socketcall
case 102: {
unsigned long *args = (unsigned long *)R_ECX;
@@ -459,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;
@@ -466,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);
@@ -510,6 +534,9 @@ void EXPORT x86Syscall(x86emu_t *emu)
case 123: // SYS_modify_ldt
R_EAX = my_modify_ldt(emu, R_EBX, (thread_area_t*)R_ECX, R_EDX);
break;
case 125: // mprotect
R_EAX = my_mprotect(emu, (void*)R_EBX, (unsigned long)R_ECX, R_EDX);
break;
case 168: // sys_poll
R_EAX = (uint32_t)poll((void*)R_EBX, R_ECX, (int)R_EDX);
break;
@@ -526,6 +553,9 @@ void EXPORT x86Syscall(x86emu_t *emu)
R_EAX = r;
}
break;
case 192: // mmap2
R_EAX = (uint32_t)my_mmap64(emu, (void*)R_EBX, (unsigned long)R_ECX, R_EDX, R_ESI, R_EDI, R_EBP);
break;
case 195: // stat64
{
struct stat64 st;
@@ -644,10 +674,16 @@ uint32_t EXPORT my_syscall(x86emu_t *emu)
return (uint32_t)close(i32(4));
case 11: // execve
return (uint32_t)my_execve(emu, p(4), p(8), p(12));
case 91: // munmap
return (uint32_t)my_munmap(emu, p(4), u32(8));
case 123: // SYS_modify_ldt
return my_modify_ldt(emu, i32(4), (thread_area_t*)p(8), i32(12));
case 125: // mprotect
return (uint32_t)my_mprotect(emu, p(4), u32(8), i32(12));
case 174: // sys_rt_sigaction
return (uint32_t)my_sigaction(emu, i32(4), (x86_sigaction_t*)p(8), (x86_sigaction_t*)p(12));
case 192: // mmap2
return (uint32_t)my_mmap64(emu, p(4), u32(8), i32(12), i32(16), i32(20), u32(24));
case 243: // set_thread_area
return my_set_thread_area((thread_area_t*)p(4));
#ifndef NOALIGN
+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];
Loaded 100 of 343 files, more files were not shown because too many files have changed in this diff. Show more