693 Commits
Author SHA1 Message Date
ptitSeb f7630dec30 Bumped to v0.1.2 2020-08-14 10:04:55 +02:00
ptitSeb 031f41a333 Added build info (time and date) and git hash tag, rebuilt at each build 2020-08-14 10:03:32 +02:00
ptitSeb d18eb1c9c5 Added version and help options to box86 2020-08-14 09:13:12 +02:00
ptitSeb a666619de7 Added 0F BA /7 BTC opcode 2020-08-13 19:31:21 +02:00
ptitSeb a6d55175ac Added 0E PUSH CS opcode 2020-08-13 19:17:31 +02:00
ptitSeb b33d952b47 [DYNAREC] Some minor changes to emit_cmp16 2020-08-13 18:13:44 +02:00
ptitSeb 65fc0f36e7 [DYNAREC] Added 0F E8 PSUBSB and 0F E9 PSUBSW opcodes 2020-08-13 16:31:09 +02:00
ptitSeb 4bb743bde0 [DYNAREC] Fixed emit_sub16c (fixed sound in DeusEx) 2020-08-13 16:20:33 +02:00
ptitSeb 1b8f92249d [DYNAREC] Minor changes, to avoid potential BUSERROR mainly 2020-08-13 16:18:46 +02:00
ptitSeb 42838834f6 [DYNAREC] More log info on Unimplemented opcode 2020-08-13 16:18:13 +02:00
ptitSeb 83508fa322 Added F1 INT1 dummy opcode 2020-08-12 18:05:28 +02:00
ptitSeb 044d667b9e Added GL_EXT_multisampled_render_to_texture wrapped functions to libGL 2020-08-12 16:58:11 +02:00
ptitSeb 97274871c8 Protect memory only if Dynarec is used 2020-08-12 16:29:31 +02:00
ptitSeb e5fabc828c [DYNAREC] Added utility function to get dynarecblock from arm native dynarec address (and used it in SegFault handler) 2020-08-12 14:01:52 +02:00
ptitSeb e5601cb09c [DYNAREC] Made 81 /7 CMP Ed, Id opcode resiliant to SMC (fixes DeusEx, maybe other too) 2020-08-12 13:58:05 +02:00
ptitSeb 6f87bd8570 Added 67 E8 xx opcode (should help #179 too) 2020-08-11 17:41:04 +02:00
ptitSeb b393923c6e Added 65 2B SUB Gd, GS:Ed and 65 03 ADD Gd, GS:Ed opcode ([DYNAREC] too) (should help #179) 2020-08-11 16:54:00 +02:00
ptitSeb 37ab148df6 Simplified a bit ResolveFile utility function 2020-08-11 13:58:37 +02:00
ptitSeb 2f977f200b Added libcurl-gnutls.so.4 as a synonym a libcurl.so.4 2020-08-11 11:18:15 +02:00
ptitSeb e674f1a528 Changed PltResolver, to be inject in PLT.GOT instead of GOT.PLT before GOT (fixes Don't Starve) 2020-08-11 11:17:28 +02:00
ptitSeb fc93d47b14 Removed some useless code in wrapped glib2 lib 2020-08-10 18:55:50 +02:00
ptitSeb 3028d096b9 Merge pull request #178 from rajdakin/makefix
x86 build fix
2020-08-10 16:52:19 +02:00
rajdakin e7313a4df4 [BOX86] Fixed multiple non-extern definitions (x86 build) 2020-08-10 16:49:24 +02:00
rajdakin 31af5ec181 [LIBTOOLS] Fixed x86 builds (__i386 is defined, not __x86__) 2020-08-10 16:48:13 +02:00
ptitSeb 98222c75c2 Merge pull request #177 from rajdakin/VMOVinsn_fix
[DYNAREC] Fixed the four VMOV VFPU instructions printer
2020-08-10 16:35:51 +02:00
rajdakin d0380eccf7 [DYNAREC] Fixed the four VMOV VFPU instructions printer 2020-08-10 16:28:03 +02:00
ptitSeb f570ee0ea2 Fixed nanoslepp that was broken with last commit 2020-08-09 15:38:43 +02:00
ptitSeb 6ac716b8ba Update README.md 2020-08-09 10:10:22 +02:00
ptitSeb e8a080f5c0 Added COLOR_PAIRS to ncurses* (help Dwarf Fortress in text mode) 2020-08-08 17:45:53 +02:00
ptitSeb 67237e54f9 Added some workaround for nanosleep with null parameter 2020-08-08 17:20:29 +02:00
ptitSeb 4acf0f080e refactored CPUID opcode, and added a few more SubCommand (80000001..80000005) 2020-08-08 11:23:09 +02:00
ptitSeb 8e576f3f7d Merge pull request #176 from spacepilotAV/patch-1
Fix spelling of surprisingly in README.md
2020-08-07 19:32:10 +02:00
ra1n 037859b007 Fix spelling of surprisingly in README.md
speeling is important guys ;)
2020-08-07 13:14:39 -04:00
ptitSeb e81e7c7ebd Allow the use of #ifndef in wrapper _private headers 2020-08-07 15:45:17 +02:00
ptitSeb a50079b920 Better wrapping of g_variant_new_va (should help #167) 2020-08-07 15:43:48 +02:00
ptitSeb 4a38d8199f Merge pull request #175 from truboxl/patch-1
Make test10 more robust
2020-08-06 12:38:27 +02:00
Jia Yuan Lo 4dd9337528 Make test10 more robust
Test10 currently only passes after "make install" (no regard to x86lib directory needed) or we build directly inside box86 folder.
This change make sure x86lib folder is properly located so that we can also "ctest" inside build folder after compile without "make install".

Signed-off-by: Jia Yuan Lo <[email protected]>
2020-08-06 18:22:01 +08:00
ptitSeb c6db07039f Merge pull request #174 from Icenowy/fld-double-sigbus
[DYNAREC] Avoid SIGBUS on FLD double
2020-08-06 09:57:43 +02:00
Icenowy Zheng 9294b59aae [DYNAREC] Avoid SIGBUS on FLD double
Signed-off-by: Icenowy Zheng <[email protected]>
2020-08-06 05:53:11 +08:00
ptitSeb 490f595d6d [DYNAREC] Avoid BUSERROR on 0F 7F MOVQ (should help #167) 2020-08-05 18:52:12 +02:00
ptitSeb 67af7a0baf [DYNAREC] Fixed freeze issue introduce with previous commit 2020-08-05 15:10:00 +02:00
ptitSeb 7da89748bb [DYNAREC] Small change on nolinker block handling (when son is outside the range of the parent) 2020-08-05 12:02:15 +02:00
ptitSeb 72a82ebece [DYNAREC] Reordered the cleaning of dynablocks / dynablocks list to avoid segfault 2020-08-05 11:17:21 +02:00
ptitSeb 12e44a3e62 Merge pull request #173 from Icenowy/blocks_hashmap_check
check whether blocks hashmap exists when removing block from it
2020-08-05 10:01:30 +02:00
Icenowy Zheng 5dd94df9dd check whether blocks hashmap exists when removing block from it
Signed-off-by: Icenowy Zheng <[email protected]>
2020-08-05 15:57:23 +08:00
ptitSeb 79051e04b4 Merge pull request #172 from Icenowy/dynablock_mark_foreach_fix
dynablock: do not access value when foreach on marks
2020-08-05 09:46:40 +02:00
ptitSeb 02a0a77bda Merge pull request #170 from Icenowy/sdl_tolowerupper
wrap SDL_to{lower,upper}
2020-08-05 09:39:33 +02:00
Icenowy Zheng b3c5115707 dynablock: do not access value when foreach on marks
Accessing the value of a kh_set (which has no values set) is an
undefined behavior, which may make monsters to appear.

Add a kh_foreach_key macro that do not touch values at all, and use it
when ennuerating marks in dynablock, to prevent SIGSEGV of accessing
non-existent values.

Signed-off-by: Icenowy Zheng <[email protected]>
2020-08-05 15:26:55 +08:00
Icenowy Zheng e069681cfd wrap SDL_to{lower,upper}
These are very simple function that accepts an int and returns an int.

Signed-off-by: Icenowy Zheng <[email protected]>
2020-08-05 15:00:30 +08:00
ptitSeb c93356fb1a Deactivated Segment optim for GS (should help #167) 2020-08-04 16:19:56 +02:00
ptitSeb c398c938e1 Added F2/F2 18..1D opcode (F2/F3 ignored) 2020-08-04 15:43:20 +02:00
ptitSeb f3c6dc31ac Added 66 36 prefix (and fixed 66 2E and 66 26 prefixes) 2020-08-04 15:28:44 +02:00
ptitSeb 06403425f9 Merge pull request #166 from Icenowy/ld_library_path_prepend
prepending LD_LIBRARY_PATH
2020-08-04 10:25:30 +02:00
ptitSeb a9fa9095d5 Merge pull request #165 from Icenowy/g_utf8_skip
wrap g_utf8_skip in glib, which is a pointer to an array of char
2020-08-04 09:40:17 +02:00
Icenowy Zheng 617eacfcd3 prepending LD_LIBRARY_PATH
LD_LIBRARY_PATH should be able to override system libraries, this is the
behavior of ld-linux.so.

Signed-off-by: Icenowy Zheng <[email protected]>
2020-08-04 04:34:54 +08:00
Icenowy Zheng 7ba89639da wrap g_utf8_skip in glib, which is a pointer to an array of char
Signed-off-by: Icenowy Zheng <[email protected]>
2020-08-04 02:14:05 +08:00
ptitSeb 2914ed358e [DYNAREC] Don't allocate Direct Dynablock on mmap 2020-08-03 00:10:17 +02:00
ptitSeb 72041b6873 Make bridges allocate larger chunk 2020-08-03 00:09:41 +02:00
ptitSeb bf8da23a76 Added SS_ONSTACK fake handling to sigaltstack, so Unity game don't assert at start 2020-08-02 20:06:34 +02:00
ptitSeb f3f3d9cdfe Some small fixes to Segment offset cache mecanism 2020-08-02 19:57:43 +02:00
ptitSeb 05c7d8fec9 Use a Cache (per thread) of Segment Offset, to sppedup GS: and FS: access 2020-08-02 16:04:27 +02:00
ptitSeb 5201aeffa6 [DYNAREC] Small optim in GetDynablocksFromAddress, starting with fast getDBFromAddress before looking içnto elf memory 2020-08-02 16:03:55 +02:00
ptitSeb 2fba190d8b [DYNAREC] Improved son creation for large dynablock (or block near end of dynablocklist) by allow the use of a different dynablocklist parent 2020-08-02 14:17:54 +02:00
ptitSeb 9e669ad06b [DYNAREC] Added 66 F2/F3 A7 REP(N)Z CMPSW and 66 F2/F3 AF REP(N)Z SCASW 2020-08-02 14:16:36 +02:00
ptitSeb 7f66be599c [DYNAREC] Added D9 /4 FLDENV Ed opcode 2020-08-02 13:55:36 +02:00
ptitSeb 7d1f429ead [DYNAREC] Added 66 91..97 XCHG AX, reg opcode 2020-08-02 13:55:07 +02:00
ptitSeb 4e602abfcb Try to improve (and fix) obstack wrapping (should help #160) 2020-08-02 10:08:05 +02:00
ptitSeb aad016d418 Merge pull request #163 from Icenowy/obstack_free
Add an automatic wrapper for {,_}obstack_free
2020-08-01 22:12:25 +02:00
Icenowy Zheng 3544428e18 Add an automatic wrapper for {,_}obstack_free
Signed-off-by: Icenowy Zheng <[email protected]>
2020-08-02 04:07:29 +08:00
ptitSeb 459c3ef530 Various small x87 adjustments 2020-08-01 17:58:09 +02:00
ptitSeb a01f5b1f3f [DYNAREC] Added a warning when a son have no code 2020-08-01 17:57:52 +02:00
ptitSeb 9183391ab0 Forgot the EXPORT for my__obstack_begin (should help #160) 2020-08-01 17:56:51 +02:00
ptitSeb c22ca077ba [DYNAREC] Added CF IRET opcode 2020-08-01 15:11:17 +02:00
ptitSeb 63c224b073 Ajusted D9 F5 FPREM1 opcode 2020-08-01 14:07:48 +02:00
ptitSeb f36567593a Added _obstack_begin wrapped function to libc (for #160) 2020-07-31 18:11:10 +02:00
ptitSeb b2efee99fa Merge pull request #159 from Icenowy/main-fix
Fix compliation of non-dynarec build
2020-07-30 20:39:27 +02:00
Icenowy Zheng 6510dc9e45 Fix compliation of non-dynarec build
sysconf() is part of unistd.h, and src/main.c uses it. However, this
source code file only includes <unistd.h> when DYNAREC, makes
non-dynarec build fail for missing _SC_PAGESIZE macro.

Move the inclusion of <unistd.h> out of #ifdef DYNAREC.

Signed-off-by: Icenowy Zheng <[email protected]>
2020-07-31 01:55:06 +08:00
ptitSeb 213beed360 Merge branch 'master' of https://github.com/ptitSeb/box86 2020-07-29 17:24:13 +02:00
ptitSeb 801f374a66 Added a workaround to get wine run under interpretor only 2020-07-29 17:23:51 +02:00
ptitSeb 7f3eecec4c Merge pull request #157 from icecream95/cmsg
Add a wrapped function for __cmsg_nxthdr
2020-07-29 13:16:40 +02:00
Icecream95 bd92f64df9 Add a wrapped function for __cmsg_nxthdr 2020-07-29 22:55:02 +12:00
ptitSeb ab2617c20f [DYNAREC] This +1 was not needed, end is alread aligned and all 2020-07-29 08:00:39 +02:00
ptitSeb cd958240df [DYNAREC] More small change on memory protection scheme 2020-07-28 17:34:06 +02:00
ptitSeb 4254a2a2f7 Small change to vfprintf wrapped function 2020-07-28 16:57:38 +02:00
ptitSeb 9735f21f65 [DYNAREC] Some more small fixes on memory protection scheme 2020-07-28 13:25:59 +02:00
ptitSeb 62343cbb77 Made bridge structure slightly bigger so it align 2020-07-28 13:24:46 +02:00
ptitSeb 23eca257f4 Merge pull request #156 from Newbytee/patch-1
Language fixup in README
2020-07-27 15:41:02 +02:00
Newbyte 5a3c17e831 Language fixup in README
I did some language fixes in README. During this I took some liberties to improve consistently, like always writing Box86 with a capital B. I am not sure whether you have a preferred way to stylise it, but as it is prior to this PR the README mixes box86 and Box86 heavily, and I decided to go with the latter. If you prefer it to always be written box86 with a lowercase b I can change it to be so.
2020-07-27 15:11:05 +02:00
ptitSeb de1bb7e438 Improved internal path resolution (should help #154) 2020-07-27 10:03:56 +02:00
ptitSeb 6216d06d0e [DYNAREC] Fine-tuned, again, how cleanDBFromAddressRange worked 2020-07-27 09:03:13 +02:00
ptitSeb cb03a51d40 [DYNAREC] Fixed a crash in later dynarec log level 2020-07-27 09:01:41 +02:00
ptitSeb 09a65a622a [DYNAREC] Small change in protection of dynarec volatile block, with a better detection of start address to scan 2020-07-26 20:42:25 +02:00
ptitSeb 95f6ce1f3e Fixed a potentiel read isse with execv method 2020-07-25 16:48:38 +02:00
ptitSeb 7ede988cb1 Added 64 67 A3 xx xx MOV FS:[Ov], EAX 2020-07-24 15:32:52 +02:00
ptitSeb a06e05dc9e Added 64 67 89 MOV FS:ED16,GD opcode 2020-07-23 10:13:27 +02:00
ptitSeb 2a3c6dc55c Added 6E/6F OUTSB/OUTSD (faked) opcode 2020-07-23 10:12:13 +02:00
ptitSeb 814701324c Added F2/F3 66 A7 REP(N)Z CMPSW 2020-07-22 15:41:43 +02:00
ptitSeb 01fea9ce3f Checked all wrapped function used by ntdlls.so, fixing some of them 2020-07-21 08:06:39 +02:00
ptitSeb da5e795858 [DYNAREC] Disable the use of SWP arm opcode for XCHG x86 opcode, while the 8bit verison seems ok, the 32bits is not 2020-07-20 08:30:52 +02:00
ptitSeb b491241307 Added 64 67 FF /6 PUSH FS:[Ed16] opcode 2020-07-20 08:29:40 +02:00
ptitSeb 81f6e87416 Fixed glXCreatePbuffer wrapped function signature 2020-07-19 23:20:06 +02:00
ptitSeb 20a680561a Added wrapped libncurses.so.6 and libtsinfo.so.6 (based on .5 version) 2020-07-19 18:21:45 +02:00
ptitSeb a4f2a19505 Added EC INSB AL, DX 2020-07-18 12:47:32 +02:00
ptitSeb a263283c93 Added 16 PUSH SS and 17 POP SS opcodes 2020-07-17 20:36:41 +02:00
ptitSeb ac2cdc65a8 Added a few off opcodes 2020-07-17 16:08:37 +02:00
ptitSeb c1b7740ac4 Added 66 91..97 XCHG AX, Reg opcodes 2020-07-17 08:21:57 +02:00
ptitSeb a1c8868159 Added 66 60 and 66 61 PUSHA POPA opcodes 2020-07-16 21:38:05 +02:00
ptitSeb a157acd185 Added 64 67 A1 xx xx opcode 2020-07-16 20:19:32 +02:00
ptitSeb 12ec1309bb Added option to disable the hack to force X11 GLX Extension beeing detected (help wine stuff while gl4es is not uet compatible) 2020-07-16 09:22:37 +02:00
ptitSeb 042d55f734 Added 66 F3 A4 (alt) MOV SB ([DYNAREC] too) 2020-07-16 08:17:21 +02:00
ptitSeb 67f8c6df42 Added F2/F3 40..4F (alt)INC/DEC reg opcode 2020-07-15 20:38:15 +02:00
ptitSeb c9d6c72fe0 Added 0F F7 MASKMOVQ opcode 2020-07-15 15:41:08 +02:00
ptitSeb e5fcadae30 Fixed signature for XGetAtomNames wrapped function 2020-07-15 13:42:00 +02:00
ptitSeb cb0ee7990a Added a workaround to ignore failed test of GLX extension in X11 2020-07-15 13:33:14 +02:00
ptitSeb 0eea4c5913 Added 0F E7 MOVNTQ opcode ([DYNAREC] too) 2020-07-15 09:14:36 +02:00
ptitSeb 5a8466b0d7 Fix compilation for non-dynarec build 2020-07-15 08:36:46 +02:00
ptitSeb 372d811f66 Added 65 8A MOV Gb, GS:Eb 2020-07-14 23:48:13 +02:00
ptitSeb ff2027846b [DYNAREC] Fixed issue when dlclose then dlopen a library 2020-07-14 20:26:37 +02:00
ptitSeb 8318eb1a0d Added 0F BA /5 BTS Ed, Ib opcode 2020-07-14 19:20:31 +02:00
ptitSeb 57c0751793 Added 66 FF /6 PUSH Ed opcode 2020-07-14 19:19:58 +02:00
ptitSeb 86b00ef7fe Added 66 9D POPF opcode 2020-07-14 18:59:56 +02:00
ptitSeb 6e12a556ec Fixed a warning 2020-07-14 18:06:01 +02:00
ptitSeb fba165d121 Added 64 67 8B opcode 2020-07-14 18:05:40 +02:00
ptitSeb 68d77636b0 Changed again a bit the destruction sequence for box86context 2020-07-14 14:37:11 +02:00
ptitSeb 394d46f731 Added 66 0F BA BTR opcode 2020-07-14 14:36:44 +02:00
ptitSeb 702a9f6aa5 Added dummy 0F 00 VERR/VERW and 0F EA PMAXSW opcode 2020-07-14 13:48:41 +02:00
ptitSeb 7ae3813ac5 Set my_context to NULL when context is beeing destroyed 2020-07-14 12:13:55 +02:00
ptitSeb 34a933af0b Try to get more info on segfault (not sure it's a good idea) 2020-07-14 12:13:22 +02:00
ptitSeb 4ac5d6df7f Added 36 SS: (ignored) prefix ([DYNAREC] too) 2020-07-14 11:29:52 +02:00
ptitSeb 0260548d9c Fixed a few glX wrapped functions 2020-07-14 11:29:22 +02:00
ptitSeb 5b64623f50 [DYNAREC] Fix a potential crash when a volite dynablock is 0 len 2020-07-14 10:18:29 +02:00
ptitSeb 233e472503 Added 0F EA PMINSW Gm, Em opcode 2020-07-14 09:58:36 +02:00
ptitSeb 335512e96a Added fake 62 BOUND GD, Ed opcode ([DYNAREC] too) 2020-07-14 09:47:13 +02:00
ptitSeb d451a3fdd7 Added 64 3B CMP Gd,FS:Ed ([DYNAREC] too) 2020-07-14 09:13:50 +02:00
ptitSeb 499de4fd60 Oops, forgot to remove some debug code 2020-07-13 21:05:18 +02:00
ptitSeb caf9abc16f Added also F2/F3 E9 opcode ([DYNAREC] too) 2020-07-13 19:12:35 +02:00
ptitSeb 5dfce69c37 Added F2/F3 E8 opcode ([DYNAREC] too) 2020-07-13 19:04:03 +02:00
ptitSeb 8f12829e95 Added some more wrapper to opengl 2020-07-13 18:23:13 +02:00
ptitSeb 15a42f5407 Added some wine prereserve mecanism 2020-07-13 17:38:45 +02:00
ptitSeb c8cdd3f432 [DYNAREC] Added F2/F3 66 AF REP(N)Z SCASW opcode 2020-07-13 17:38:19 +02:00
ptitSeb ac7c72396d Added F2/F3 66 AF REP(N)Z SCASW opcode 2020-07-13 17:37:43 +02:00
ptitSeb ce3271f095 Fixed some case of bad error with mmap / mmap64, plus improve trace of it 2020-07-13 17:36:32 +02:00
ptitSeb 3ff4b04e52 [DYNAREC] More alignment fixes 2020-07-13 17:35:05 +02:00
ptitSeb ecd90a41d5 [DYNAREC] Try to avoid some SIGBUS on DC xx opcodes 2020-07-13 14:50:58 +02:00
ptitSeb 87695cf84b [DYNAREC] Try to avoid potention SIGBUS on some F2 0F xx opcodes 2020-07-13 14:32:12 +02:00
ptitSeb 3bb93e1fd9 Added F2 0F 7C HADDPS opcode ([DYNAREC] too) 2020-07-13 11:30:24 +02:00
ptitSeb 69279b2233 Added D9 F6 FDECSTP and D9 F7 FINCSTP opcodes 2020-07-13 10:54:46 +02:00
ptitSeb 7c811666fe Added 0F A0/A1/A8/A9 PUSH/POP FS/GS opcodes ([DYNAREC] too) 2020-07-13 10:43:49 +02:00
ptitSeb 9a18dd3718 Added 0F D7 PMOVMSKB opcode ([DYNAREC] too) 2020-07-12 15:03:06 +02:00
ptitSeb 3338d26aaa Add 2 more wrapped function to libpulse 2020-07-12 12:38:58 +02:00
ptitSeb 167ea1587e Chnaged a bit signals debug 2020-07-12 12:38:31 +02:00
ptitSeb 7ad6399940 Added workaround for _finite function not always present in libm, using regular function as fallback (should help #138) 2020-07-12 10:39:03 +02:00
ptitSeb 71db6b3275 Some changes to the interpretor to ensure R_EIP is always correct 2020-07-11 18:12:03 +02:00
ptitSeb 00626b9f3e Fixed an issue with FS: access (or any other custom selector) 2020-07-11 16:11:48 +02:00
ptitSeb d0fa79c9ca [DYNAREC] Fixed PUSH FS:Ed opcode 2020-07-11 15:54:10 +02:00
ptitSeb fc1f75c3f6 [DYNAREC] Added 2 segment related opcodes 2020-07-11 15:17:15 +02:00
ptitSeb 21b9676093 Added some wrapped function to libusb-1.0 2020-07-11 14:38:36 +02:00
ptitSeb ea2a7204df Forgot that fix for libpng12 2020-07-11 14:38:10 +02:00
ptitSeb bcdd09a2e6 Removed dup'd function in wrapped libpng16 2020-07-11 14:28:37 +02:00
ptitSeb 7c394ddeee Show args for emulated program on BOX86_LOG=1 at start 2020-07-11 13:57:23 +02:00
ptitSeb 50d7e2d1d7 Some fixes to wrapped libpng16 and libpng12 2020-07-11 13:55:10 +02:00
ptitSeb 395cecb082 More change on signal handler. Still not complete enough 2020-07-10 20:46:20 +02:00
ptitSeb c8888915d7 [DYNAREC] Very small optim on CALL Ed opcode 2020-07-09 22:13:00 +02:00
ptitSeb 38740ce1c9 [DYNAREC] Try to avoid a segfault, bad mix with PltResolver that can hapens (should help #145) 2020-07-08 22:46:43 +02:00
ptitSeb 73b893215e [DYNAREC] Added FSAVE and FRSTOR opcode 2020-07-08 22:45:58 +02:00
ptitSeb e93c3f0028 Added option to have different trace per pid (to avoid overwritting when multiple process are spawning) 2020-07-08 18:21:49 +02:00
ptitSeb be2e35381e Removed a dupe in wrapped lib xrender 2020-07-08 16:46:57 +02:00
ptitSeb c79f59c86f Added one more wrapped function to libxi 2020-07-08 16:30:10 +02:00
ptitSeb 6f02d5f2c4 Added more gnutls wrapped functions 2020-07-08 16:23:40 +02:00
ptitSeb 969bd84f1d Added more FreeType wrapped functions 2020-07-08 15:36:20 +02:00
ptitSeb 8865b7bfec Added wrapped libgnutls (with some wrapped functions) 2020-07-08 15:15:11 +02:00
ptitSeb f60ecc3626 Added more wrapped function to libpng16 2020-07-08 14:10:36 +02:00
ptitSeb 824b230bd0 Added some support for modify_ldt syscall, but pretty useless whle 16bits is not supported 2020-07-08 13:38:13 +02:00
ptitSeb 71a208334d [DYNAREC] Changed a bit what PUSH/POP DS/ES emit (more in line with PUSH/POP reg) 2020-07-08 13:37:08 +02:00
ptitSeb 1d75d23772 Added wrapped libmpg123 lib (partial) 2020-07-07 09:40:16 +02:00
ptitSeb 6dd848eac5 Added F2/F3 70..7F (BND) Jxx and 64 8F PUSH FS:Ed opcodes 2020-07-07 07:50:17 +02:00
ptitSeb 0c0684bfb7 Added support for set_thread_area and handling of FS: 2020-07-06 21:57:46 +02:00
ptitSeb b56337df19 [DYNAREC] Fix potential crash when deleting a dynoblock without map 2020-07-06 21:57:46 +02:00
ptitSeb 0f0512c67c Merge pull request #144 from Mashintime/master
Update CMakeLissts.txt to copy libstdc++.so.5
2020-07-06 21:35:46 +02:00
Mashintime b677261976 Update CMakeLissts.txt to copy libstdc++.so.5
Included in x86libs but not copied to /usr/lib when 'make installing'
2020-07-06 15:25:24 -04:00
ptitSeb 0d0a75319c Fixed an old typo on impacting thread_attr_setstacksize 2020-07-06 21:24:53 +02:00
ptitSeb 0d283757d5 Update README.md 2020-07-06 07:48:19 +02:00
ptitSeb c09f477251 Improvement to the trace of called wrapped functions 2020-07-05 18:48:13 +02:00
ptitSeb 1d2bf3cb48 Try to make the O_XXXX convert function more portable 2020-07-05 14:28:25 +02:00
ptitSeb 7057160b3e Improved handling of pthread get/set affinit (old and new version) 2020-07-04 18:53:26 +02:00
ptitSeb 4244f41c41 Added helper function to get function name based on address 2020-07-04 15:41:28 +02:00
ptitSeb 70f587e305 Fixed potential issue with cmake 2020-07-04 14:20:51 +02:00
ptitSeb 97c5119807 Update README.md 2020-07-03 21:04:08 +02:00
ptitSeb 77a74d64bf [DYNAREC] Try to avoid a crash caused by a bad mix of dynarec and unresolved plt 2020-07-02 09:53:55 +02:00
ptitSeb 0547cec24d More SDL2 wrapped function with dummy fallback (plus some refactor and a fix probably) 2020-06-30 19:51:20 +02:00
ptitSeb 6837f58a0e Added 1 unofficial wrapped function (with dummy fallback) to SDL2 2020-06-30 18:28:32 +02:00
ptitSeb 2518377f83 Some fix to SDL2 wrapped lib 2020-06-30 14:14:24 +02:00
ptitSeb d38e67f539 Improved libx11 callback handling 2020-06-30 13:55:09 +02:00
ptitSeb a3d16d3c71 [DYNAREC] Fixed a warning 2020-06-30 12:48:41 +02:00
ptitSeb 14e1363930 Changed how FXSAVE/FXRSTOR works (in [DYNAREC] too) 2020-06-30 12:45:54 +02:00
ptitSeb 86eba0aaeb [DYNAREC] Actually use 64 FS: prefix 2020-06-30 12:06:39 +02:00
ptitSeb 10d7e28de3 Added some wrapped functions to a few libs 2020-06-30 09:49:02 +02:00
ptitSeb 082d08755e Stop ignoring tgsysall for now 2020-06-30 09:41:38 +02:00
ptitSeb 195bbddd6f This should avoid the 'wall of segfault' that happens sometimes 2020-06-30 09:06:43 +02:00
ptitSeb d68cbfd837 Added CF IRET opcode (not sure if correct) 2020-06-30 00:42:21 +02:00
ptitSeb 851d487015 [DYNAREC] Fixed FXSAVE / FXRSTOR (partial) opcode 2020-06-30 00:16:18 +02:00
ptitSeb 0a3ae03043 Added libncurses.so.5 wrapped function (bases libncursesw) and added 1 wrapped function to lbtsinfo.so.5 2020-06-30 00:09:59 +02:00
ptitSeb d56fea52f3 Added preliminary dlinfo wrapped function 2020-06-29 23:25:08 +02:00
ptitSeb 1de0f14194 [DYNAREC] Fix hang when call address 0 2020-06-29 23:24:48 +02:00
ptitSeb d3addae744 Fixed a warning in x86tls.c 2020-06-29 21:30:22 +02:00
ptitSeb ee0e831efe [DYNAREC] Added some FS: opcode (copy of GS: ones) 2020-06-29 20:41:44 +02:00
ptitSeb 59559efbb5 Handling default value for FS when creating new x86emu_t structure 2020-06-29 19:52:56 +02:00
ptitSeb 05e2a9c824 Fixed pwrite64 wrapped function signature 2020-06-29 19:39:41 +02:00
ptitSeb 9038d94184 Added a few wrapped function to libm 2020-06-29 18:25:51 +02:00
ptitSeb 08a93fc5ae Added memccpy wrapped function to libc 2020-06-29 18:09:04 +02:00
ptitSeb 6b6075ca48 Fixed dladdr wrapped function 2020-06-29 17:43:54 +02:00
ptitSeb 51135b9222 Added support for DT_RUNPATH (handed the same way as DT_RPATH) 2020-06-29 16:49:39 +02:00
ptitSeb 922c1770a0 [DYNAREC] Fix PUSH/POP DS/ES that should handle 32bits value on the stack (even if segment is 16bits) 2020-06-29 14:24:11 +02:00
ptitSeb b9dc8d79e0 Added 1 wrapped function to libX11 2020-06-29 13:03:11 +02:00
ptitSeb 7b823e4185 Changed execv wrapped function to automaticaly call box86(t) for x86 binary (help valgrind with --trace-children=yes) 2020-06-29 12:27:53 +02:00
ptitSeb fbdb4aa619 Changed how actual box86 fullpath is found 2020-06-29 12:24:55 +02:00
ptitSeb 7716936f77 [DYNAREC] Better way to free dynablocks (when a son would be free because his parent is freed, but still accessed to check if it can be freed) 2020-06-29 12:02:25 +02:00
ptitSeb 9636fec9da Free elfs first thing in FreeBox86Context 2020-06-29 12:01:15 +02:00
ptitSeb e15676e946 Changed how argv strings are handled 2020-06-29 11:41:07 +02:00
ptitSeb 28fb4ed090 [DYNAREC] Fixed a small potential memory overwritting 2020-06-29 11:19:55 +02:00
ptitSeb 8b5474d0a8 Added a few libX11 wrapped functions 2020-06-29 10:02:17 +02:00
ptitSeb 35e5a48e63 Added some FreeType wrapped functions 2020-06-29 08:56:47 +02:00
ptitSeb 470446a104 Removed some debug leftover 2020-06-29 08:56:26 +02:00
ptitSeb c0cc48d129 Added preliminary support for FS: and set_thread_area 2020-06-29 08:44:13 +02:00
ptitSeb 1134294037 [DYNAREC] Fix (66) 8E MOV Seg,Ew opcodes 2020-06-29 07:45:25 +02:00
ptitSeb f0f49d4f8f [DYNAREC] Fixed 66 8C MOV Ew, Seg and 66 8E MOV Seg, Ew opcodes 2020-06-28 19:22:19 +02:00
ptitSeb 5f361cbd2d Added exception for win-preloader in main (to not preload but load directly) 2020-06-28 18:01:54 +02:00
ptitSeb 20d65d3685 Wrapped lib now have path set to actual name 2020-06-28 17:16:50 +02:00
ptitSeb 51f0780c66 [DYNAREC] Added 0F 63 PACKSSWB opcode 2020-06-28 16:22:02 +02:00
ptitSeb b3db9aece7 [DYNAREC] Fixed PUSH ES / POP ES 2020-06-28 15:58:29 +02:00
ptitSeb 4e22fd1a69 Enabled SYS_RECVMMSG and SYS_SENDMMSG on syscall 102 even if those 2 macro are not defined 2020-06-28 11:23:42 +02:00
ptitSeb d290ccee7f [DYNAREC] Added 0F 51 SQRTPS and 0F 52 RSQRTPS opcodes 2020-06-27 20:13:42 +02:00
ptitSeb 4d227ef882 [DYNAREC] Added MINPD and MAXPD 66 0F 5D and 66 0F 5F opcodes 2020-06-27 18:28:40 +02:00
ptitSeb 6f842cea8b Changed the way NEEDED lib and GLOBAL symbol are fetched (again, for good this time hopefully, at least is seems to fix #136) 2020-06-27 14:02:56 +02:00
ptitSeb 36da25e08e Added 1 wrapped function to x11 lib 2020-06-27 08:57:45 +02:00
ptitSeb f586bb2617 Added syscall 196 sys_lstat64 2020-06-26 23:10:31 +02:00
ptitSeb f3a81ac635 Added syscall 66 sys_setsid 2020-06-26 19:37:31 +02:00
ptitSeb 266fc0961b Added syscall 271: sys_utimes 2020-06-26 19:09:11 +02:00
ptitSeb 824ae55d77 Added DS: prefix (ignored), can be used as hint, along with CS: in conditionnal jump (also ignored) 2020-06-26 18:22:41 +02:00
ptitSeb 656bfdc569 Fixed a small warning in gio2 wrapped lib 2020-06-26 09:01:53 +02:00
ptitSeb 0f45dd5fee Added libc syscall 174 (rt_sigaction) 2020-06-25 08:53:28 +02:00
ptitSeb 82e7faf83d Added more slot for pthread_once_callback 2020-06-24 18:24:20 +02:00
ptitSeb 0c7310b18d Really fixed epoll_create1 2020-06-24 16:00:28 +02:00
ptitSeb 2cedd0d2c6 Do not convert argument for epoll_create1 2020-06-24 15:15:44 +02:00
ptitSeb b63d087d5c Improved trace on semop wrapped function 2020-06-24 15:15:16 +02:00
ptitSeb bccdb36bd3 Added 2 x11 related wrapped functions 2020-06-23 07:47:24 +02:00
ptitSeb 298ef551ce Merge pull request #132 from rajdakin/explicitELF64
Explicit error message when having 64-bits ELFs
2020-06-21 20:46:39 +02:00
rajdakin 9b23a0a7ab [ELF] Explicit error message when having 64-bits ELFs 2020-06-21 20:44:54 +02:00
ptitSeb 5e2546dd0c Try to stop at double-segfault 2020-06-21 17:44:57 +02:00
ptitSeb 4e9bef301d Reworks INIT/FINI process, and fixed epoll syscall (now Half-Life quit properly) 2020-06-21 15:45:31 +02:00
ptitSeb be5d718280 [DYNAREC] Fixed a warning 2020-06-21 10:45:21 +02:00
ptitSeb 3bc1d6d0a1 Added alternative name for libopenal.so as openal.so 2020-06-21 09:25:34 +02:00
ptitSeb 2d23169ea5 [DYNAREC] Fixed many F3 0F xxxxSS opcodes 2020-06-20 19:48:59 +02:00
ptitSeb b486c60d5e Merge pull request #130 from rajdakin/printer
Dynarec printer fix
2020-06-20 18:22:25 +02:00
rajdakin 3246d2bbb6 [SIGNAL] Fixed unknown architecture build 2020-06-20 18:13:09 +02:00
rajdakin 7d7765ce14 [DYNAREC] Fixed one more time the printer (VMOV.F32 S, imm) 2020-06-20 18:12:46 +02:00
ptitSeb c1f2750b05 [DYNAREC] Fixed some printer issue with VFPU registers 2020-06-20 17:39:12 +02:00
ptitSeb bb4d44499c [DYNAREC] Added 66 0F C2 CMPPD opcode 2020-06-20 15:32:37 +02:00
ptitSeb 195ac3e5b6 [DYNAREC] Added 0F 2D CVTPS2PI opcode 2020-06-20 15:22:14 +02:00
ptitSeb bc9679cad9 [DYNAREC] Added 66 0F E6 CVTTPD2DQ opcode 2020-06-20 14:55:08 +02:00
ptitSeb a603b58970 [DYNAREC] Fixed 66 0F 5E DIVPD opcode 2020-06-20 14:39:06 +02:00
ptitSeb a740dbf871 [DYNAREC] Added 66 0F 5E DIVPD and 66 0F 15 UNPCKHPD opcode 2020-06-20 14:32:26 +02:00
ptitSeb b10e462e03 [DYNAREC] Added (naive) 0F 50 MOVMSKPS opcode 2020-06-20 14:19:37 +02:00
ptitSeb 6f28eb16c6 [DYNAREC] Fixed another potential BUSERROR 2020-06-20 12:53:22 +02:00
ptitSeb 140a41141c Fixed a potential BUSERROR 2020-06-20 12:03:46 +02:00
ptitSeb 6f00b50c6e Added Faked libtcmalloc_minimal (empty wrapped, use regular malloc/new functions) 2020-06-20 11:45:16 +02:00
ptitSeb a9cb19933a Change order of Global and Weak symbol fetching. Should be good this time 2020-06-20 10:50:03 +02:00
ptitSeb cbd8ce408e Enabled Trace in LOCAL function works now 2020-06-20 09:51:44 +02:00
ptitSeb 9837888e50 Allow Trace on LOCAL symbol loaded at start (was ok on dlopenned libs) 2020-06-20 09:28:28 +02:00
ptitSeb 42176b6593 Added a few dbus and gtk wrapped functions 2020-06-19 21:05:10 +02:00
ptitSeb a320528e64 Added some workaround for g_threads_got_initialized 2020-06-19 20:13:26 +02:00
ptitSeb 69a9175c67 Small changes to atfork handling 2020-06-19 18:55:01 +02:00
ptitSeb 9fdc3196d9 Fixed loaing of dependant libs of a local lib 2020-06-19 17:12:36 +02:00
ptitSeb 0b271fc44f Added PltResolver, so JmpSlot symbols are resolved at runtime now 2020-06-19 16:26:21 +02:00
ptitSeb 0fa2f7b8f1 Added one wrapped function to FontConfig 2020-06-18 22:30:44 +02:00
ptitSeb 41c775fb44 Fixed a warning 2020-06-18 22:10:31 +02:00
ptitSeb 28b06f45fe Fixed R_386_TLS_TPOFF relocation (fixed libtcmalloc_minimal.so.4 loading) 2020-06-18 22:06:28 +02:00
ptitSeb 083b3d2a1c Improved vfprintf trace 2020-06-18 22:05:51 +02:00
ptitSeb 61866f6dae [DYNAREC] Made the printing of a segfault a permanent printf for now 2020-06-18 22:05:34 +02:00
ptitSeb 39d7274359 Changed BOX86 load address to a low address 2020-06-18 22:04:46 +02:00
ptitSeb a9b4d994eb [DYNAREC] Added F3 0F 1E and F3 0F 1F multibte NOP, also used a ENDBR opcode 2020-06-18 08:46:55 +02:00
ptitSeb 3701dcd0b4 Added F3 0F 1E and F3 0F 1F multibte NOP, also used a ENDBR opcode 2020-06-18 08:46:18 +02:00
ptitSeb efe2588fd9 Added__libc_dlXXX wrapped function 2020-06-18 08:45:10 +02:00
ptitSeb 3c17d886cc Added many libcrypto and libSSL wrapped functions (and now Minit runs) 2020-06-17 18:51:21 +02:00
ptitSeb 83fe3605f6 Merge pull request #129 from rajdakin/fixes
Fixed ARMS (ARM shifted) instruction category
2020-06-17 12:08:52 +02:00
rajdakin dec474953b [DYNAREC] Ran the printer generator 2020-06-17 11:50:08 +02:00
rajdakin f80964d8d7 [DYNAREC] Fixed ARMS (ARM shifted) instruction category 2020-06-17 11:41:09 +02:00
ptitSeb a43687ee30 Change how symbol are fetched in Elf Relocate mecanism (hacky and probably wrong, but seems to work pretty well) 2020-06-17 00:07:26 +02:00
ptitSeb e04233a897 Some debugging helper 2020-06-16 18:22:21 +02:00
ptitSeb 93cd9b00bd [DYNAREC] Made x86emu_t structure up-to-date when calling arm_linker 2020-06-16 18:21:59 +02:00
ptitSeb 3a592ca9c4 [DYNAREC] Added a special case on 'read' wrapped function when reading on a write protected block (because it's an executable one) 2020-06-16 18:18:48 +02:00
ptitSeb 555d0d51b0 CPUID detection actualy need this bit to be changeable, not fixed 2020-06-16 18:10:53 +02:00
ptitSeb a70f29a8c9 Merge pull request #128 from rajdakin/fixesARMs
Fixed the ARMs and ARM$ instructions type for the printer
2020-06-16 11:36:37 +02:00
ptitSeb dad53a84c8 Merge pull request #127 from rajdakin/fixes
Fixed the U/SXT* opcodes print (and probably others too)
2020-06-16 11:35:56 +02:00
rajdakin d03b21ee19 [DYNAREC] Fixed the ARMs and ARM$ instructions type for the printer 2020-06-16 11:34:50 +02:00
rajdakin 1a1bf5f76a [DYNAREC] Oops, fixed the fix that removes rbrackets of reglists 2020-06-16 11:28:27 +02:00
rajdakin 0ebc0f19b8 [DYNAREC] Fixed the U/SXT* opcodes print (and probably others too) 2020-06-16 11:23:25 +02:00
ptitSeb d4cfa94aaa Merge pull request #126 from M-HT/old_glibc
Allow compilation with older version of glibc
2020-06-16 07:58:20 +02:00
M-HT 383d4c8f9a Allow compilation with older version of glibc 2020-06-16 07:35:33 +02:00
ptitSeb 48b187edd1 [DYNAREC] Don't create a son at the 1st instruction 2020-06-15 18:15:48 +02:00
ptitSeb 316e18f8c5 The syscall 254 sys_epoll_create use a flags parameter that need transform... 2020-06-15 17:59:07 +02:00
ptitSeb 657595d363 Rollback: don't ignore unsupported Int 2020-06-15 17:59:07 +02:00
ptitSeb 9cd9ad16b2 Some fixes t DBUS wrapped lib 2020-06-15 16:50:33 +02:00
ptitSeb 7d49d0fc8a Complete handling of LOCAL/GLOBAL on glopen wrapped function 2020-06-15 16:25:38 +02:00
ptitSeb fa9bdbfd64 Added a few more syscall 2020-06-15 16:23:45 +02:00
ptitSeb 558dc58a52 Don't stop on unknown interrupt, just skip it 2020-06-15 16:23:15 +02:00
ptitSeb 383b1afe0b Try to handle LOCAL/GLOBAL on dlopen wrapped function 2020-06-14 22:32:11 +02:00
ptitSeb 3d757a2af6 Merge pull request #124 from M-HT/fix_64bit_inodes
Fix 64bit inodes in readdir and readdir_r functions
2020-06-14 13:49:31 +02:00
M-HT 2cb20b665d Fix 64bit inodes in readdir and readdir_r functions 2020-06-14 13:16:57 +02:00
ptitSeb eadb36bcdd Merge pull request #123 from M-HT/fix_64bit_inodes
Add option to fix 64bit inodes
2020-06-13 23:27:23 +02:00
M-HT a3bbaeb11b Add option to fix 64bit inodes 2020-06-13 23:03:30 +02:00
ptitSeb 816ee7e23b Fixed last commit 2020-06-10 21:54:45 +02:00
ptitSeb 2a10da129e [TRACE] Allow tracing function in the Init part of a dlopen lib 2020-06-10 18:58:10 +02:00
ptitSeb 9784c3bf2d Compensate for bad lib dependacie in libmss.so.6 (fixes #121 Neverwinter Night Diamond Edition) 2020-06-07 22:40:18 +02:00
ptitSeb f64a7e2c5b Added some png12 and libc wrapped functions 2020-06-07 18:17:54 +02:00
ptitSeb f01359a62e Added some pango wrapped functions 2020-06-07 17:26:57 +02:00
ptitSeb 729f392148 Added a large batch of cairo wrapped functions 2020-06-07 17:20:11 +02:00
ptitSeb e48802c898 Added a dbus wrapped function 2020-06-07 16:42:32 +02:00
ptitSeb 34ed9f03e1 Added cairo_pango wrapped functions 2020-06-07 15:54:25 +02:00
ptitSeb 4990b6db94 Added some FreeType wrapped functions 2020-06-07 15:54:25 +02:00
ptitSeb ecf50c8181 Added 2 wrapped functions to libfontconfig 2020-06-07 15:54:25 +02:00
ptitSeb 927159011c Some small fixes to cpuinfo file creation 2020-06-07 13:46:31 +02:00
ptitSeb 640db5e667 Added some cairo wrapped functions 2020-06-07 13:18:05 +02:00
ptitSeb 509f09dfbc Refined gdk_display hack 2020-06-07 13:07:40 +02:00
ptitSeb 4f42ae0d81 Added a few libm wrapped functions 2020-06-07 12:44:18 +02:00
ptitSeb 1b4391ac23 Added some DBus wrapped functions 2020-06-07 12:39:39 +02:00
ptitSeb 5cb6894657 Added a workaround, again, for gdk_display symbol 2020-06-07 12:14:39 +02:00
ptitSeb be66c8bffa Create a fake /proc/cpuinfo instead of opening the real one 2020-06-07 11:48:37 +02:00
ptitSeb 5f71bcfe9a Slight change in elfloader 2020-06-06 11:10:53 +02:00
ptitSeb 95d786e9a8 Added a special case for libSgGL to load libGL as needed (fixes Hotline Miami) 2020-06-06 11:08:52 +02:00
ptitSeb 8b5e977868 Improved wrapping of curl (and now UrbanTerror download maps) 2020-06-05 17:20:51 +02:00
ptitSeb 49a631b475 Forgot a debug printf in mmap 2020-06-05 16:26:53 +02:00
ptitSeb 8b98a68d1a Update README with latest improvments 2020-06-05 11:42:31 +02:00
ptitSeb c03e46814b [BOX86LIB] Some slight adjustments for box86 as a lib 2020-06-05 11:41:58 +02:00
ptitSeb 7efac81f8b Force RelWithDebInfo build type if none was specified 2020-06-05 08:28:34 +02:00
ptitSeb 58e98e9580 [DYNAREC] Change a message log level, so it's less alarming 2020-06-04 17:58:53 +02:00
ptitSeb 56c211fbeb Added a few libpng12 wrapped function (fixed old FTL 1.5.13) 2020-06-04 17:23:18 +02:00
ptitSeb 2aa2e53fef [DYNAREC] Use a mecanism with Memory Protection to handle JIT'd code (good improvment in speed for Unity games at least) 2020-06-04 16:56:00 +02:00
ptitSeb 3993c88fbb Simplified Lib/Elf loading process (hopefully fixing some bugs in the process) 2020-06-03 19:53:17 +02:00
ptitSeb f706e7eecc Added a few __libc_XXXX wrapped function 2020-06-03 18:54:36 +02:00
ptitSeb 549de25a49 Improved trace a bit (lib name added in front of function name) 2020-06-03 18:54:14 +02:00
ptitSeb 217b05fb80 Small change to Interpretor in non-trace build 2020-06-03 18:53:14 +02:00
ptitSeb e1b9d40ca6 Fixed TRACE build 2020-06-03 17:50:41 +02:00
ptitSeb 0eeba809f2 Added one GS:ADD and one GS:ADC opcode (fixes Arma3 DS, #120, but it crashes after loading everything) 2020-06-03 16:29:59 +02:00
ptitSeb 4a0df1042d Fixed 'Unimplemented Opcode' message that would crash without showing in certain cases on no trace build (mainly with Dynarec) 2020-06-03 16:18:00 +02:00
ptitSeb e7a4274511 [DYNAREC] Try to avoid to keep a reference of a block that will potentially get removed 2020-06-02 16:36:36 +02:00
ptitSeb b3def68a4f Added Logo and Icon from @grayduck 2020-06-01 21:50:16 +02:00
ptitSeb 3c67de08a3 [DYNAREC] Create a temp variable there, that seems more safe 2020-06-01 21:49:27 +02:00
ptitSeb cec67ef3e3 Fixed the TRACE that was broken since last refactor 2020-06-01 17:37:04 +02:00
ptitSeb 881501b278 Fixed issue with glDebugMessageCallbackARB (now 140 run with mesa) 2020-06-01 12:12:18 +02:00
ptitSeb d09a949755 Fixed PREFETCH opcode (especially for the Interpretor) 2020-06-01 11:42:27 +02:00
ptitSeb bf6fa0f335 Added sbrk and brk functions to wrapped libc 2020-05-31 09:28:40 +02:00
ptitSeb 9dcfa322a5 Added SDL_Sem function to wrapped SDL2 2020-05-30 18:15:46 +02:00
ptitSeb a1c21ce05f [DYNAREC] More improvements to FreeDynablock 2020-05-30 09:59:28 +02:00
ptitSeb 22be56179d [DYNAREC] Improved FreeDynablock function 2020-05-29 20:16:58 +02:00
ptitSeb 24da6fcb3b [DYNAREC] Add dest reference in table only when dest as a mark set 2020-05-28 21:48:15 +02:00
ptitSeb 8078b27172 [DYNAREC] Chnage DBGetBlock to forget current block if it gets removed 2020-05-27 21:21:22 +02:00
ptitSeb 89d1254106 [DYNAREC] Added 66 F3 variant for REP MOVSW and REP STOSW 2020-05-27 14:16:32 +02:00
ptitSeb 497f66f5dc Fix for previous fix, for some (not so?) rare cases 2020-05-26 19:37:30 +02:00
ptitSeb a321d54142 Fix a small issue when detecting owner of some memory 2020-05-26 18:49:45 +02:00
ptitSeb 8495b461b8 [DYNAREC] Added protect/unprotect of an address range (will be used later) 2020-05-24 18:35:21 +02:00
ptitSeb 35d6354898 [DYNAREC] Detect PageSize (will be used later) 2020-05-24 17:57:30 +02:00
ptitSeb a2b4af137c Update README.md 2020-05-23 21:03:09 +02:00
ptitSeb 756d1c12fd Update README.md 2020-05-23 21:01:46 +02:00
ptitSeb 63f2e52edb Merge branch 'master' of https://github.com/ptitSeb/box86 2020-05-21 13:54:37 +02:00
ptitSeb fd704eca00 Remove the creation of x86emu_t structure from the stack when using RunFunction, use the thread local onee now 2020-05-20 20:42:38 +02:00
ptitSeb 8c233f1861 Removed emu from context structure, and made a per thread one 2020-05-20 19:01:22 +02:00
ptitSeb 669bb00590 Added libudev.so.1 wrapped lib (straight copy of libudev.so.0 for now) 2020-05-18 10:54:01 +02:00
ptitSeb 815fd918cb Fixed non-dynarec build (#116) 2020-05-15 13:09:47 +02:00
ptitSeb 4249adbe4e Update COMPILE.md 2020-05-14 08:49:00 +02:00
ptitSeb 1aec17da4d Update COMPILE.md 2020-05-14 08:45:59 +02:00
ptitSeb 3680a3092e [DYNAREC] Made FillBlock candidate for threading 2020-05-13 16:47:52 +02:00
ptitSeb b11a269867 [DYNAREC] Fixed TRACE build 2020-05-13 14:52:26 +02:00
ptitSeb cccbf75878 Simplified some function, removing the x86emu_t* argument 2020-05-13 13:17:03 +02:00
ptitSeb 5ce309e64b [DYNAREC] 66 0F D6 MOVQ can be unaligned... (should help #115) 2020-05-12 22:08:11 +02:00
ptitSeb 4b48a43413 Removed a small warning in new pthread_cond handling 2020-05-12 16:08:35 +02:00
ptitSeb a05df24c8b Changed, again, how phtread_conditions are handled 2020-05-12 16:06:59 +02:00
ptitSeb 4f599b521a Improved a bit the handling of thread conditions 2020-05-12 11:13:02 +02:00
ptitSeb 44cf2fc4fb [DYNAREC] Removed some warning 2020-05-12 11:12:30 +02:00
ptitSeb 0ca9f70796 [DYNAREC] Add father/son notion in dynablock, to allow branging in the middle of a dynablock (and avoid generating a new one) 2020-05-11 19:54:54 +02:00
ptitSeb 83cb2dbc4d [DYNAREC] Added mecanism to allow liner with volite code blocks 2020-05-11 08:54:39 +02:00
ptitSeb b09937ad3d [DYAREC] Added a few more NOP variant 2020-05-10 16:21:08 +02:00
ptitSeb c88d5d462c Use another method to handle errors in wrapped libjpeg 2020-05-10 13:12:18 +02:00
ptitSeb 78c971cb87 Added a few more SDL2 wrapped functions 2020-05-09 10:39:59 +02:00
ptitSeb 1bafddcfe2 Rewrapped some non-64 libc functions, to avoid mixing with 64 bits on some plateforms (fixes Saves of IcewindDale on Pi4) 2020-05-08 22:20:53 +02:00
ptitSeb 047b2071f5 [BOX86LIB] Added some libs to the linking of libbox86.so 2020-05-07 20:15:25 +02:00
ptitSeb 8aca039ca6 Added some old and rarely used opcode (helps ZeldaClassic) 2020-05-07 11:50:49 +02:00
ptitSeb db8c6b0c9e Fixed build with cmake less than 3.13.5 (fix for #112) 2020-05-06 20:49:32 +02:00
ptitSeb dbc6aa83f3 Merge pull request #111 from rajdakin/cmake-fix
Fix configuration on older CMake
2020-05-06 20:03:06 +02:00
rajdakin 08472aa68b [CMake] Fix configuration on older CMake 2020-05-06 19:59:57 +02:00
ptitSeb 3010068660 Try a fix on Python finding with old cmake (should fix #110) 2020-05-06 19:28:22 +02:00
ptitSeb 5e2faff01d [DYNAREC] Small changes 2020-05-06 19:12:49 +02:00
ptitSeb 598338809f Take LD_PRELOAD into account if BOX86_LD_PRELOAD is not present 2020-05-06 19:12:11 +02:00
ptitSeb 4778760622 [DYNAREC] Improved handling of JIT'd code by marking potentialy changed block as dirty instead of purging the whole block 2020-05-06 16:41:59 +02:00
ptitSeb 3a23cc42f6 Small cosmetic changes 2020-05-06 14:16:56 +02:00
ptitSeb e23283e794 [BOX86LIB] Improved the Build as a lib version, and introduced build as dynamic lib 2020-05-06 14:09:56 +02:00
ptitSeb 4d730a31c4 Merge pull request #109 from icecream95/posix_spawn
Wrap some posix_spawn functions
2020-05-06 07:37:02 +02:00
ptitSeb 216b6407f3 Merge pull request #108 from rajdakin/reprinter
Printer automation
2020-05-05 20:38:11 +02:00
rajdakin e95988f402 [DYNAREC] Forgot to increase the version number 2020-05-05 19:32:40 +02:00
rajdakin 1ce3731d7d [DYNAREC] Refactored the printer generator (8) 2020-05-05 19:27:32 +02:00
rajdakin 7420d3c8de [DYNAREC] Refactored the printer generator (7) 2020-05-05 19:27:32 +02:00
rajdakin f1edcc06d3 [DYNAREC] Refactored the printer generator (6) 2020-05-05 19:27:32 +02:00
rajdakin ce5c3db346 [DYNAREC] Refactored the printer generator (5) 2020-05-05 19:27:32 +02:00
rajdakin cc0b7b3719 [DYNAREC] Refactored the printer generator (4) + major bug fix 2020-05-05 19:27:32 +02:00
rajdakin 7854fa2e18 [DYNAREC] Removed WIP spacing 2020-05-05 19:27:32 +02:00
rajdakin 1b7bc825d5 [DYNAREC] Refactored the printer generator (3) 2020-05-05 19:27:32 +02:00
rajdakin e65f58acb2 [DYNAREC] Refactored the printer generator (2) 2020-05-05 19:27:32 +02:00
rajdakin 18fe17dc2d [DYNAREC] Refactored the printer generator (1) 2020-05-05 19:27:32 +02:00
rajdakin 8098461e0f [DYNAREC] Changed a little how the printer generator works 2020-05-05 19:27:32 +02:00
rajdakin bf8e9f9242 [DYNAREC] Added an ARM instructions printer generator 2020-05-05 19:27:32 +02:00
rajdakin 4838067440 [WRAPPERS] Rewrote the wrappers generator a bit 2020-05-05 19:27:32 +02:00
rajdakin 53a080e32e [CMake] Cleanup the CMakeLists.txt file a bit 2020-05-05 19:27:32 +02:00
rajdakin 3ac41770b8 [CMake] Force the use of Python3 2020-05-05 19:27:32 +02:00
ptitSeb 6fe51fd7f4 [DYNAREC] Finaly found why Unreal crashes when CPUID detection was enabled: linfmod use some SMC, that's bad. So found some workaround 2020-05-05 17:16:46 +02:00
ptitSeb a6cbe15b5e [DYNAREC] Some small optim on 32bits float access 2020-05-05 17:15:33 +02:00
ptitSeb 3313eba45c [DYNAREC] When using BOX86_DYNAREC_DUMP, use some mutexes to avoid mixing block in dump 2020-05-05 17:14:04 +02:00
Icecream95 b01150f707 Wrap some posix_spawn functions 2020-05-05 14:13:52 +12:00
ptitSeb 4502948f89 Changed a bit the thread creation / cancellation, and associted mutex 2020-05-04 22:47:37 +02:00
ptitSeb 8cb2ffbd2e Added some crude (maybe incorrect?) workaround for function with 0 size in elf header (fixed some libfmod function, somehow) 2020-05-04 15:45:34 +02:00
ptitSeb be80cb03d6 Changed how Trace ona Function works, so it can works on defered (dlopen'd) library 2020-05-04 15:44:43 +02:00
ptitSeb 13d6e96cdc Set trace begin/end as global 2020-05-04 14:04:18 +02:00
ptitSeb 9f280b1f9c Set CPU Family to 6 (instead of 1) in CPUID 2020-05-03 18:53:43 +02:00
ptitSeb 786dfa6700 [DYNAREC] Small optimization on x87 Stack sync 2020-05-03 18:52:36 +02:00
ptitSeb e260aee2e6 [DYNAREC] Use NOP instead of B to ext instruction 2020-05-03 18:51:59 +02:00
ptitSeb 504c27c934 [DYNAREC], Nope, that Unreal bug is still not fixed, not enable CPUID detection yet 2020-05-03 18:51:25 +02:00
ptitSeb c4ba481561 In trace, function name with 0 sized are like infinite size 2020-05-03 18:48:43 +02:00
ptitSeb 841770aed1 [DYNAREC] Small dump improvment 2020-05-03 18:48:01 +02:00
ptitSeb 1a4643f3a2 [DYNAREC] Small improvment on x87 cache access 2020-05-03 12:56:17 +02:00
ptitSeb e89702d99d [DYNAREC] Fixed printer for rotated immadiate 2020-05-03 12:55:46 +02:00
ptitSeb 250e3820df [DYNAREC] Small fixe to the printer to get more printed opcodes in dumps 2020-05-03 11:14:36 +02:00
ptitSeb 8b2a509a32 [DYNAREC] A bit more color in dump 2020-05-02 19:48:31 +02:00
ptitSeb 6db92c56b9 [DYNAREC] Some trace improvments 2020-05-02 19:17:44 +02:00
ptitSeb e4914a2139 Rollback CPUID detection code until I found why Unreal crashes with it 2020-05-01 21:42:18 +02:00
ptitSeb 704c4b36ab Added support for CPUID detection in PUSHF/POPF 2020-05-01 09:32:47 +02:00
ptitSeb b9d61108bf Added a few wrapped function (should help X3) 2020-05-01 09:01:56 +02:00
ptitSeb e92d2f737b Small thread improvment 2020-04-30 21:10:10 +02:00
ptitSeb 6ec36072c4 A bit more wrapped libz functions 2020-04-30 15:06:00 +02:00
ptitSeb ab18d4d23a [DYNAREC] Fix build for non-trace enabled build (fix #105) 2020-04-30 14:01:28 +02:00
ptitSeb 1e6893a9d9 [DYNAREC] Added a few more opcodes (Int3 and FXSAVE/FXRSTOR) 2020-04-30 11:08:34 +02:00
ptitSeb 01bcc957e8 Added PSUBB opcode (should help 'The Journey Down Chapter One') 2020-04-29 14:44:39 +02:00
ptitSeb 3c989cfa04 Removed that yield in cond_broadcast, useless, and probably harming the performances 2020-04-28 18:55:18 +02:00
ptitSeb bde29ef155 Fixed some libz wrapped functions (fixed AM2R) 2020-04-28 18:41:23 +02:00
ptitSeb cee4cd26e0 [DYNAREC] Don't use x1, x2 or x3 scratch before use READFLAGS, also fixed the the bordercase fix call/ret optim (all this fixed zsnes and starfox) 2020-04-28 17:42:57 +02:00
ptitSeb f774b88211 [DYNAREC] Fixed PUSHAD/POPAD opcode, also small fix on border case for Call/Ret optimisation 2020-04-28 17:42:57 +02:00
ptitSeb 251f9b7338 Update README.md 2020-04-27 10:24:17 +02:00
ptitSeb dd5fc10a95 [DYNAREC] Optimised CALL/RET by using a local stack in x6emu_t struct (large improvment in some game, but doesn't help ShovelKnight) 2020-04-26 22:39:40 +02:00
ptitSeb 5e84efc542 Remove test on x87 stack status 2020-04-26 15:15:25 +02:00
ptitSeb b29fd4abbd [DYNAREC] Added missing change from previous commit 2020-04-26 15:15:03 +02:00
ptitSeb 1c6f2254f3 [DYNAREC] Store current block in table linker, to help find next block 2020-04-25 15:14:23 +02:00
ptitSeb 73685273f4 Added wrapped libdrm (almost empty) 2020-04-24 19:26:59 +02:00
ptitSeb 76d070777f Added a few wrapped functions to xcb, fontconfig and freetype 2020-04-24 17:23:21 +02:00
ptitSeb 42d18f7302 Added libstdc++.so.5 (along with the .6) in x86libs (usefull in some older games) 2020-04-24 16:15:25 +02:00
ptitSeb 963a7a527a On system where getrandom syscall is not supported, read /dev/urandom and not /dev/random 2020-04-24 12:02:05 +02:00
ptitSeb df61ed3048 [DYNAREC] Fixed potential issue when an opcode is not handled by the dynarec (fixed TeamSpeak3, for good) 2020-04-24 12:01:16 +02:00
ptitSeb 2a8e6061a2 Added BOX86_NOSIGILL 2020-04-24 11:11:22 +02:00
ptitSeb 96c4fe7057 Some changes in signal hanbdling (not sure it's a good idea) 2020-04-24 10:51:11 +02:00
ptitSeb 124df9ae83 Also add my_getrandom fallback to wrapped libc syscall 2020-04-24 08:30:49 +02:00
ptitSeb 62b2eecf6e Some system (like the Pandora) don't have the getrandom syscall 2020-04-24 08:26:29 +02:00
ptitSeb 9fb6b7bbd9 Use align on come fctnl function (fixes TeamSpeak3 server) 2020-04-23 22:27:15 +02:00
ptitSeb 0ac7929230 Added syscall 355 2020-04-23 21:39:38 +02:00
ptitSeb d16e8f1c51 Added some aio_*64 wrapped function to librt 2020-04-23 21:30:39 +02:00
ptitSeb 4b59f04930 Small fixes to some gobject signals 2020-04-23 16:06:12 +02:00
ptitSeb 7a375136cc Cosmetics in myalign.c 2020-04-23 16:05:49 +02:00
ptitSeb 62a328af45 Go back to using SharedCallback for qsort and qsort_r (should be faster and more reliable) 2020-04-23 08:37:42 +02:00
ptitSeb aafe35dca7 Changed how MMAP memory is alloced/freed 2020-04-22 14:40:27 +02:00
ptitSeb c73b728255 More cosmetic changes 2020-04-22 14:40:01 +02:00
ptitSeb 1186072e48 Added a sched_yield before cond_brodcast, just in case Dynarec is building a block with a cond_wait inside (to be tested) 2020-04-22 14:38:42 +02:00
ptitSeb 141de19804 Misc cosmetic changes 2020-04-22 14:37:41 +02:00
ptitSeb 97d71dfe09 [DYNAREC] Fixed some printer issues 2020-04-22 14:32:30 +02:00
ptitSeb f05b4fa7ff Some small changes to pthread_register_cancel, again, to hopefully have something working 100% 2020-04-21 19:34:37 +02:00
ptitSeb 2f36ec82f9 Made my_context global, plus some warning hunting... 2020-04-21 15:12:29 +02:00
ptitSeb c386a0a356 [DYNAREC] Warning hunt... 2020-04-21 15:11:57 +02:00
ptitSeb 4ba1f972b5 [DYNAREC] Fixed some emiter (missing parenthesis) 2020-04-21 13:50:08 +02:00
ptitSeb 525eb10854 [DYNAREC] Ooops, fixed ROR Ed, Ib opcode 2020-04-20 18:36:16 +02:00
ptitSeb 7176b08882 Fixed some potentiel memory overwrite (should help #102) 2020-04-20 16:57:32 +02:00
ptitSeb a6f4248502 [DYNAREC] Added complete emiter for ror32c 2020-04-20 12:18:14 +02:00
ptitSeb f0da6dd64f [DYNAREC] Added complete emiter for rol32c 2020-04-20 11:31:03 +02:00
ptitSeb af3c9042c3 Disabling that pthread_cancel test, box86 is still too unstable on that it seems 2020-04-19 21:38:40 +02:00
ptitSeb d8aa65bc17 Update README.md 2020-04-19 19:40:27 +02:00
ptitSeb da6ab3f752 Update README.md 2020-04-19 19:39:33 +02:00
ptitSeb 3cdf7fe742 Update README.md 2020-04-19 19:38:38 +02:00
ptitSeb cb54d7e343 Update README.md 2020-04-19 19:38:02 +02:00
ptitSeb 60611e54f3 [RPI] Call sanitize_mojosetup_gtk_background also on uninstall, to avoid extreme sluginess of the GUI 2020-04-19 19:33:17 +02:00
ptitSeb a4a78681ef More improvement to pthread_register_cancel handling 2020-04-19 17:56:15 +02:00
ptitSeb 4d85147077 Fixed a mamory averwriting issue 2020-04-19 17:55:27 +02:00
ptitSeb 857048f47c Small change in the init phase 2020-04-19 17:19:15 +02:00
ptitSeb 6084102d20 More improvement to thread_cancel_register mecanism 2020-04-19 16:52:31 +02:00
ptitSeb 2dc1fcc875 Improved handling of __pthread_register_cancel (and add a unit test about that) 2020-04-19 15:58:54 +02:00
ptitSeb 584479c10d Move around a bit thread helper initialization 2020-04-19 15:39:35 +02:00
ptitSeb 3430550dac Some attempt to improve __pthread_cancel_(un)register wrapped functions 2020-04-19 13:33:19 +02:00
ptitSeb 81f5bc79aa Various improvement to thread handling (should solve some memory issue when a lot of thread are created) 2020-04-19 13:33:19 +02:00
ptitSeb e20ccb7991 More changes to exec (now steam can start some game directly) 2020-04-19 13:33:19 +02:00
ptitSeb 5cf4af83b0 Update README.md 2020-04-18 15:42:47 +02:00
ptitSeb e5cb34d1f8 Update FUNDING.yml 2020-04-18 15:41:55 +02:00
ptitSeb 91c46f99a0 Update FUNDING.yml 2020-04-18 15:38:50 +02:00
ptitSeb dbdcaf8962 Create FUNDING.yml 2020-04-18 15:38:08 +02:00
ptitSeb 230d6246c6 Fixed a warning from previous commit 2020-04-18 15:32:20 +02:00
ptitSeb 066e5f966a Simplified some phtread wrapped functions 2020-04-18 15:24:16 +02:00
ptitSeb ff615cba03 Added preliminary FS: support 2020-04-18 15:06:08 +02:00
ptitSeb 631fa0f536 Move box86 on top of user memory (help Witcher 2, but not enough, as it use FS:) 2020-04-18 14:35:50 +02:00
ptitSeb ce2eb76703 Small changes in sem_open and set priority on threads 2020-04-18 10:56:15 +02:00
ptitSeb 9422039e09 Added IMG_LoadTexture and friend wrapped funcito to sdl2image 2020-04-17 22:24:47 +02:00
ptitSeb 0f13eb8611 More log for exev* wrapped functions 2020-04-17 21:49:59 +02:00
ptitSeb 196394f666 Added dummy syscall 243 (need work for a proper implementation 2020-04-17 21:49:21 +02:00
ptitSeb 9b2f7029df Improved elfloader to support elf with 'fragmented' memory map 2020-04-17 15:48:35 +02:00
ptitSeb a2e6b57c35 Simplified handling of exevl* 2020-04-17 14:02:24 +02:00
ptitSeb e5fdb4ba85 [DYNAREC] Added complete emiter for sar32c 2020-04-17 14:02:03 +02:00
ptitSeb 0c83522296 [DYNAREC] Fixed needed_flags function 2020-04-16 19:23:54 +02:00
ptitSeb f59e30442a Proprer support for timer_create with notify to SIGEV_THREAD 2020-04-16 17:40:00 +02:00
ptitSeb b67b750009 [DYNAREC] Added shr32c complete emiter 2020-04-16 15:41:02 +02:00
ptitSeb 61f2a43628 [DYNAREC] Reduce the recursivity of needed_flags function 2020-04-16 12:09:08 +02:00
ptitSeb 769545ccd7 Add proper support for RPATH with 2020-04-16 11:15:46 +02:00
ptitSeb c0b9272b82 Fixed ODroid and GameShell profile help that were mixed up 2020-04-16 09:30:40 +02:00
ptitSeb d5e5cbb393 Added ODROID profile 2020-04-16 07:52:09 +02:00
ptitSeb d8251ec441 Fix link on non-dynarec build 2020-04-16 07:40:47 +02:00
ptitSeb 0a04ef44d4 [DYNAREC] Fix issue when code use lots of FPU code with a few jump (i.e. x87 with loops), on dynarec pass 1 (helps Hotline Miami, and probably others) 2020-04-15 22:25:50 +02:00
ptitSeb 79ada49fdc Added some workaround to get steam somehow running 2020-04-15 21:36:08 +02:00
ptitSeb 1bf134c3ef Fixed interpretor for PALIGNR SSSE3 opcode 2020-04-15 16:54:56 +02:00
ptitSeb 38098290b7 [DYNAREC] Fixed psrlw and psraw opcode 2020-04-15 15:49:46 +02:00
ptitSeb b66c95d920 [DYNAREC] Added neg8 complete emiter 2020-04-15 15:42:35 +02:00
ptitSeb 25ae0f9311 [DYNAREC] Added neg16 complete emiter 2020-04-15 13:04:08 +02:00
ptitSeb f63799ecbb [DYNAREC] Small fixes to NEG and XADD opcodes 2020-04-15 12:03:25 +02:00
ptitSeb f2de080c68 [DYNAREC] Added shl32c complete emiter 2020-04-15 11:28:22 +02:00
ptitSeb 4ceaa7bd4b More workround on fcntl F_SETFL 2020-04-15 11:20:02 +02:00
ptitSeb 5753983f41 Fixed fctnl and fcntl64 wrapped function that weren't converting some parameter (should help OSS game, among other things) 2020-04-15 08:40:16 +02:00
ptitSeb 58768ca886 Merge pull request #97 from PokeEngineer/master
Include sysmacros.h in elfloader.c
2020-04-15 07:38:40 +02:00
Jacob Mullins d3d740c38f Included sysmacros.h
Some compilers (like the one on the GameShell) need this to be included or you get undefined references to "major," "minor," and "makedev."
2020-04-15 00:43:57 -04:00
ptitSeb 27f99bd3c0 Added some basic /proc/self/maps emulation (missing heap, stack and loaded lib) 2020-04-14 20:18:22 +02:00
ptitSeb 230fa96d2b Added basic support for RPATH 2020-04-14 14:27:08 +02:00
ptitSeb 1e7f5692ce Added syscall 266 2020-04-13 10:41:40 +02:00
ptitSeb af884e427d [DYNAREC] Added PSRAW/PSRAD/PRSRLW/PSRLD opcodes 2020-04-12 10:53:58 +02:00
ptitSeb 00b2002855 Added PAVGB and PAVGW SSE2 opcodes (also in DYNAREC) 2020-04-12 10:10:47 +02:00
ptitSeb e5d20ea8ae [DYNAREC] Fixed isue with CLC and STC opcodes 2020-04-12 09:37:01 +02:00
ptitSeb 3b4ca235d5 [DYNAREC] Added neg32 complete emiter with flags 2020-04-11 18:37:40 +02:00
ptitSeb 8633aca6fa Fixes isNativeCall (help FTL) 2020-04-11 18:17:14 +02:00
ptitSeb 85dde4b9d0 [DYNAREC] Assorted bugfixes (but still an issue in zsnes somewhere) 2020-04-11 15:30:58 +02:00
ptitSeb 43e981579f [DYNAREC] Added sbb8 and sbb16 complete emiter with flags 2020-04-10 10:44:31 +02:00
ptitSeb f12706599e [DYNAREC] Added sbb32 complete emiter with flags 2020-04-10 09:57:58 +02:00
ptitSeb 650668eaf7 [DYNAREC] Added adc16 complete emiter with flags 2020-04-10 08:41:43 +02:00
ptitSeb 6093589e41 [DYNAREC] Added adc8 complete emiter with flags 2020-04-09 23:38:37 +02:00
ptitSeb ce777c9393 [DYNAREC] Added complete emiter with flags for adc32 2020-04-09 22:55:50 +02:00
ptitSeb 983523c2f6 [DYNAREC] Inc/Dec doesn't change CC, plus many fixes on emiter with flags... 2020-04-09 20:02:47 +02:00
ptitSeb 8f5843e0fe [DYNAREC] Added or16/xor16/and16 and use the emiters 2020-04-09 18:24:09 +02:00
ptitSeb 98b0602ae5 [DYNAREC] Added complete emiter for sub16, and converted SUB and INC/DEC 16 opcodes 2020-04-09 17:06:10 +02:00
ptitSeb 0286e8362e [DYNAREC] Use emit_add8/32 and emit_sub8/32 for inc/dec opcodes 2020-04-09 16:20:38 +02:00
ptitSeb bcfc464f24 [DYNAREC] Fixed add8/sub8 and added complete emiter with flags for add16 2020-04-09 14:51:42 +02:00
ptitSeb 7a9e9df3c0 [DYNAREC] Added complete emiter with flags for or8, xor8 and and8 2020-04-09 11:49:28 +02:00
ptitSeb 829bf941f4 [DYNAREC] Added complete emiter for sub8 opcodes 2020-04-09 10:48:26 +02:00
ptitSeb 3e42161c35 [DYNAREC] Also use emit_addXX on XADD opcodes 2020-04-09 10:47:54 +02:00
ptitSeb 9cdaa5e028 [DYNAREC] Fixed some logic complete emiter (with constant) 2020-04-09 08:02:35 +02:00
ptitSeb 34ef7b9b79 [DYNAREC] Added more complete emiter, plus some reorganisation of sources 2020-04-08 21:59:56 +02:00
ptitSeb 201677899b [DYNAREC] Created emiter (with flags) for add32 and sub32 2020-04-08 18:56:00 +02:00
ptitSeb fd563c5b4b [DYNAREC] Fun with flags: improved Carry flag handling 2020-04-07 17:50:15 +02:00
ptitSeb d5b5031f5c [DYNAREC] Fun with flags: added the X_PEND flags to calculate flags + setting defered 2020-04-07 17:40:32 +02:00
ptitSeb 08f2fcd1b9 [DYNAREC] Fun with flags: done all test emiter too. 2020-04-06 16:38:45 +02:00
ptitSeb f7da6bc070 [DYNAREC] Fun with flags: Continue adding all cmp emiter, plus some bug fixes 2020-04-06 16:02:31 +02:00
ptitSeb 1414fed3b2 [DYNAREC] Added optionnal Coloring to Dump 2020-04-06 16:01:36 +02:00
ptitSeb 13ff5c80be [DYNAREC] Fun with flags: Optimized cmp16_0 emiter 2020-04-05 21:17:29 +02:00
ptitSeb 782dd645c3 [DYNAREC] Fun with flags: Optimized cmp16 emiter 2020-04-05 21:13:47 +02:00
ptitSeb 020bcd46c2 [DYNAREC] Fun with flags: Optimized cmp32_0 emiter 2020-04-05 21:08:02 +02:00
ptitSeb fefb01f930 [DYNAREC] Func with flags: optimzed cmp32 emiter 2020-04-05 21:02:38 +02:00
ptitSeb 6489a2ca3b [DYNAREC] Fun with flags: fixed a typo 2020-04-05 21:02:16 +02:00
ptitSeb cbe4ec30d1 [DYNAREC] Fun with flags: optimize FCOMI emiter 2020-04-05 20:35:22 +02:00
ptitSeb 38a9b04ce0 [DYNAREC] Change the way X86 Flags are handled 2020-04-05 20:10:18 +02:00
ptitSeb 7de59621c4 Changed how ROR and ROL handle flags (less exact but faster, seems ok on all tests) 2020-04-04 11:11:46 +02:00
ptitSeb e9560dd916 [DYNAREC] Improved is_nops function 2020-04-02 18:19:50 +02:00
ptitSeb 91fec006ae [DYNAREC] Improved dynarec by allowing each block to be bigger 2020-04-02 08:26:18 +02:00
ptitSeb 82af74c459 [PANDORA] Fix for the use of tremor in SDL(1/2)_mixer 2020-04-01 15:35:47 +02:00
ptitSeb 32dc46efac [DYNAREC] Improve DUMP info a bit 2020-04-01 13:05:41 +02:00
ptitSeb 020b94794b [DYNAREC] Removed duplicate include 2020-03-31 21:52:27 +02:00
ptitSeb bb59ef692e Improved a bit a warning message 2020-03-31 21:51:58 +02:00
ptitSeb 8280d4628d Fixed a few wrapped functions prototypes 2020-03-30 16:39:46 +02:00
ptitSeb 91c6a71353 [DYNAREC] Fixed CMPXCHG opcode (helps Telsagrad, and probably others) 2020-03-30 16:21:10 +02:00
ptitSeb fa9e8223b9 [DYNAREC] Fixed memory allocated with mmap64 that was tracked (fix Unity/Mono JIT not beeing Dynarec'd correctly) 2020-03-30 15:11:08 +02:00
ptitSeb 7057ce7a2c Fixes to some libc wrapper functions with callback (fixed Teslagrad) 2020-03-30 14:16:04 +02:00
ptitSeb b98febce24 Added one more synonim for SDL2 2020-03-29 15:52:40 +02:00
ptitSeb 11758cfa90 Improvments to libc wrapped function with callback 2020-03-29 09:38:26 +02:00
ptitSeb a37928110d Some improvments to vorbisfile wrapped lib 2020-03-29 09:38:02 +02:00
ptitSeb a3c7674676 [DYNAREC] Added PMADDUBSW opcode 2020-03-28 20:43:07 +01:00
ptitSeb ed68b17bac [DYNAREC] Added PACKSSWB opcode, and changed a MOVD one to avoid some BusError 2020-03-28 17:40:24 +01:00
ptitSeb aa86b8ecf4 [DYNAREC] Added PADDSB opcode 2020-03-28 17:04:44 +01:00
ptitSeb e0c5630ed7 [DYNAREC] Added PSUBSB opcode 2020-03-28 17:01:39 +01:00
ptitSeb c4b4107f57 [DYNAREC] Added PCMPEQB opcode 2020-03-28 16:58:08 +01:00
ptitSeb d198f6c64a [DYNAREC] Added PADDUSB opcode 2020-03-28 16:52:05 +01:00
ptitSeb fd3812c27e [DYNAREC] Added PSADBW and PMAXUB 2020-03-28 16:46:08 +01:00
ptitSeb ddbffd874b [DYNAREC] Added PSHUFB SSE3 opcode 2020-03-28 15:02:08 +01:00
ptitSeb bc1b5bed0b Refactored (and simplified) libc functions with callbacks 2020-03-28 14:04:37 +01:00
ptitSeb f7019e0ff8 Added 2 SSE3 opcodes 2020-03-28 14:01:58 +01:00
ptitSeb e47f88f4f3 Changed (optimized?) a bit the idiv operations 2020-03-28 14:01:35 +01:00
ptitSeb baf750b89a Added one dummy libc wrapped function 2020-03-28 10:39:30 +01:00
ptitSeb bea256ddc6 Added wrapped lib Xmu (with 2 functions) 2020-03-28 10:25:28 +01:00
ptitSeb e7f841b71e Made looking for emulated libs more resiliant 2020-03-27 22:19:54 +01:00
ptitSeb 1df10d7a48 [DYNAREC] Added UD2 opcode 2020-03-27 21:50:54 +01:00
ptitSeb 53c4a0d418 More SDL2 wrapped functions 2020-03-26 20:48:19 +01:00
ptitSeb 883f1990c6 Added some more GS: opcodes 2020-03-25 23:02:22 +01:00
ptitSeb c2efed56e0 Added 1 libX11 wrapped function 2020-03-25 19:28:21 +01:00
ptitSeb 37814194ae [PANDORA] Try some workaround for Xxf86vm Gamma issues 2020-03-25 14:29:54 +01:00
ptitSeb 03cc86c6d1 Added a few libc wrapped functions 2020-03-25 11:58:42 +01:00
ptitSeb 206f5d3aa8 Added barely used 82 opcode (same as 80) [DYNAREC] too 2020-03-25 11:41:36 +01:00
ptitSeb d5c71f3dcc Added FPREM1 opcode 2020-03-25 11:14:55 +01:00
ptitSeb 1ed35d06c7 Add some fail safe on program that use _IO_2_1_st* symbols 2020-03-25 08:56:31 +01:00
ptitSeb 4456ab2ab5 Add a libc symbol 2020-03-25 08:55:55 +01:00
ptitSeb 645297de61 Added one new syscall 2020-03-24 18:02:25 +01:00
ptitSeb 71dbfda219 Added 2 X11 wrapped functions 2020-03-24 17:06:28 +01:00
ptitSeb c8977e68d0 Added a wrapped x11 function 2020-03-23 13:57:58 +01:00
ptitSeb 9b1bfb17b0 Expose SSE3 and SSSE3 2020-03-23 13:46:25 +01:00
ptitSeb 95858b46b0 [DYNAREC] Changed MOVQ 0f 7f opcode to avoid potential Bus Error (helps steam) 2020-03-23 13:31:48 +01:00
ptitSeb d7ca13e7f7 Added wrapped libnm (also as a replacement for libnm-glib and libnm-util, to help steam, but need network-manager-gnome package) 2020-03-22 19:05:33 +01:00
ptitSeb a17dfe8ed6 Added a few gtk wrapped functions 2020-03-22 17:10:45 +01:00
ptitSeb 1d9eb8fa17 Added some more gio2 wrapped functions 2020-03-22 16:58:16 +01:00
ptitSeb 6d8e64a213 Added gudev wrapped functions 2020-03-22 14:55:45 +01:00
ptitSeb c5859a0d92 Added a large bunch of glib2 / gobject2 / gio2 wrapped functions 2020-03-22 14:38:23 +01:00
ptitSeb 058b199606 Added a large bunch of dbus and dbus-glib1 wrapped functions 2020-03-22 08:45:29 +01:00
ptitSeb 5b58985fdf One more glib2 wrapped function 2020-03-21 20:42:44 +01:00
ptitSeb b9e1192d69 Added more slot to gobject2 callbacks 2020-03-21 19:31:42 +01:00
ptitSeb 1d0a575773 Try to define all gobject cclosur_marshaler as DATA and not wrapped functions 2020-03-21 19:22:29 +01:00
ptitSeb 72e3e36f1b Added wrapped dbusmenu-glib library 2020-03-21 18:54:35 +01:00
ptitSeb bd2271de86 Fixed a wrapped gobject2 function (and steam is almost starting) 2020-03-21 17:52:42 +01:00
ptitSeb ffa2aa6f1c Added a few more libc wrapped functions 2020-03-21 16:44:49 +01:00
ptitSeb c0d35aa6e7 Some (speed) improvement to wrapped pulse library 2020-03-21 15:58:07 +01:00
ptitSeb 11c1396d83 Small change in epool_ctl wrapped function 2020-03-21 15:57:43 +01:00
ptitSeb 41e6ba1030 Init new stacks to 0 (in line with x86 behavour?) 2020-03-21 15:57:13 +01:00
ptitSeb e92e9043fa Fixed some multi-threaded libpulse wrapped functions 2020-03-21 15:29:56 +01:00
ptitSeb c53ab30b2e Improved autodetect of binary, and added special case for steam 2020-03-21 12:34:53 +01:00
ptitSeb c763ca269a Smalls changes on libudev wrapped function 2020-03-21 11:59:16 +01:00
ptitSeb bf4c05c41c Added a few more gobject2 wrapped functions 2020-03-21 10:06:22 +01:00
ptitSeb 9b9130ed57 Added a few more dbug-glib2 wrapped functions 2020-03-20 19:51:18 +01:00
ptitSeb 5fde277748 Added a wrapped function to gobject2 2020-03-19 21:39:07 +01:00
ptitSeb 7757666a0b Added some more glib2 wrapped functions 2020-03-18 21:00:29 +01:00
ptitSeb 4bc52873f7 Added some glib2 wrapped functions 2020-03-17 22:16:53 +01:00
ptitSeb a5a38203ae Added some gio dbus wrapped functions 2020-03-16 17:57:23 +01:00
ptitSeb 1209862996 Fixed fprintf trace (in case it's in fact __fprintf_chk that is called) 2020-03-16 17:56:57 +01:00
ptitSeb 4f0bb1010d Fixed return value for dladdr wrapped function 2020-03-15 15:29:03 +01:00
ptitSeb 050b974051 [DYNAREC] Fixed a MOVQ mmx opcode 2020-03-15 12:41:13 +01:00
ptitSeb 88fb7efec3 Use fopen64 and fseeko64 on main binary so >4Gb file can be open (now psychonauts installer can be run) 2020-03-15 09:53:39 +01:00
ptitSeb a91c562dcf Removed old monounity wrapped lib attempt (not working well enough) 2020-03-14 12:52:27 +01:00
ptitSeb f1a136c9b4 Added libXdamage wrapped lib (complete) 2020-03-13 20:21:43 +01:00
ptitSeb 57583b39e7 Added libXcomposite wrapped library (complete) 2020-03-13 19:31:13 +01:00
ptitSeb 3467ea2476 Added some more libcrypto wrapped functions 2020-03-12 20:23:23 +01:00
ptitSeb 0e6daf412d Fixed execl wrapped functions 2020-03-12 20:23:11 +01:00
ptitSeb 8468c5318d Improve trace, especialy in BUILDLIB scenario 2020-03-11 20:29:49 +01:00
ptitSeb 853f4865ce [BUILDLIB] Add some failsafe fallback for getauxval 2020-03-10 20:57:21 +01:00
ptitSeb 0742c694b0 Added a few gtk wrapped functions 2020-03-09 20:13:13 +01:00
ptitSeb 247622a6db [DYNAREC] Small change in how JIT'd code in handled in the linker 2020-03-08 16:36:26 +01:00
ptitSeb cbd4b4f73a Fixed an issue with TLS data (and now hotline_launcher works) 2020-03-08 15:59:05 +01:00
ptitSeb 3782d7f4df [TRACE] Fixed start of symbol that was not printed in the trace 2020-03-08 12:08:20 +01:00
ptitSeb bc13894b31 Added lots of libxcb wrapped functions 2020-03-08 11:24:57 +01:00
ptitSeb d6ff293d7f [BUILD] Added dependancie on wrapped functions between .c and _private.h 2020-03-07 17:11:11 +01:00
ptitSeb 9e2ba671b8 Added some FontConfig wrapped functions 2020-03-07 16:19:44 +01:00
ptitSeb fb56c5f422 Added a few more X11 wrapped functions 2020-03-07 13:03:54 +01:00
ptitSeb a45d6bd79b Added some wrapped function used by gtk-1.2 2020-03-06 15:53:47 +01:00
ptitSeb 28a26db054 Added dontstarve autodetect to force use of emulated SDL2 2020-03-06 10:17:35 +01:00
ptitSeb 95782e7311 Remove import glob from wrapper generator, not used anymore 2020-03-06 09:51:17 +01:00
ptitSeb 5f6221de7f [DYNAREC] Added TZCNT opcode 2020-03-06 09:50:26 +01:00
ptitSeb b42ac3eb11 Revert stat / lstat change 2020-03-05 18:32:32 +01:00
ptitSeb 2964727959 Reworked py generator to avoid useless recompiles 2020-03-05 17:05:15 +01:00
ptitSeb fca7808b55 [DYNAREC] Added a few more opcodes 2020-03-05 14:21:15 +01:00
ptitSeb 07c98d30ad [DYNAREC] Add preliminary support for JIT'd code 2020-03-05 11:41:43 +01:00
ptitSeb a7c95a783e [DYNAREC] Added a few opcodes 2020-03-05 11:40:49 +01:00
ptitSeb e84ebce421 [DYNAREC] Dump of Dynarec blocks is now a seprated option 2020-03-05 11:39:56 +01:00
ptitSeb 0df765bbbd Fixed some type in USAGE 2020-03-04 13:19:02 +01:00
ptitSeb 2af2fbfe6d [DYNAREC] Preliminary work to support JIT'd code in Dynarec 2020-03-03 16:09:24 +01:00
ptitSeb 96f5f92b09 Fixed some typo is libgthread2 wrapped lib 2020-03-03 10:25:01 +01:00
ptitSeb dedd7f4827 Use lstat instead of stat on filexist function (alow use of symlink of libs) 2020-03-02 16:57:52 +01:00
ptitSeb 28a066a7c9 Added a few more pulse wrapped functions (should help Paper, Please) 2020-03-02 14:40:43 +01:00
ptitSeb 6377884c4a Improved emulation of dl_iterate_phdr (fixed Paper, Please) 2020-03-02 13:56:23 +01:00
ptitSeb 41cc61e4c7 Fixed an issue with a wrapped function in gtk 2020-03-01 14:40:04 +01:00
ptitSeb 73e13baa84 And more SDL2 wrapped functions 2020-03-01 13:03:23 +01:00
rajdakin 403707bb5b A few more SDL2 wrapped functions 2020-03-01 11:02:06 +01:00
ptitSeb 873bdd793a Some more SDL2 wrapped functions 2020-02-29 09:49:41 +01:00
ptitSeb edbd6cdfa5 A few more SDL2 wrapped functions 2020-02-28 18:37:50 +01:00
ptitSeb e7a9679a20 More SDL2 wrapped functions 2020-02-27 21:28:20 +01:00
ptitSeb b9d09acf92 Added a few SDL2 wrapped functons 2020-02-26 22:04:30 +01:00
ptitSeb 7a02b1720e Fixed glXProcAddress and alGetProcAddress when querying a my_ wrapped functions (fixed Isaac Aftyerbirth, and probably others games) 2020-02-15 21:26:53 +01:00
ptitSeb 3c88e8aac0 Added a few wrapped functions to wrandr and dbus 2020-02-15 20:11:29 +01:00
ptitSeb df4e93973b [DYNAREC] revert the use of TryLock, it fallback to interpretor too often 2020-02-15 19:48:59 +01:00
ptitSeb c3dbe47f3c [DYNAREC] Fixed x87 TAG issues (causing massive FPU under/over flow messages) 2020-02-15 19:48:25 +01:00
ptitSeb af91d80c94 Added some handling of TAG for x87 emulation (DYNAREC too) 2020-02-15 18:22:46 +01:00
ptitSeb a133621934 Use Trylock instead of Lock RWMutex in Dynarec block creation, to allow fallback to Interpreter instead of waiting 2020-02-15 16:00:48 +01:00
ptitSeb 329bddc4f6 Avoid Dynarec in signal handler, to avoid potentiel deadlocks 2020-02-15 15:59:57 +01:00
ptitSeb 31785d6fbe Added wrapped mkstemps64 function 2020-02-15 12:53:45 +01:00
ptitSeb c7bf006b49 Added better support for pthread_cleanup_push and pop macros (help Unity games) 2020-02-14 10:47:15 +01:00
ptitSeb 3fc1458cc2 Added a few more SDL2 wrapped functions 2020-02-13 20:21:29 +01:00
ptitSeb 53be7dad84 Added better handing of thread stack querying 2020-02-12 17:29:46 +01:00
ptitSeb 7507a0f20f Added a few SDL2 wrapped functions 2020-02-11 20:20:12 +01:00
ptitSeb 32a6711898 Small improvment on trace, to avoid potention deadlock or segfault 2020-02-10 20:19:42 +01:00
ptitSeb 223c6513ba Simplified pulsesimple, as it use full pulse now 2020-02-09 10:47:41 +01:00
ptitSeb d395df1f37 [DYNAREC] Prepare SDIV and UDIV emmiter (but no use yet) 2020-02-08 15:58:28 +01:00
ptitSeb f5a7d96a77 [DYNAREC] Added support for SWP opcode when handling XCHG x86 opcode 2020-02-08 12:34:38 +01:00
ptitSeb 81ae020273 [DYNAREC] Added detection of hardware cpu extensions 2020-02-08 10:57:24 +01:00
ptitSeb 57024db6e6 Improved getauxval handling 2020-02-07 08:18:25 +01:00
ptitSeb e507b964a1 Added actual getauxval wrapped function, and support for native getauxval 2020-02-06 22:48:12 +01:00
ptitSeb d2bff48e88 New developpement cycle 2020-02-06 22:01:12 +01:00
258 changed files with 37037 additions and 11119 deletions

No files matched your search

+12
View File
@@ -0,0 +1,12 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
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
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: paypal.me/0ptitSeb
+3 -2
View File
@@ -1,4 +1,5 @@
build
build*
build/
build*/
.vscode
.gdb_history
src/git_head.h
Executable
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Executable
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

+18
View File
@@ -1,3 +1,21 @@
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)
+132 -12
View File
@@ -10,7 +10,8 @@ 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(GAMESHELL "Set to ON if targeting a Gameshell device" ${GAMESHELL})
option(GAMESHELL "Set to ON if targeting a GameShell device" ${GAMESHELL})
option(ODROID "Set to ON if targeting an ODroid device" ${ODROID})
option(USE_CCACHE "Set to ON to use ccache if present in the system" ${USE_CCACHE})
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})
@@ -20,11 +21,30 @@ option(NOLOADADDR "Set to ON to avoid fixing the load address of Box86" ${NO_LOA
option(ARM_DYNAREC "Set to ON to use ARM Dynamic Recompilation (WIP, don't use yet)" ${ARM_DYNAREC})
option(NOGETCLOCK "Set to ON to avoid using clock_gettime with CLOCK_MONOTONIC_COARSE for RDTSC opcode (use gltimeofday instead)" ${NOGETCLOCK})
find_package(PythonInterp)
if(NOT PYTHONINTERP_FOUND)
message( FATAL_ERROR "You need a Python interpretor, CMake will exit." )
if(${CMAKE_VERSION} VERSION_LESS "3.12.2")
find_package(PythonInterp 3)
if(NOT PYTHONINTERP_FOUND)
message( FATAL_ERROR "You need a Python interpretor, CMake will exit." )
endif()
if(${PYTHON_VERSION_MAJOR} LESS 3)
message( FATAL_ERROR "You need a Python 3 interpretor, CMake will exit." )
endif()
else()
find_package(Python3)
if(NOT Python3_Interpreter_FOUND)
message( FATAL_ERROR "You need a Python interpretor, CMake will exit." )
endif()
set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE} CACHE INTERNAL "The Python3 executable" FORCE)
endif()
set(default_build_type "RelwithDebInfo")
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()
# Pandora
if(PANDORA)
add_definitions(-DPANDORA)
@@ -78,6 +98,15 @@ if(RPI4)
set(LD80BITS OFF)
set(NOALIGN OFF)
endif()
if(ODROID)
add_definitions(-mcpu=cortex-a9 -mfpu=neon-vfpv4 -mfloat-abi=hard -marm)
set(CMAKE_ASM_FLAGS "-marm -mcpu=cortex-a9 -mfpu=neon-vfpv4 -mfloat-abi=hard")
set(ARM_DYNAREC ON)
set(LD80BITS OFF)
set(NOALIGN OFF)
endif()
set(BOX86_ELF_ADDRESS "0x02800000")
if(LD80BITS)
add_definitions(-DHAVE_LD80BITS)
@@ -108,6 +137,9 @@ endif()
if(BOX86LIB)
add_definitions(-DBUILD_LIB)
if(BOX86DYNAMIC)
add_definitions(-DBUILD_DYNAMIC)
endif()
add_definitions(-fPIC)
if(NOT BOX86_ROOT)
message(FATAL_ERROR "BOX86_ROOT not set when build as lib")
@@ -117,7 +149,7 @@ else()
endif()
add_definitions(-g -std=gnu99 -funwind-tables -O3 -fvisibility=hidden)
add_definitions(-std=gnu99 -funwind-tables -fvisibility=hidden)
if(USE_CCACHE)
find_program(CCACHE_FOUND ccache)
@@ -133,15 +165,26 @@ include_directories(
"${BOX86_ROOT}/src/wrapped/generated"
)
add_custom_command(
OUTPUT "${BOX86_ROOT}/src/git_head.h"
COMMAND bash -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\"\>${BOX86_ROOT}/src/git_head.h"
DEPEND "${BOX86_ROOT}/src/build_info.c"
VERBATIM
)
set(ELFLOADER_SRC
"${BOX86_ROOT}/src/git_head.h"
"${BOX86_ROOT}/src/main.c"
"${BOX86_ROOT}/src/box86context.c"
"${BOX86_ROOT}/src/build_info.c"
"${BOX86_ROOT}/src/tools/bridge.c"
"${BOX86_ROOT}/src/tools/pathcoll.c"
"${BOX86_ROOT}/src/tools/fileutils.c"
"${BOX86_ROOT}/src/tools/callback.c"
"${BOX86_ROOT}/src/tools/box86stack.c"
"${BOX86_ROOT}/src/tools/my_cpuid.c"
"${BOX86_ROOT}/src/tools/gtkclass.c"
"${BOX86_ROOT}/src/tools/wine_tools.c"
"${BOX86_ROOT}/src/elfs/elfloader.c"
"${BOX86_ROOT}/src/elfs/elfparser.c"
"${BOX86_ROOT}/src/elfs/elfload_dump.c"
@@ -155,10 +198,14 @@ set(ELFLOADER_SRC
"${BOX86_ROOT}/src/emu/x86primop.c"
"${BOX86_ROOT}/src/emu/x86trace.c"
"${BOX86_ROOT}/src/emu/x86int3.c"
"${BOX86_ROOT}/src/emu/x86tls.c"
"${BOX86_ROOT}/src/emu/x87emu_private.c"
"${BOX86_ROOT}/src/emu/x87run.c"
"${BOX86_ROOT}/src/libtools/auxval.c"
"${BOX86_ROOT}/src/libtools/myalign.c"
"${BOX86_ROOT}/src/libtools/myalign64.c"
"${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"
@@ -207,14 +254,19 @@ set(WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedlibxcb.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxtst.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxt.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxcomposite.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxdamage.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxmu.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibz.c"
"${BOX86_ROOT}/src/wrapped/wrappedopenal.c"
"${BOX86_ROOT}/src/wrapped/wrappedalut.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibjpeg.c"
"${BOX86_ROOT}/src/wrapped/wrappedcurl.c"
"${BOX86_ROOT}/src/wrapped/wrappedudev0.c"
"${BOX86_ROOT}/src/wrapped/wrappedudev1.c"
"${BOX86_ROOT}/src/wrapped/wrappeddbus.c"
"${BOX86_ROOT}/src/wrapped/wrappediconv.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibdrm.c"
"${BOX86_ROOT}/src/wrapped/wrappedcrypto.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibssl.c"
"${BOX86_ROOT}/src/wrapped/wrappedutil.c"
@@ -231,7 +283,10 @@ set(WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedlibusb1.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibncursesw.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibformw.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibncurses.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibtinfo.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibncurses6.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibtinfo6.c"
"${BOX86_ROOT}/src/wrapped/wrappedgtkx112.c"
"${BOX86_ROOT}/src/wrapped/wrappedgdkx112.c"
"${BOX86_ROOT}/src/wrapped/wrappedgdkpixbuf2.c"
@@ -242,6 +297,7 @@ set(WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedgstreamer010.c"
"${BOX86_ROOT}/src/wrapped/wrappedgstinterfaces010.c"
"${BOX86_ROOT}/src/wrapped/wrappeddbusmenugtk.c"
"${BOX86_ROOT}/src/wrapped/wrappeddbusmenuglib.c"
"${BOX86_ROOT}/src/wrapped/wrappedatk.c"
"${BOX86_ROOT}/src/wrapped/wrappedpangoft2.c"
"${BOX86_ROOT}/src/wrapped/wrappedpangocairo.c"
@@ -250,7 +306,10 @@ set(WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedpango.c"
"${BOX86_ROOT}/src/wrapped/wrappeddbusglib1.c"
"${BOX86_ROOT}/src/wrapped/wrappedgudev1.c"
# "${BOX86_ROOT}/src/wrapped/wrappedmonounity.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibnm.c"
"${BOX86_ROOT}/src/wrapped/wrappedtcmallocminimal.c"
"${BOX86_ROOT}/src/wrapped/wrappedmpg123.c"
"${BOX86_ROOT}/src/wrapped/wrappedgnutls.c"
"${BOX86_ROOT}/src/wrapped/wrappedldlinux.c"
)
@@ -258,11 +317,32 @@ set(WRAPPEDS_HEAD "")
foreach(A ${WRAPPEDS})
string(REPLACE ".c" "_private.h" B ${A})
set(WRAPPEDS_HEAD ${WRAPPEDS_HEAD} ${B})
set_source_files_properties(${A} PROPERTIES OBJECT_DEPENDS ${B})
endforeach()
set(WRAPPER "${BOX86_ROOT}/src/wrapped/generated/wrapper.c" "${BOX86_ROOT}/src/wrapped/generated/wrapper.h")
add_custom_command(OUTPUT ${WRAPPER} COMMAND "${PYTHON_EXECUTABLE}" "${BOX86_ROOT}/rebuild_wrappers.py" "${BOX86_ROOT}" "PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "USE_FLOAT" MAIN_DEPENDENCY "${BOX86_ROOT}/rebuild_wrappers.py" DEPENDS ${WRAPPEDS} ${WRAPPEDS_HEAD})
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" "USE_FLOAT" "--" ${WRAPPEDS_HEAD}
MAIN_DEPENDENCY "${BOX86_ROOT}/rebuild_wrappers.py"
DEPENDS ${WRAPPEDS} ${WRAPPEDS_HEAD}
BYPRODUCTS ${WRAPPER}
)
add_custom_command(
OUTPUT "${BOX86_ROOT}/src/dynarec/last_run.txt"
COMMAND "${PYTHON_EXECUTABLE}" "${BOX86_ROOT}/rebuild_printer.py" "${BOX86_ROOT}"
MAIN_DEPENDENCY "${BOX86_ROOT}/rebuild_printer.py"
DEPENDS "${BOX86_ROOT}/src/dynarec/arm_instructions.txt"
BYPRODUCTS "${BOX86_ROOT}/src/dynarec/arm_printer.c"
)
add_custom_target(WRAPPERS DEPENDS "${BOX86_ROOT}/src/wrapped/generated/functions_list.txt")
add_custom_target(PRINTER DEPENDS "${BOX86_ROOT}/src/dynarec/last_run.txt")
#this is to force build_info.c to be rebuilt all the time
set_source_files_properties("${BOX86_ROOT}/src/build_info.c" PROPERTIES OBJECT_OUTPUTS "dummy.c")
if(ARM_DYNAREC)
set(DYNAREC_SRC
@@ -280,9 +360,14 @@ if(ARM_DYNAREC)
set(DYNAREC_PASS
"${BOX86_ROOT}/src/dynarec/dynarec_arm_helper.c"
"${BOX86_ROOT}/src/dynarec/dynarec_arm_emit_tests.c"
"${BOX86_ROOT}/src/dynarec/dynarec_arm_emit_math.c"
"${BOX86_ROOT}/src/dynarec/dynarec_arm_emit_logic.c"
"${BOX86_ROOT}/src/dynarec/dynarec_arm_emit_shift.c"
"${BOX86_ROOT}/src/dynarec/dynarec_arm_pass.c"
"${BOX86_ROOT}/src/dynarec/dynarec_arm_00.c"
"${BOX86_ROOT}/src/dynarec/dynarec_arm_0f.c"
"${BOX86_ROOT}/src/dynarec/dynarec_arm_64.c"
"${BOX86_ROOT}/src/dynarec/dynarec_arm_65.c"
"${BOX86_ROOT}/src/dynarec/dynarec_arm_66.c"
"${BOX86_ROOT}/src/dynarec/dynarec_arm_67.c"
@@ -312,6 +397,10 @@ if(ARM_DYNAREC)
set_target_properties(arm_pass2 PROPERTIES COMPILE_FLAGS "-DSTEP=2")
add_library(arm_pass3 OBJECT ${DYNAREC_PASS})
set_target_properties(arm_pass3 PROPERTIES COMPILE_FLAGS "-DSTEP=3")
add_dependencies(arm_pass0 WRAPPERS)
add_dependencies(arm_pass1 WRAPPERS)
add_dependencies(arm_pass2 WRAPPERS)
add_dependencies(arm_pass3 WRAPPERS)
add_library(dynarec STATIC
$<TARGET_OBJECTS:dynarec_arm>
@@ -323,8 +412,22 @@ if(ARM_DYNAREC)
endif()
if(BOX86LIB)
#build a static lib...
add_library(box86 OBJECT ${ELFLOADER_SRC} ${WRAPPEDS})
#build a static or dynamic lib...
if(BOX86DYNAMIC)
add_library(box86 SHARED ${ELFLOADER_SRC} ${WRAPPEDS})
else()
add_library(box86 OBJECT ${ELFLOADER_SRC} ${WRAPPEDS})
endif()
if(ARM_DYNAREC)
target_link_libraries(box86 dynarec m dl rt pthread)
endif()
if(${CMAKE_VERSION} VERSION_LESS "3.13")
set_target_properties(box86 PROPERTIES LINK_FLAGS -rdynamic)
else()
target_link_options(box86 PUBLIC -rdynamic)
endif()
add_dependencies(box86 WRAPPERS)
add_dependencies(box86 PRINTER)
else(BOX86LIB)
@@ -337,13 +440,24 @@ else()
endif()
add_executable(${BOX86} ${ELFLOADER_SRC} ${WRAPPEDS})
add_dependencies(${BOX86} WRAPPERS)
add_dependencies(${BOX86} PRINTER)
target_link_libraries(${BOX86} m dl rt pthread)
if(ARM_DYNAREC)
target_link_libraries(${BOX86} dynarec)
endif()
if(NOT NOLOADADDR)
target_link_libraries(${BOX86} -Wl,-Ttext-segment,0x03800000)
if(${CMAKE_VERSION} VERSION_LESS "3.13")
if(NOT NOLOADADDR)
set_target_properties(${BOX86} PROPERTIES LINK_FLAGS "-rdynamic -Wl,-Ttext-segment,${BOX86_ELF_ADDRESS}")
else()
set_target_properties(${BOX86} PROPERTIES LINK_FLAGS -rdynamic)
endif()
else()
target_link_options(${BOX86} PUBLIC -rdynamic)
if(NOT NOLOADADDR)
target_link_options(${BOX86} PUBLIC -Wl,-Ttext-segment,${BOX86_ELF_ADDRESS})
endif()
endif()
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "i686" _x86)
@@ -354,6 +468,7 @@ if(NOT _x86 AND NOT _x86_64)
RUNTIME DESTINATION bin)
install(FILES ${CMAKE_SOURCE_DIR}/system/box86.conf DESTINATION /etc/binfmt.d/)
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.6 DESTINATION /usr/lib/i386-linux-gnu/)
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.5 DESTINATION /usr/lib/i386-linux-gnu/)
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libgcc_s.so.1 DESTINATION /usr/lib/i386-linux-gnu/)
endif()
@@ -432,7 +547,12 @@ add_test(test13 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref13.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
add_test(test14 ${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 )
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
foreach(file ${extension_tests})
get_filename_component(testname "${file}" NAME_WE)
add_test(NAME "${testname}" COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
+18 -8
View File
@@ -2,31 +2,35 @@ Compiling
----
#### for Pandora
`mkdir build; cd build; cmake .. -DPANDORA=1; make`
`mkdir build; cd build; cmake .. -DPANDORA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
#### for Pyra
`mkdir build; cd build; cmake .. -DPYRA=1; make`
`mkdir build; cd build; cmake .. -DPYRA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
#### for Gameshell
`mkdir build; cd build; cmake .. -DGAMESHELL=1; make`
`mkdir build; cd build; cmake .. -DGAMESHELL=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
#### for RaspberryPI
_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)_
`mkdir build; cd build; cmake .. -DRPI4=1; make`
`mkdir build; cd build; cmake .. -DRPI4=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
_For Pi4. Change to RPI2 or RPI3 for other models._
#### for ODROID
`mkdir build; cd build; cmake .. -DODROID=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
#### for Other ARM Linux
`mkdir build; cd build; cmake .. ; make`
`mkdir build; cd build; cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
#### for x86 Linux
`mkdir build; cd build; cmake .. -DLD80BITS=1 -DNOALIGN=1; make`
`mkdir build; cd build; cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
#### use ccmake
@@ -34,14 +38,20 @@ Alternatively, you can use the curses-bases ccmake (or any other gui frontend fo
#### Customize your build
*use ccache if you have it*
*use ccache if you have it*
Add `-DUSE_CCACHE=1` if you have ccache (it's better if you plan to touch the sources)
*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.
*to have a Trace Enabled build*
*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 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).
----
+35 -17
View File
@@ -1,21 +1,22 @@
# box86
![Official logo](Box86Logo.png "Official Logo")
Linux Userspace x86 Emulator with a twist
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=LU8Y2T62ZWFHU)
Box86 lets you run x86 Linux programs (such as games) on non-x86 Linux, like ARM (host system needs to be 32bit little-endian).
Box86 will let you run x86 Linux programs (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).
Because Box86 uses the native version for some "system" libraries, like libc, libm, or SDL and OpenGL, it's easy to integrate and use, and performances can be surprinsigly high in some cases.
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 probably needed.
Most x86 Games need OpenGL, so on ARM platforms a solution like [gl4es](https://github.com/ptitSeb/gl4es) is usually necessary.
Box86 now integrate a DynaRec for ARM platform, providing a speed boost between 5 to 10 times compared to only the interpretor.
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, like for example: WorldOfGoo, Airline Tycoon Deluxe or FTL. Many of the GameMaker linux games also run fine (there a long list, among them are UNDERTALE, A Risk of Rain, and Cook Server Delicious)
Many games already work, 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 it's support in the cmake project (use ccmake for example)
To have TRACE enabled (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) accessible on your system.
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
@@ -23,46 +24,63 @@ Here are 6 videos, the first 2 of "Airline Tycoon Deluxe" and "Heretic 2" runnin
[![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!
----
Compiling
----
How to compile can be found [here](COMPILE.md)
Compilation instructions can be found [here](COMPILE.md)
----
Usage
----
There are a few environment variables to control Box86 behaviour.
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 [here](CHANGELOG.md)
The change log is available [here](CHANGELOG.md)
----
A note about 64bits platform
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 32bits library. Box86 doesn't include any 32bits <-> 64bits translation. So basically, to run box86 on, for example, an ARM64 platform, you will need to build box86 for arm 32bits, and also need to have a chroot with 32bits library.
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 binary on 64bits platform. You will still need box86 (and see 32bits chroot) to run x86 binary (in fact, like it is the case on actual x86_64 linux)
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 not possible for now. Mono itself uses signals that are not well emulated enough. So the solution is to use a native version of the libmono used by Unity. It can be found here: https://github.com/Unity-Technologies/mono and it needs to be built from source. When built copy `libmonosgen-2.0.so` to `libmonounity.so` and put it somewhere it can be dlopen'd (so in `usr/lib` or friend or somewhere in your `LD_LIBRARY_PATH`).
Note that libmonounity is not completely wrapped yet, and the mechanism to call x86 library from libmonounity is not done yet, so the use of libmonounity is not enable for now.
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: mono games are not working for now anyway.
TL;DR: Not all Mono games work and can require a high OpenGL profile, but the speed, for the ones running, should be correct now.
----
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.
----
+22 -2
View File
@@ -27,6 +27,7 @@ Controls the folder scanned to look for x86 executable. Default is current folde
#### 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
@@ -58,6 +59,11 @@ 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
@@ -68,6 +74,16 @@ 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 :
@@ -77,7 +93,7 @@ Set level of DynaRec log
* 2 :
* DEBUG : Debug Log for Dynarec (with detail on block created / executed)
* 3 :
* DUMP : All above plus dump of the x86 -> native opcode conversions
* VERBOSE : All above plus more
#### BOX86_DYNAREC
* 0 : Disable Dynarec
@@ -103,10 +119,14 @@ Set level of DynaRec log
#### 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 LittleInforno for example is auto detected, and libvorbis.so.0 is automatical added to emulated libs
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_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.
+1984
View File
File diff suppressed because it is too large. Load diff
+113 -109
View File
@@ -1,19 +1,17 @@
#!/usr/bin/env python
import os
import glob
import sys
values = ['E', 'e', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'V', "O", "S"]
values = ['E', 'e', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'V', 'O', 'S']
def splitchar(s):
ret = [len(s)]
i = 0
for c in s:
i = i + 1
if i == 2:
continue
ret.append(values.index(c))
return ret
try:
ret = [len(s), values.index(s[0])]
for c in s[2:]:
ret.append(values.index(c))
return ret
except ValueError as e:
raise ValueError("Value is " + s) from e
def value(define):
return define[9:-1] if define.startswith("!") else define[8:-1]
@@ -36,16 +34,16 @@ def splitdef(dnf, defines):
def invert(define):
return define[1:] if define.startswith("!") else ("!" + define)
def main(root, defines, ver):
# Initialize variables: gbl for all values, vals for file-per-file values, redirects for redirections
def main(root, defines, files, ver):
global values
# Initialize variables: gbl for all values, redirects for redirections
gbl = {}
vals = {}
redirects = {}
# First read the files inside the headers
for filepath in glob.glob(os.path.join(root, "src/wrapped/", "wrapped*_private.h")):
for filepath in files:
filename = filepath.split("/")[-1]
locval = {}
dependants = []
with open(filepath, 'r') as file:
for line in file:
@@ -68,8 +66,8 @@ def main(root, defines, ver):
raise KeyError(preproc_cmd[5:].strip())
dependants.append("defined(" + preproc_cmd[5:].strip() + ")")
elif preproc_cmd.startswith("ifndef"):
if preproc_cmd[5:].strip() not in defines:
raise KeyError(preproc_cmd[5:].strip())
if preproc_cmd[6:].strip() not in defines:
raise KeyError(preproc_cmd[6:].strip())
dependants.append("!defined(" + preproc_cmd[6:].strip() + ")")
elif preproc_cmd.startswith("else"):
dependants[-1] = invert(dependants[-1])
@@ -91,29 +89,20 @@ def main(root, defines, ver):
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', 'o', '0', '1'] + values
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]))
# Ok, this is acceptable: there is 0, 1, stdout and void
# Ok, this is acceptable: there is 0, 1 and/or void
ln = (ln
.replace("v", "") # void -> nothing
.replace("o", "p") # stdout -> pointer
.replace("0", "p") # 0 -> pointer
.replace("1", "i")) # 1 -> integer
redirects.setdefault(" && ".join(dependants), {})
redirects[" && ".join(dependants)][old] = ln
# Simply append the function name if it's not yet existing
locval.setdefault(" && ".join(dependants), [])
gbl.setdefault(" && ".join(dependants), [])
if ln not in locval[" && ".join(dependants)]:
locval[" && ".join(dependants)].append(ln)
if ln not in gbl[" && ".join(dependants)]:
gbl[" && ".join(dependants)].append(ln)
# Sort the file local values and add it to the dictionary
for k in locval:
locval[k].sort(key=splitchar)
vals[filename] = locval
gbl_vals = {}
for k in gbl:
@@ -180,24 +169,44 @@ def main(root, defines, ver):
redirects_idxs = []
for k, v in redirects_vals:
key = "(" + (") || (".join(redirects_vals[(k, v)])) + ")"
val = redirects.get(key, {})
val[k] = v
redirects[key] = val
if key in redirects:
redirects[key].append([k, v])
else:
redirects[key] = [[k, v]]
if (key not in redirects_idxs) and (key != "()"):
redirects_idxs.append(key)
redirects_idxs.sort(key=lambda v: splitdef(v, defines))
# Sort the table
# Sort the tables
for k in gbl:
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]))
values = values[:-2]
def length(s):
l = len(s)
if l < 10:
ret = "0" + str(l)
else:
ret = str(l)
return ret
# Check if there was any new functions
functions_list = ""
for k in ["()"] + gbl_idxs:
for v in gbl[k]:
functions_list = functions_list + "#" + k + " " + v + "\n"
for k in ["()"] + redirects_idxs:
for v in redirects[k]:
functions_list = functions_list + "#" + k + " " + v[0] + " -> " + v[1] + "\n"
# functions_list is a unique string, compare it with the last run
try:
last_run = ""
with open(os.path.join(root, "src", "wrapped", "generated", "functions_list.txt"), 'r') as file:
last_run = file.read()
if last_run == functions_list:
# 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
except IOError:
# The file does not exist yet, first run
pass
# Now the files rebuilding part
# File headers and guards
@@ -243,11 +252,7 @@ static void* io_convert(void* v)
#else
#define ST0val ST0.d
#endif
#ifndef NOALIGN
int of_convert(int flag) { return (flag&~0740000) | ((flag&0140000)<<2) | ((flag&0600000)>>2);}
#else
int of_convert(int flag) { return flag; }
#endif
int of_convert(int);
""",
"wrapper.h": """/*****************************************************************
* File automatically generated by rebuild_wrappers.py (v%s)
@@ -284,57 +289,50 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
"""
}
# Transform strings into arrays
for k in gbl:
gbl[k] = [[c for c in v] for v in gbl[k]]
# Rewrite the wrapper.h file:
with open(os.path.join(root, "src/wrapped/generated/", "wrapper.h"), 'w') as 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 " + ''.join(v) + "(x86emu_t *emu, uintptr_t fnc);\n")
file.write("void " + v + "(x86emu_t *emu, uintptr_t fnc);\n")
for k in gbl_idxs:
if k != "()":
file.write("\n#if " + k + "\n")
for v in gbl[k]:
file.write("void " + ''.join(v) + "(x86emu_t *emu, uintptr_t fnc);\n")
file.write("#endif\n")
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 " + ''.join(v) + "(x86emu_t *emu, uintptr_t fnc);\n")
file.write("void " + v[0] + "(x86emu_t *emu, uintptr_t fnc);\n")
for k in redirects_idxs:
if k != "()":
file.write("\n#if " + k + "\n")
for v in redirects[k]:
file.write("void " + ''.join(v) + "(x86emu_t *emu, uintptr_t fnc);\n")
file.write("#endif\n")
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"])
# Rewrite the wrapper.c file:
with open(os.path.join(root, "src/wrapped/generated/", "wrapper.c"), 'w') as file:
with open(os.path.join(root, "src", "wrapped", "generated", "wrapper.c"), 'w') as file:
file.write(files_headers["wrapper.c"] % 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
# E e v c w i I C W u U f d D K l L p V O S
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*"]
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])] + " (*" + ''.join(v) + "_t)"
file.write("typedef " + types[values.index(v[0])] + " (*" + v + "_t)"
+ "(" + ', '.join(types[values.index(t)] for t in v[2:]) + ");\n")
for k in gbl_idxs:
if k != "()":
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
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*"]
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])] + " (*" + ''.join(v) + "_t)"
+ "(" + ', '.join(types[values.index(t)] for t in v[2:]) + ");\n")
file.write("#endif\n")
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
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*"]
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")
file.write("#endif\n")
file.write("\n")
# Next part: function definitions
@@ -352,27 +350,27 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
return "1, " + function_args(args[1:], d)
arg = [
"emu, ", # E
"&emu, ", # e
"", # v
"*(int8_t*)(R_ESP + {p}), ", # c
"*(int16_t*)(R_ESP + {p}), ", # w
"*(int32_t*)(R_ESP + {p}), ", # i
"*(int64_t*)(R_ESP + {p}), ", # I
"*(uint8_t*)(R_ESP + {p}), ", # C
"*(uint16_t*)(R_ESP + {p}), ", # W
"*(uint32_t*)(R_ESP + {p}), ", # u
"*(uint64_t*)(R_ESP + {p}), ", # U
"*(float*)(R_ESP + {p}), ", # f
"*(double*)(R_ESP + {p}), ", # d
"*(long double*)(R_ESP + {p}), ", # D
"FromLD((void*)(R_ESP + {p})), ", # K
"*(intptr_t*)(R_ESP + {p}), ", # l
"*(uintptr_t*)(R_ESP + {p}), ", # L
"*(void**)(R_ESP + {p}), ", # p
"(void*)(R_ESP + {p}), ", # V
"of_convert(*(int32_t*)(R_ESP + {p})), ", # O
"io_convert(*(void**)(R_ESP + {p})), ", # S
"emu, ", # E
"&emu, ", # e
"", # v
"*(int8_t*)(R_ESP + {p}), ", # c
"*(int16_t*)(R_ESP + {p}), ", # w
"*(int32_t*)(R_ESP + {p}), ", # i
"*(int64_t*)(R_ESP + {p}), ", # I
"*(uint8_t*)(R_ESP + {p}), ", # C
"*(uint16_t*)(R_ESP + {p}), ", # W
"*(uint32_t*)(R_ESP + {p}), ", # u
"*(uint64_t*)(R_ESP + {p}), ", # U
"*(float*)(R_ESP + {p}), ", # f
"*(double*)(R_ESP + {p}), ", # d
"*(long double*)(R_ESP + {p}), ", # D
"FromLD((void*)(R_ESP + {p})), ", # K
"*(intptr_t*)(R_ESP + {p}), ", # l
"*(uintptr_t*)(R_ESP + {p}), ", # L
"*(void**)(R_ESP + {p}), ", # p
"(void*)(R_ESP + {p}), ", # V
"of_convert(*(int32_t*)(R_ESP + {p})), ", # O
"io_convert(*(void**)(R_ESP + {p})), ", # S
]
# E e v c w i I C W u U f d D K l L p V O S
deltas = [0, 0, 4, 4, 4, 4, 8, 4, 4, 4, 8, 4, 8, 12, 12, 4, 4, 4, 0, 4, 4]
@@ -412,28 +410,34 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
f.write(vals[values.index(rettype)].format(function_args(args)[:-2]) + " }\n")
for v in gbl["()"]:
function_writer(file, ''.join(v), ''.join(v) + "_t", v[0], v[2:])
function_writer(file, v, v + "_t", v[0], v[2:])
for k in gbl_idxs:
if k != "()":
file.write("\n#if " + k + "\n")
for v in gbl[k]:
function_writer(file, ''.join(v), ''.join(v) + "_t", v[0], v[2:])
file.write("#endif\n")
file.write("\n#if " + k + "\n")
for v in gbl[k]:
function_writer(file, v, v + "_t", v[0], v[2:])
file.write("#endif\n")
file.write("\n")
for v in redirects["()"]:
function_writer(file, v, redirects["()"][v] + "_t", v[0], v[2:])
function_writer(file, v[0], v[1] + "_t", v[0][0], v[0][2:])
for k in redirects_idxs:
if k != "()":
file.write("\n#if " + k + "\n")
for v in redirects[k]:
function_writer(file, v, redirects[k][v] + "_t", v[0], v[2:])
file.write("#endif\n")
file.write("\n#if " + k + "\n")
for v in redirects[k]:
function_writer(file, v[0], v[1] + "_t", v[0][0], v[0][2:])
file.write("#endif\n")
file.write(files_guards["wrapper.c"])
# 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:
file.write(functions_list)
return 0
if __name__ == '__main__':
if main(sys.argv[1], sys.argv[2:], "1.1.1.06") != 0:
limit = []
for i, v in enumerate(sys.argv):
if v == "--":
limit.append(i)
if main(sys.argv[1], sys.argv[2:limit[0]], sys.argv[limit[0]+1:], "1.2.0.09") != 0:
exit(2)
exit(0)
+8 -1
View File
@@ -13,7 +13,14 @@ if( NOT TEST_REFERENCE )
endif( NOT TEST_REFERENCE )
set(ENV{BOX86_LOG} 0)
set(ENV{LD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/x86lib)
if( EXISTS ${CMAKE_SOURCE_DIR}/x86lib )
# we are inside box86 folder
set(ENV{LD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/x86lib)
else()
# we are inside build folder
set(ENV{LD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/../x86lib)
endif( EXISTS ${CMAKE_SOURCE_DIR}/x86lib )
# run the test program, capture the stdout/stderr and the result var
execute_process(
COMMAND ${TEST_PROGRAM} ${TEST_ARGS} ${TEST_ARGS2}
+328 -87
View File
@@ -16,49 +16,227 @@
#include "callback.h"
#include "wrapper.h"
#include "myfts.h"
#include "threads.h"
#include "x86trace.h"
#include "signals.h"
#ifdef DYNAREC
#include <sys/mman.h>
#include "dynablock.h"
#define MMAPSIZE (4*1024*1024) // allocate 4Mo sized blocks
#define MMAPBLOCK 256 // minimum size of a block
typedef struct mmaplist_s {
void* block;
uintptr_t offset; // offset in the block
uint8_t map[MMAPSIZE/(8*MMAPBLOCK)]; // map of allocated sub-block
} mmaplist_t;
#define MMAPSIZE (4*1024*1024) // allocate 4Mo sized blocks
uintptr_t AllocDynarecMap(box86context_t *context, int size)
// get first subblock free in map, stating at start. return -1 if no block, else first subblock free, filling size (in subblock unit)
static int getFirstBlock(mmaplist_t *map, int start, int maxsize, int* size)
{
// make size 0x10 bytes aligned
size = (size+0x0f)&~0x0f;
pthread_mutex_lock(&context->mutex_mmap);
// look for free space
for(int i=0; i<context->mmapsize; ++i) {
if(context->mmaplist[i].offset+size < MMAPSIZE) {
uintptr_t ret = context->mmaplist[i].offset + (uintptr_t)context->mmaplist[i].block;
context->mmaplist[i].offset+=size;
pthread_mutex_unlock(&context->mutex_mmap);
return ret;
#define ISFREE(A) (((map->map[(A)>>3]>>((A)&7))&1)?0:1)
if(start<0) start = 0;
while(start<MMAPSIZE/(8*MMAPBLOCK)) { // still a chance...
if(ISFREE(start)) {
// free, now get size...
int end = start+1;
while(end<MMAPSIZE/(8*MMAPBLOCK)) {
if(!ISFREE(end) || (end-start==maxsize)) {
if(size) *size = end-start;
return start;
}
++end;
}
if(size) *size = end-start;
return start;
}
++start;
}
return -1;
}
static void allocBlock(mmaplist_t *map, int start, int size)
{
for(int i=0; i<size; ++i) {
map->map[start/8]|=(1<<(start&7));
++start;
}
}
static void freeBlock(mmaplist_t *map, int start, int size)
{
for(int i=0; i<size; ++i) {
map->map[start/8]&=~(1<<(start&7));
++start;
}
}
uintptr_t AllocDynarecMap(int size, int nolinker)
{
if(size>MMAPSIZE) {
void* p = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if(p==MAP_FAILED) {
dynarec_log(LOG_DEBUG, "Cannot create dynamic map of %d bytes\n", size);
return 0;
}
return (uintptr_t)p;
}
pthread_mutex_lock(&my_context->mutex_mmap);
int bsize = (size+MMAPBLOCK-1)/MMAPBLOCK;
// look for free space
for(int i=0; i<my_context->mmapsize; ++i) {
int rsize = 0;
int start = 0;
do {
start = getFirstBlock(my_context->mmaplist+i, start, bsize, &rsize);
if(start!=-1 && rsize>=bsize) {
allocBlock(my_context->mmaplist+i, start, bsize);
uintptr_t ret = (uintptr_t)my_context->mmaplist[i].block + start*MMAPBLOCK;
pthread_mutex_unlock(&my_context->mutex_mmap);
return ret;
}
if(start!=-1)
start += rsize;
} while (start!=-1);
}
// no luck, add a new one !
int i = context->mmapsize++; // yeah, usefull post incrementation
dynarec_log(LOG_DEBUG, "Ask for DynaRec Block Alloc #%d\n", context->mmapsize);
context->mmaplist = (mmaplist_t*)realloc(context->mmaplist, context->mmapsize*sizeof(mmaplist_t));
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 = mmap(NULL, MMAPSIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if(p==MAP_FAILED) {
dynarec_log(LOG_INFO, "Cannot create memory map of %d byte for dynarec block #%d\n", MMAPSIZE, i);
--context->mmapsize;
pthread_mutex_unlock(&context->mutex_mmap);
dynarec_log(LOG_DEBUG, "Cannot create memory map of %d byte for dynarec block #%d\n", MMAPSIZE, i);
--my_context->mmapsize;
pthread_mutex_unlock(&my_context->mutex_mmap);
return 0;
}
context->mmaplist[i].block = p;
context->mmaplist[i].offset=size;
pthread_mutex_unlock(&context->mutex_mmap);
my_context->mmaplist[i].block = p;
memset(my_context->mmaplist[i].map, 0, sizeof(my_context->mmaplist[i].map));
allocBlock(my_context->mmaplist+i, 0, bsize);
pthread_mutex_unlock(&my_context->mutex_mmap);
return (uintptr_t)p;
}
void FreeDynarecMap(uintptr_t addr, uint32_t size)
{
if(size>MMAPSIZE) {
munmap((void*)addr, size);
return;
}
pthread_mutex_lock(&my_context->mutex_mmap);
int bsize = (size+MMAPBLOCK-1)/MMAPBLOCK;
// look for free space
for(int i=0; i<my_context->mmapsize; ++i) {
if(addr>=(uintptr_t)my_context->mmaplist[i].block && ((uintptr_t)my_context->mmaplist[i].block+MMAPSIZE)>=addr+size) {
int start = (addr - (uintptr_t)my_context->mmaplist[i].block) / MMAPBLOCK;
freeBlock(my_context->mmaplist+i, start, bsize);
pthread_mutex_unlock(&my_context->mutex_mmap);
return;
}
}
pthread_mutex_unlock(&my_context->mutex_mmap);
}
// each dynmap is 64k of size
dynablocklist_t* getDBFromAddress(uintptr_t addr)
{
int idx = (addr>>16);
if(!my_context->dynmap[idx]) {
return NULL;
}
return my_context->dynmap[idx]->dynablocks;
}
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>>16);
uintptr_t end = ((addr+size-1)>>16);
for (uintptr_t i=idx; i<=end; ++i) {
if(!my_context->dynmap[i]) {
my_context->dynmap[i] = (dynmap_t*)calloc(1, sizeof(dynmap_t));
my_context->dynmap[i]->dynablocks = NewDynablockList(i<<16, i<<16, 1<<16, 1, 0);
}
}
protectDB(addr, size);
}
void cleanDBFromAddressRange(uintptr_t addr, uintptr_t size, int destroy)
{
dynarec_log(LOG_DEBUG, "cleanDBFromAddressRange %p -> %p %s\n", (void*)addr, (void*)(addr+size-1), destroy?"destroy":"mark");
uintptr_t idx = (addr>box86_dynarec_largest && !destroy)?((addr-box86_dynarec_largest)>>16):(addr>>16);
uintptr_t end = ((addr+size-1)>>16);
for (uintptr_t i=idx; i<=end; ++i) {
dynmap_t* dynmap = my_context->dynmap[i];
if(dynmap) {
uintptr_t startdb = StartDynablockList(dynmap->dynablocks);
uintptr_t enddb = EndDynablockList(dynmap->dynablocks);
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) {
my_context->dynmap[i] = NULL;
FreeDynablockList(&dynmap->dynablocks);
free(dynmap);
} else
MarkDynablockList(&dynmap->dynablocks);
} else
if(destroy)
FreeRangeDynablock(dynmap->dynablocks, startaddr, endaddr-startaddr+1);
else
MarkRangeDynablock(dynmap->dynablocks, 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(start, end-start, 0);
}
#endif
EXPORTDYN
void initAllHelpers(box86context_t* context)
{
static int inited = 0;
if(inited)
return;
my_context = context;
init_pthread_helper();
init_signal_helper();
inited = 1;
}
EXPORTDYN
void finiAllHelpers()
{
static int finied = 0;
if(finied)
return;
fini_pthread_helper();
fini_signal_helper();
finied = 1;
}
void x86Syscall(x86emu_t *emu);
/// maxval not inclusive
@@ -82,14 +260,25 @@ void free_tlsdatasize(void* p)
free(p);
}
EXPORTDYN
box86context_t *NewBox86Context(int argc)
{
#ifdef BUILD_DYNAMIC
if(my_context) {
++my_context->count;
return my_context;
}
#endif
// init and put default values
box86context_t *context = (box86context_t*)calloc(1, sizeof(box86context_t));
#ifdef BUILD_LIB
context->deferedInit = 0;
#else
context->deferedInit = 1;
context->maplib = NewLibrarian(context);
#endif
context->maplib = NewLibrarian(context, 1);
context->local_maplib = NewLibrarian(context, 1);
context->system = NewBridge();
// create vsyscall
context->vsyscall = AddBridge(context->system, vFv, x86Syscall, 0);
@@ -109,13 +298,14 @@ box86context_t *NewBox86Context(int argc)
pthread_mutex_init(&context->mutex_once2, NULL);
pthread_mutex_init(&context->mutex_trace, NULL);
pthread_mutex_init(&context->mutex_lock, NULL);
pthread_mutex_init(&context->mutex_thread, NULL);
pthread_key_create(&context->tlskey, free_tlsdatasize);
#ifdef DYNAREC
pthread_mutex_init(&context->mutex_blocks, NULL);
pthread_mutex_init(&context->mutex_mmap, NULL);
context->dynablocks = NewDynablockList(0, 0, 0);
context->dynablocks = NewDynablockList(0, 0, 0, 0, 0);
#endif
InitFTSMap(context);
@@ -123,109 +313,135 @@ box86context_t *NewBox86Context(int argc)
context->canary[getrand(4)] = 0;
printf_log(LOG_DEBUG, "Setting up canary (for Stack protector) at GS:0x14, value:%08X\n", *(uint32_t*)context->canary);
initAllHelpers(context);
return context;
}
EXPORTDYN
void FreeBox86Context(box86context_t** context)
{
#ifdef BUILD_DYNAMIC
if(--(*context)->count)
return;
#endif
if(!context)
return;
if(--(*context)->forked >= 0)
return;
FreeFTSMap(*context);
box86context_t* ctx = *context; // local copy to do the cleanning
if((*context)->maplib)
FreeLibrarian(&(*context)->maplib);
for(int i=0; i<ctx->elfsize; ++i) {
FreeElfHeader(&ctx->elfs[i]);
}
free(ctx->elfs);
FreeFTSMap(ctx);
if(ctx->maplib)
FreeLibrarian(&ctx->maplib);
if(ctx->local_maplib)
FreeLibrarian(&ctx->local_maplib);
#ifdef DYNAREC
dynarec_log(LOG_INFO, "Free global Dynarecblocks\n");
if((*context)->dynablocks)
FreeDynablockList(&(*context)->dynablocks);
for (int i=0; i<(*context)->mmapsize; ++i)
if((*context)->mmaplist[i].block)
munmap((*context)->mmaplist[i].block, MMAPSIZE);
free((*context)->mmaplist);
pthread_mutex_destroy(&(*context)->mutex_blocks);
pthread_mutex_destroy(&(*context)->mutex_mmap);
dynarec_log(LOG_DEBUG, "Free global Dynarecblocks\n");
if(ctx->dynablocks)
FreeDynablockList(&ctx->dynablocks);
for (int i=0; i<ctx->mmapsize; ++i)
if(ctx->mmaplist[i].block)
munmap(ctx->mmaplist[i].block, MMAPSIZE);
free(ctx->mmaplist);
pthread_mutex_destroy(&ctx->mutex_blocks);
pthread_mutex_destroy(&ctx->mutex_mmap);
dynarec_log(LOG_DEBUG, "Free dynamic Dynarecblocks\n");
cleanDBFromAddressRange(0, 0xffffffff, 1);
#endif
if((*context)->emu)
FreeX86Emu(&(*context)->emu);
*context = NULL; // bye bye my_context
FreeCollection(&(*context)->box86_path);
FreeCollection(&(*context)->box86_ld_lib);
FreeCollection(&(*context)->box86_emulated_libs);
if((*context)->zydis)
DeleteX86Trace(*context);
CleanStackSize(ctx);
if((*context)->deferedInitList)
free((*context)->deferedInitList);
FreeCollection(&ctx->box86_path);
FreeCollection(&ctx->box86_ld_lib);
FreeCollection(&ctx->box86_emulated_libs);
// stop trace now
if(ctx->dec)
DeleteX86TraceDecoder(&ctx->dec);
if(ctx->zydis)
DeleteX86Trace(ctx);
if(ctx->deferedInitList)
free(ctx->deferedInitList);
#ifndef BUILD_LIB
if((*context)->box86lib)
dlclose((*context)->box86lib);
if(ctx->box86lib)
dlclose(ctx->box86lib);
#endif
FreeDLPrivate(&(*context)->dlprivate);
FreeDLPrivate(&ctx->dlprivate);
for(int i=0; i<(*context)->argc; ++i)
free((*context)->argv[i]);
free((*context)->argv);
free(ctx->argv);
for (int i=0; i<(*context)->envc; ++i)
free((*context)->envv[i]);
free((*context)->envv);
for (int i=0; i<ctx->envc; ++i)
free(ctx->envv[i]);
free(ctx->envv);
for(int i=0; i<(*context)->elfsize; ++i) {
FreeElfHeader(&(*context)->elfs[i]);
}
free((*context)->elfs);
free(ctx->stack);
free((*context)->stack);
free(ctx->fullpath);
free(ctx->box86path);
free((*context)->fullpath);
free((*context)->box86path);
FreeBridge(&ctx->system);
FreeBridge(&(*context)->system);
freeGLProcWrapper(ctx);
freeALProcWrapper(ctx);
if((*context)->glwrappers)
freeProcWrapper(&(*context)->glwrappers);
if((*context)->alwrappers)
freeProcWrapper(&(*context)->alwrappers);
FreeCallbackList(&(*context)->callbacks);
FreeCallbackList(&ctx->callbacks);
void* ptr;
if ((ptr = pthread_getspecific((*context)->tlskey)) != NULL) {
if ((ptr = pthread_getspecific(ctx->tlskey)) != NULL) {
free_tlsdatasize(ptr);
pthread_setspecific((*context)->tlskey, NULL);
pthread_setspecific(ctx->tlskey, NULL);
}
pthread_key_delete((*context)->tlskey);
pthread_key_delete(ctx->tlskey);
if((*context)->tlsdata)
free((*context)->tlsdata);
if(ctx->tlsdata)
free(ctx->tlsdata);
pthread_mutex_destroy(&(*context)->mutex_once);
pthread_mutex_destroy(&(*context)->mutex_once2);
pthread_mutex_destroy(&(*context)->mutex_trace);
pthread_mutex_destroy(&(*context)->mutex_lock);
for(int i=0; i<3; ++i) {
if(ctx->segtls[i].present) {
// key content not handled by box86, so not doing anything with it
pthread_key_delete(ctx->segtls[i].key);
}
}
if((*context)->atfork_sz) {
free((*context)->atforks);
(*context)->atforks = NULL;
(*context)->atfork_sz = (*context)->atfork_cap = 0;
pthread_mutex_destroy(&ctx->mutex_once);
pthread_mutex_destroy(&ctx->mutex_once2);
pthread_mutex_destroy(&ctx->mutex_trace);
pthread_mutex_destroy(&ctx->mutex_lock);
pthread_mutex_destroy(&ctx->mutex_thread);
free_neededlib(&ctx->neededlibs);
if(ctx->atfork_sz) {
free(ctx->atforks);
ctx->atforks = NULL;
ctx->atfork_sz = ctx->atfork_cap = 0;
}
for(int i=0; i<MAX_SIGNAL; ++i)
if((*context)->signals[i]!=0 && (*context)->signals[i]!=1) {
if(ctx->signals[i]!=0 && ctx->signals[i]!=1) {
signal(i, SIG_DFL);
}
if(ctx->emu_sig)
FreeX86Emu(&ctx->emu_sig);
free(*context);
*context = NULL;
finiAllHelpers();
free(ctx);
}
int AddElfHeader(box86context_t* ctx, elfheader_t* head) {
@@ -242,7 +458,32 @@ int AddElfHeader(box86context_t* ctx, elfheader_t* head) {
}
int AddTLSPartition(box86context_t* context, int tlssize) {
int oldsize = context->tlssize;
context->tlssize += tlssize;
context->tlsdata = realloc(context->tlsdata, context->tlssize);
memmove(context->tlsdata+tlssize, context->tlsdata, oldsize); // move to the top, using memmove as regions will probably overlap
memset(context->tlsdata, 0, tlssize); // fill new space with 0 (not mandatory)
return -context->tlssize; // negative offset
}
}
void add_neededlib(needed_libs_t* needed, library_t* lib)
{
if(!needed)
return;
if(needed->size == needed->cap) {
needed->cap += 8;
needed->libs = (library_t**)realloc(needed->libs, needed->cap*sizeof(library_t*));
}
needed->libs[needed->size++] = lib;
}
void free_neededlib(needed_libs_t* needed)
{
if(!needed)
return;
needed->cap = 0;
needed->size = 0;
if(needed->libs)
free(needed->libs);
needed->libs = NULL;
}
+1 -1
View File
@@ -3,6 +3,6 @@
#define BOX86_MAJOR 0
#define BOX86_MINOR 1
#define BOX86_REVISION 0
#define BOX86_REVISION 2
#endif //__BOX86_VERSION_H_
+28
View File
@@ -0,0 +1,28 @@
#include <stdio.h>
#include "debug.h"
#include "box86version.h"
#include "git_head.h"
void PrintBox86Version()
{
printf("Box86%s%s%s v%d.%d.%d %s built on %s %s\n",
#ifdef HAVE_TRACE
" with trace",
#else
"",
#endif
#ifdef DYNAREC
" with Dynarec",
#else
"",
#endif
#ifdef USE_FLOAT
" (float only)",
#else
"",
#endif
BOX86_MAJOR, BOX86_MINOR, BOX86_REVISION,
GITREV,
__DATE__, __TIME__);
}
+6
View File
@@ -0,0 +1,6 @@
#ifndef __BUILD_INFO_H__
#define __BUILD_INFO_H__
void PrintBox86Version();
#endif //__BUILD_INFO_H__
+275 -65
View File
@@ -33,16 +33,16 @@ Op is 20-27
#define xSP 13
// barel roll operations (4 possibles)
#define brLSL(i, r) (0<<4 | 0<<5 | ((i&31)<<7) | r)
#define brLSR(i, r) (0<<4 | 1<<5 | ((i&31)<<7) | r)
#define brASR(i, r) (0<<4 | 2<<5 | ((i&31)<<7) | r)
#define brROR(i, r) (0<<4 | 3<<5 | ((i&31)<<7) | r)
#define brLSL(i, r) (0<<4 | 0<<5 | (((i)&31)<<7) | (r))
#define brLSR(i, r) (0<<4 | 1<<5 | (((i)&31)<<7) | (r))
#define brASR(i, r) (0<<4 | 2<<5 | (((i)&31)<<7) | (r))
#define brROR(i, r) (0<<4 | 3<<5 | (((i)&31)<<7) | (r))
#define brIMM(r) (abs(r))
// barel roll with a register
#define brRLSL(i, r) (1<<4 | 0<<5 | ((i&15)<<8) | r)
#define brRLSR(i, r) (1<<4 | 1<<5 | ((i&15)<<8) | r)
#define brRASR(i, r) (1<<4 | 2<<5 | ((i&15)<<8) | r)
#define brRROR(i, r) (1<<4 | 3<<5 | ((i&15)<<8) | r)
#define brRLSL(i, r) (1<<4 | 0<<5 | (((i)&15)<<8) | (r))
#define brRLSR(i, r) (1<<4 | 1<<5 | (((i)&15)<<8) | (r))
#define brRASR(i, r) (1<<4 | 2<<5 | (((i)&15)<<8) | (r))
#define brRROR(i, r) (1<<4 | 3<<5 | (((i)&15)<<8) | (r))
// conditions
@@ -79,12 +79,12 @@ Op is 20-27
// 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) { \
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); \
MOVT(dst, (((uint32_t)imm32)>>16))
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) )
// mov dst #imm8 ror imm4*2
@@ -93,22 +93,30 @@ Op is 20-27
#define MOV_IMM_COND(cond, dst, imm8, rimm4) EMIT(cond | 0x03a00000 | ((dst) << 12) | (imm8) | ((rimm4) << 8) )
// mov dst, src lsl imm5
#define MOV_REG_LSL_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (0<<5) | (imm5<<7))
#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))
#define MOV_REG_LSR_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((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))
#define MOV_REG_ASR_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (2<<5) | ((imm5)<<7))
// mov dst, src ror imm5
#define MOV_REG_ROR_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (3<<5) | (imm5<<7))
#define MOV_REG_ROR_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (3<<5) | ((imm5)<<7))
// mov.s dst, src lsl imm5
#define MOVS_REG_LSL_IMM5(dst, src, imm5) EMIT(0xe1b00000 | ((dst) << 12) | (src) | (0<<4) | (0<<5) | ((imm5)<<7))
// mov.s dst, src lsr imm5
#define MOVS_REG_LSR_IMM5(dst, src, imm5) EMIT(0xe1b00000 | ((dst) << 12) | (src) | (0<<4) | (1<<5) | ((imm5)<<7))
// mov.s dst, src asr imm5
#define MOVS_REG_ASR_IMM5(dst, src, imm5) EMIT(0xe1b00000 | ((dst) << 12) | (src) | (0<<4) | (2<<5) | ((imm5)<<7))
// 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 dst, src lsl rs
#define MOV_REG_LSL_REG(dst, src, rs) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (1<<4) | (0<<5) | (rs<<8))
#define MOV_REG_LSL_REG(dst, src, rs) EMIT(0xe1a00000 | ((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))
#define MOV_REG_LSR_REG(dst, src, rs) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (1<<4) | (1<<5) | ((rs)<<8))
// mov dst, src asr rs
#define MOV_REG_ASR_REG(dst, src, rs) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (1<<4) | (2<<5) | (rs<<8))
#define MOV_REG_ASR_REG(dst, src, rs) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (1<<4) | (2<<5) | ((rs)<<8))
// mov dst, src ror rs
#define MOV_REG_ROR_REG(dst, src, rs) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (1<<4) | (3<<5) | (rs<<8))
#define MOV_REG_ROR_REG(dst, src, rs) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (1<<4) | (3<<5) | ((rs)<<8))
// sub dst, src, #(imm8)
#define SUB_IMM8(dst, src, imm8) \
@@ -119,20 +127,32 @@ Op is 20-27
// sub.s dst, src, #(imm8)
#define SUBS_IMM8(dst, src, imm8) \
EMIT(0xe2500000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
// add dst, src1, src2, lsl #imm
#define SUB_REG_LSL_IMM8(dst, src1, src2, imm8) \
EMIT(0xe0400000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm8, src2) )
// add.s dst, src1, src2, lsl #imm
#define SUBS_REG_LSL_IMM8(dst, src1, src2, imm8) \
EMIT(0xe0500000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm8, src2) )
// sub dst, src1, src2, lsl #imm
#define SUB_REG_LSL_IMM5(dst, src1, src2, imm5) \
EMIT(0xe0400000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
// sub.s dst, src1, src2, lsl #imm
#define SUBS_REG_LSL_IMM5(dst, src1, src2, imm5) \
EMIT(0xe0500000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
// sbc dst, src, #(imm8)
#define SBC_IMM8(dst, src, imm8) \
EMIT(0xe2c00000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
// sbc.s dst, src, #(imm8)
#define SBCS_IMM8(dst, src, imm8) \
EMIT(0xe2d00000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
// sbc dst, src1, src2, lsl #imm
#define SBC_REG_LSL_IMM5(dst, src1, src2, imm5) \
EMIT(0xe0c00000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
// sbc.s dst, src1, src2, lsl #imm
#define SBCS_REG_LSL_IMM5(dst, src1, src2, imm5) \
EMIT(0xe0d00000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
// rsb dst, src, #(imm8)
#define RSB_IMM8(dst, src, imm8) \
EMIT(0xe2600000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
// rsb.s dst, src, #(imm8)
#define RSBS_IMM8(dst, src, imm8) \
EMIT(0xe2700000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
// rsb cond dst, src, #(imm8)
#define RSB_COND_IMM8(cond, dst, src, imm8) \
EMIT((cond) | 0x02600000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
@@ -152,21 +172,38 @@ Op is 20-27
// and.s dst, src, #(imm8)
#define ANDS_IMM8(dst, src, imm8) \
EMIT(0xe2100000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
// and.s dst, src1, #imm ror rot*2
#define ANDS_IMM8_ROR(src, imm8, rot) \
EMIT(0xe2100000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
// add dst, src, #(imm8)
#define ADD_IMM8(dst, src, imm8) \
EMIT(0xe2800000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
// add.s dst, src, #(imm8)
#define ADDS_IMM8(dst, src, imm8) \
EMIT(0xe2900000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
// add.c dst, src, #(imm8)
#define ADD_IMM8_cond(cond, dst, src, imm8) \
EMIT((cond) | 0x02800000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
// add dst, src1, src2, lsl #imm
#define ADD_REG_LSL_IMM5(dst, src1, src2, imm5) \
EMIT(0xe0800000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
// add.s dst, src1, src2, lsl #imm
#define ADDS_REG_LSL_IMM5(dst, src1, src2, imm8) \
#define ADDS_REG_LSL_IMM5(dst, src1, src2, imm5) \
EMIT(0xe0900000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
// add dst, src1, src2, lsr #imm
#define ADD_REG_LSR_IMM5(dst, src1, src2, imm5) \
EMIT(0xe0800000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
#define ADC_IMM8(dst, src, imm8) \
EMIT(0xe2a00000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
// add.s dst, src, #(imm8)
#define ADCS_IMM8(dst, src, imm8) \
EMIT(0xe2b00000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
// add dst, src1, src2, lsl #imm
#define ADC_REG_LSL_IMM5(dst, src1, src2, imm5) \
EMIT(0xe0a00000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
// add.s dst, src1, src2, lsl #imm
#define ADCS_REG_LSL_IMM5(dst, src1, src2, imm5) \
EMIT(0xe0b00000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
// cmp.s dst, src1, src2, lsl #imm
#define CMPS_REG_LSL_IMM5(src1, src2, imm5) \
EMIT(0xe1500000 | ((0) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
@@ -174,8 +211,8 @@ Op is 20-27
#define CMPS_IMM8(src, imm8) \
EMIT(0xe3500000 | ((0) << 12) | ((src) << 16) | brIMM(imm8) )
// tst.s dst, src1, src2, lsl #imm
#define TSTS_REG_LSL_IMM8(src1, src2, imm8) \
EMIT(0xe1100000 | ((0) << 12) | ((src1) << 16) | brLSL(imm8, src2) )
#define TSTS_REG_LSL_IMM5(src1, src2, imm5) \
EMIT(0xe1100000 | ((0) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
// tst.s dst, src1, #imm
#define TSTS_IMM8(src, imm8) \
EMIT(0xe3100000 | ((0) << 12) | ((src) << 16) | brIMM(imm8) )
@@ -183,26 +220,33 @@ Op is 20-27
#define TSTS_IMM8_ROR(src, imm8, rot) \
EMIT(0xe3100000 | ((0) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
// orr dst, src1, src2, lsl #imm
#define ORR_REG_LSL_IMM8(dst, src1, src2, imm8) \
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm8, src2) )
#define ORR_REG_LSL_IMM5(dst, src1, src2, imm5) \
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
// orr.s dst, src1, src2, lsl #imm
#define ORRS_REG_LSL_IMM8(dst, src1, src2, imm8) \
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm8, src2) )
#define ORRS_REG_LSL_IMM5(dst, src1, src2, imm5) \
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brLSL(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
#define ORR_REG_LSL_REG(dst, src1, src2, rs) \
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brRLSL(rs, src2) )
// xor dst, src1, src2, lsl #imm
#define XOR_REG_LSL_IMM8(dst, src1, src2, imm8) \
EMIT(0xe0200000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm8, src2) )
#define XOR_REG_LSL_IMM5(dst, src1, src2, imm5) \
EMIT(0xe0200000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
// xor.s dst, src1, src2, lsl #imm
#define XORS_REG_LSL_IMM8(dst, src1, src2, imm8) \
EMIT(0xe0300000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm8, src2) )
#define XORS_REG_LSL_IMM5(dst, src1, src2, imm5) \
EMIT(0xe0300000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
#define XOR_REG_LSL_IMM5_COND(cond, dst, src1, src2, imm5) \
EMIT((cond) | 0x00200000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
// xor dst, src, #(imm8)
#define XOR_IMM8(dst, src, imm8) \
EMIT(0xe2200000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
#define XORS_IMM8(dst, src, imm8) \
EMIT(0xe2300000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
// xor.cond dst, src, #(imm8)
#define XOR_IMM8_COND(cond, dst, src, imm8) \
EMIT(cond | 0x02200000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
@@ -213,17 +257,20 @@ Op is 20-27
#define XOR_REG_LSR_IMM8(dst, src1, src2, imm8) \
EMIT(0xe0200000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm8, src2) )
// bic dst, src1, src2, lsl #imm
#define BIC_REG_LSL_IMM8(dst, src1, src2, imm8) \
EMIT(0xe1c00000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm8, src2) )
#define BIC_REG_LSL_IMM5(dst, src1, src2, imm5) \
EMIT(0xe1c00000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
// bic dst, src, IMM8
#define BIC_IMM8(dst, src, imm8, rot) \
EMIT(0xe3c00000 | ((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) )
// bic dst, src1, src2, lsl #imm
#define BIC_REG_LSL_REG(dst, src1, src2, rs) \
EMIT(0xe1c00000 | ((dst) << 12) | ((src1) << 16) | brRLSL(rs, src2) )
// mvn dst, src1, src2, lsl #imm
#define MVN_REG_LSL_IMM8(dst, rm, imm8) \
EMIT(0xe1e00000 | ((dst) << 12) | (0 << 16) | brLSL(imm8, rm) )
#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 )
@@ -234,8 +281,8 @@ Op is 20-27
#define MVN_REG_LSR_REG(dst, rm, rs) \
EMIT(0xe1e00000 | ((dst) << 12) | (0 << 16) | (1<<4) | (1<<5) | (rs<<8) | (rm) )
// mvn with condition dst, src1, src2, lsl #imm
#define MVN_COND_REG_LSL_IMM8(cond, dst, rm, imm8) \
EMIT(cond | 0x01e00000 | ((dst) << 12) | (0 << 16) | brLSL(imm8, rm) )
#define MVN_COND_REG_LSL_IMM5(cond, dst, rm, imm5) \
EMIT(cond | 0x01e00000 | ((dst) << 12) | (0 << 16) | brLSL(imm5, rm) )
// Single data transfert construction
#define SDT_REG(Cond, P, U, B, W, L, Rn, Rd, ShiftRm) (Cond | (0b00<<26) | (1<<25) | (P<<24) | (U<<23) | (B<<22) | (U<<23) | (W<<21) | (L<<20) | (Rn<<16) | (Rd<<12) | ShiftRm)
@@ -264,6 +311,8 @@ Op is 20-27
#define LDRBAI_REG_LSL_IMM5(reg, addr, rm, imm5) EMIT(0xe6d00000 | ((reg) << 12) | ((addr) << 16) | (1<<25) | brLSL(imm5, rm) )
// ldrd reg, reg+1, [addr, #+/-imm9], reg must be even, reg+1 is implicit
#define LDRD_IMM8(reg, addr, imm8) EMIT(c__ | 0b000<<25 | 1<<24 | (((imm8)<0)?0:1)<<23 | 1<<22 | 0<<21 | 0<<20 | ((reg) << 12) | ((addr) << 16) | ((abs(imm8))&0xf0)<<(8-4) | (0b1101<<4) | ((abs(imm8))&0x0f) )
// ldrd reg, reg+1, [addr, +rm], reg must be even, reg+1 is implicit
#define LDRD_REG(reg, addr, rm) EMIT(c__ | 0b000<<25 | 1<<24 | 1<<23 | 0<<22 | 0<<21 | 0<<20 | ((reg) << 12) | ((addr) << 16) | 0b1101<<4 | (rm) )
// str reg, [addr, #+/-imm9]
#define STR_IMM9(reg, addr, imm9) EMIT(0xe5000000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
@@ -283,6 +332,8 @@ Op is 20-27
#define STRBAI_REG_LSL_IMM5(reg, addr, rm, imm5) EMIT(0xe6c00000 | ((reg) << 12) | ((addr) << 16) | (1<<25) | brLSL(imm5, rm) )
// strd reg, reg+1, [addr, #+/-imm8], reg must be even, reg+1 is implicit
#define STRD_IMM8(reg, addr, imm8) EMIT(c__ | 0b000<<25 | 1<<24 | (((imm8)<0)?0:1)<<23 | 1<<22 | 0<<21 | 0<<20 | ((reg) << 12) | ((addr) << 16) | ((abs(imm8))&0xf0)<<(8-4) | (0b1111<<4) | ((abs(imm8))&0x0f) )
// strd reg, reg+1, [addr, +rm], reg must be even, reg+1 is implicit
#define STRD_REG(reg, addr, rm) EMIT(c__ | 0b000<<25 | 1<<24 | 1<<23 | 0<<22 | 0<<21 | 0<<20 | ((reg) << 12) | ((addr) << 16) | 0b1111<<4 | (rm) )
// bx reg
#define BX(reg) EMIT(0xe12fff10 | (reg) )
@@ -293,33 +344,33 @@ Op is 20-27
#define BLX(reg) EMIT(0xe12fff30 | (reg) )
// b cond offset
#define Bcond(C, O) EMIT(C | (0b101<<25) | (0<<24) | ((O)>>2)&0xffffff)
#define Bcond(C, O) EMIT(C | (0b101<<25) | (0<<24) | (((O)>>2)&0xffffff))
// bl cond offset
#define BLcond(C, O) EMIT(C | (0b101<<25) | (1<<24) | ((O)>>2)&0xffffff)
#define BLcond(C, O) EMIT(C | (0b101<<25) | (1<<24) | (((O)>>2)&0xffffff))
// push reg!, {list}
// 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))
#define PUSH(reg, list) EMIT(c__ | (0b100<<25) | (1<<24) | (0<<23) | (0<<22) | (1<<21) | (0<<20) | ((reg)<<16) | (list))
// 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))
#define POP(reg, list) EMIT(c__ | (0b100<<25) | (0<<24) | (1<<23) | (0<<22) | (1<<21) | (1<<20) | ((reg)<<16) | (list))
// 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))
#define STMDB(reg, list) EMIT(c__ | (0b100<<25) | (1<<24) | (0<<23) | (0<<22) | (0<<21) | (0<<20) | ((reg)<<16) | (list))
// STMia reg, {list}
// all | const |postindex| add | no PSR | no wb | store | base |reg list
#define STM(reg, list) EMIT(c__ | (0b100<<25) | (0<<24) | (1<<23) | (0<<22) | (0<<21) | (0<<20) | (reg<<16) | (list))
#define STM(reg, list) EMIT(c__ | (0b100<<25) | (0<<24) | (1<<23) | (0<<22) | (0<<21) | (0<<20) | ((reg)<<16) | (list))
// LDMia reg, {list}
// all | const |postindex| add | no PSR | no wb | load | base |reg list
#define LDM(reg, list) EMIT(c__ | (0b100<<25) | (0<<24) | (1<<23) | (0<<22) | (0<<21) | (1<<20) | (reg<<16) | (list))
#define LDM(reg, list) EMIT(c__ | (0b100<<25) | (0<<24) | (1<<23) | (0<<22) | (0<<21) | (1<<20) | ((reg)<<16) | (list))
// Half Word and signed data transfert construction
#define HWS_REG(Cond, P, U, W, L, Rn, Rd, S, H, Rm) (Cond | (0b000<<25) | (P<<24) | (U<<23) | (0<<22) | (W<<21) | (L<<20) | (Rn<<16) | (Rd<<12) | (1<<7) | (S<<6) | (H<<5) | (1<<4) | Rm)
#define HWS_OFF(Cond, P, U, W, L, Rn, Rd, S, H, Imm8) (Cond | (0b000<<25) | (P<<24) | (U<<23) | (1<<22) | (W<<21) | (L<<20) | (Rn<<16) | (Rd<<12) | ((Imm8&0xf0)<<(8-4)) | (1<<7) | (S<<6) | (H<<5) | (1<<4) | (Imm8&0x0f))
#define HWS_REG(Cond, P, U, W, L, Rn, Rd, S, H, Rm) (Cond | 0b000<<25 | (P)<<24 | (U)<<23 | 0<<22 | (W)<<21 | (L)<<20 | (Rn)<<16 | (Rd)<<12 | 1<<7 | (S)<<6 | (H)<<5 | 1<<4 | (Rm))
#define HWS_OFF(Cond, P, U, W, L, Rn, Rd, S, H, Imm8) (Cond | 0b000<<25 | (P)<<24 | (U)<<23 | 1<<22 | (W)<<21 | (L)<<20 | (Rn)<<16 | (Rd)<<12 | ((Imm8)&0xf0)<<(8-4) | 1<<7 | (S)<<6 | (H)<<5 | 1<<4 | ((Imm8)&0x0f))
#define LDRSB_IMM8(reg, addr, imm8) EMIT(HWS_OFF(c__, 1, (((imm8)<0)?0:1), 0, 1, addr, reg, 1, 0, abs(imm8)))
#define LDRSH_IMM8(reg, addr, imm8) EMIT(HWS_OFF(c__, 1, (((imm8)<0)?0:1), 0, 1, addr, reg, 1, 1, abs(imm8)))
@@ -328,17 +379,20 @@ Op is 20-27
#define STRH_IMM8(reg, addr, imm8) EMIT(HWS_OFF(c__, 1, (((imm8)<0)?0:1), 0, 0, addr, reg, 0, 1, abs(imm8)))
#define STRSH_IMM8(reg, addr, imm8) EMIT(HWS_OFF(c__, 1, (((imm8)<0)?0:1), 0, 0, addr, reg, 1, 1, abs(imm8)))
#define LDRH_REG(reg, addr, rm) EMIT(HWS_REG(c__, 1, 1, 0, 1, addr, reg, 0, 1, rm))
#define STRH_REG(reg, addr, rm) EMIT(HWS_REG(c__, 1, 1, 0, 0, addr, reg, 0, 1, rm))
#define LDRHAI_REG_LSL_IMM5(reg, addr, rm) EMIT(HWS_REG(c__, 0, 1, 0, 1, addr, reg, 0, 1, rm))
#define STRHAI_REG_LSL_IMM5(reg, addr, rm) EMIT(HWS_REG(c__, 0, 1, 0, 0, addr, reg, 0, 1, rm))
// Mul Long construction
#define MULLONG(Cond, U, A, S, RdHi, RdLo, Rs, Rm) (Cond | (0b00001<<23) | (U<<22) | (A<<21) | (S<<20) | (RdHi<<16) | (RdLo<<12) | (Rs<<8) | (0b1001<<4) | (Rm))
#define MULLONG(Cond, U, A, S, RdHi, RdLo, Rs, Rm) (Cond | 0b00001<<23 | (U)<<22 | (A)<<21 | (S)<<20 | (RdHi)<<16 | (RdLo)<<12 | (Rs)<<8 | 0b1001<<4 | (Rm))
#define UMULL(RdHi, RdLo, Rs, Rm) EMIT(MULLONG(c__, 0, 0, 0, RdHi, RdLo, Rs, Rm))
#define SMULL(RdHi, RdLo, Rs, Rm) EMIT(MULLONG(c__, 1, 0, 0, RdHi, RdLo, Rs, Rm))
// Mul and MulA
#define MULMULA(Cond, A, S, Rd, Rn, Rs, Rm) (Cond | (0b000000<<22) | (A<<21) | (S<<20) | (Rd<<16) | (Rn<<12) | (Rs<<8) | (0b1001<<4) | (Rm))
#define MULMULA(Cond, A, S, Rd, Rn, Rs, Rm) (Cond | 0b000000<<22 | (A)<<21 | (S)<<20 | (Rd)<<16 | (Rn)<<12 | (Rs)<<8 | 0b1001<<4 | (Rm))
#define MUL(Rd, Rm, Rn) EMIT(MULMULA(c__, 0, 0, (Rd), 0, (Rm), (Rn)))
#define SMUL_16_gen(cond, Rd, Rm, M, N, Rn) (cond | 0b00010110<<20 | (Rd)<<16 | (Rm)<<8 | 1<<7 | (M)<<6 | (N)<<5 | (Rn))
@@ -401,6 +455,20 @@ Op is 20-27
// Preload Cache Rn-Rm
#define PLDn(Rn, Rm) EMIT(PLD_gen(0, 1, Rn, 0, 0, Rm))
#define SWP_gen(cond, B, Rn, Rt, Rt2) (cond | 0b0001<<24 | (B)<<22 | (Rn)<<16 | (Rt)<<12 | 0b1001<<4 | (Rt2))
// SWAP (atomic) [Rn]->Rt2 / Rt->[Rn], Rt can be same as Rt2
#define SWP(Rt, Rt2, Rn) EMIT(SWP_gen(c__, 0, Rn, Rt, Rt2))
// SWAP Byte (atomic) [Rn]->Rt2 / Rt->[Rn], Rt can be same as Rt2, Byte is zero extended
#define SWPB(Rt, Rt2, Rn) EMIT(SWP_gen(c__, 1, Rn, Rt, Rt2))
#define SDIV_gen(cond, Rd, Rm, Rn) (cond | 0b0111<<24 | 0b0001<<20 | (Rd)<<16 | 0b1111<<12 | (Rm)<<8 | 0b0001<<4 | (Rn))
// Signed Div Rd <- Rn/Rm
#define SDIV(Rd, Rm, Rn) EMIT(SDIV_gen(c__, Rd, Rm, Rn))
#define UDIV_gen(cond, Rd, Rm, Rn) (cond | 0b0111<<24 | 0b0011<<20 | (Rd)<<16 | 0b1111<<12 | (Rm)<<8 | 0b0001<<4 | (Rn))
// Unsigned Div Rd <- Rn/Rm
#define UDIV(Rd, Rm, Rn) EMIT(UDIV_gen(c__, Rd, Rm, Rn))
// VFPU
#define TRANSFERT64(C, op) ((0b1100<<24) | (0b010<<21) | (0b101<<9) | ((C)<<8) | ((op)<<4))
@@ -490,16 +558,16 @@ Op is 20-27
#define VCVT_S16_F64(Dd) EMIT(VCVT_16_gen(c__, ((Dd)>>4)&1, 1, 0, (Dd)&15, 1, 0, 16&1, (16>>1)&15))
// Mutiply F64 Dd = Dn*Dm
#define VMUL_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (0<<23) | ((((Dd)>>4)&1)<<22) | (0b10<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (((Dn>>4)&1)<<7) | (((Dm>>4)&1)<<5) | ((Dm)&15) )
#define VMUL_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (0<<23) | ((((Dd)>>4)&1)<<22) | (0b10<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | ((((Dn)>>4)&1)<<7) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
// Divide F64 Dd = Dn/Dm
#define VDIV_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b00<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (((Dn>>4)&1)<<7) | (((Dm>>4)&1)<<5) | ((Dm)&15) )
#define VDIV_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b00<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | ((((Dn)>>4)&1)<<7) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
// Add F64 Dd = Dn + Dm
#define VADD_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (0<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (((Dn>>4)&1)<<7) | (0<<6) | (((Dm>>4)&1)<<5) | ((Dm)&15) )
#define VADD_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (0<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | ((((Dn)>>4)&1)<<7) | (0<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
// Sub F64 Dd = Dn + Dm
#define VSUB_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (0<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (((Dn>>4)&1)<<7) | (1<<6) | (((Dm>>4)&1)<<5) | ((Dm)&15) )
#define VSUB_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (0<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | ((((Dn)>>4)&1)<<7) | (1<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
// Mutiply F32 Sd = Sn*Sm
#define VMUL_F32(Sd, Sn, Sm) EMIT(c__ | (0b1110<<24) | (0<<23) | (((Sd)&1)<<22) | (0b10<<20) | ((((Sn)>>1)&15)<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (((Sn)&1)<<7) | (((Sm)&1)<<5) | (((Sm)>>1)&15) )
@@ -514,7 +582,7 @@ Op is 20-27
#define VSUB_F32(Sd, Sn, Sm) EMIT(c__ | (0b1110<<24) | (0<<23) | (((Sd)&1)<<22) | (0b11<<20) | ((((Sn)>>1)&15)<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (((Sn)&1)<<7) | (1<<6) | (((Sm)&1)<<5) | (((Sm)>>1)&15) )
// Cmp between 2 double Dd and Dm
#define VCMP_F64(Dd, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0100<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0<<7) | (1<<6) | (((Dm>>4)&1)<<5) | ((Dm)&15) )
#define VCMP_F64(Dd, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0100<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0<<7) | (1<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
// Cmp between 1 double Dd and 0.0
#define VCMP_F64_0(Dd) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0101<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0<<7) | (1<<6) | (0<<5) | (0) )
// Cmp between 2 single Sd and Sm
@@ -523,10 +591,10 @@ Op is 20-27
#define VCMP_F32_0(Sd) EMIT(c__ | (0b1110<<24) | (1<<23) | (((Sd)&1)<<22) | (0b11<<20) | (0b0101<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (0<<7) | (1<<6) | (0<<5) | (0) )
// Neg F64 Dd = - Dm
#define VNEG_F64(Dd, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0001<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0b01<<6) | (((Dm>>4)&1)<<5) | ((Dm)&15) )
#define VNEG_F64(Dd, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0001<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0b01<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
// Sqrt F64 Dd = - Dm
#define VSQRT_F64(Dd, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0001<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0b11<<6) | (((Dm>>4)&1)<<5) | ((Dm)&15) )
#define VSQRT_F64(Dd, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0001<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0b11<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
// Sqrt F32 Dd = - Dm
#define VSQRT_F32(Sd, Sm) EMIT(c__ | (0b1110<<24) | (1<<23) | (((Sd)&1)<<22) | (0b11<<20) | (0b0001<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (0b11<<6) | (((Sm)&1)<<5) | (((Sm)>>1)&15) )
@@ -597,6 +665,10 @@ Op is 20-27
#define VMOVD(Dd, Dm) EMIT(VMOV_gen(((Dd)>>4)&1, (Dd)&15, ((Dm)>>4)&1, (Dm)&15, 0))
#define VMOVQ(Dd, Dm) EMIT(VMOV_gen(((Dd)>>4)&1, (Dd)&15, ((Dm)>>4)&1, (Dm)&15, 1))
#define VMOV_igen(i, D, imm3, Vd, cmode, Q, op, imm4) (0b1111<<28 | 0b001<<25 | (i)<<24 | 1<<23 | (D)<<22 | (imm3)<<16 | (Vd)<<12 | (cmode)<<8 | (Q)<<6 | (op)<<5 | 1<<4 | (imm4))
#define VMOV_8(Dd, imm) EMIT(VMOV_igen(((imm)>>7)&1, ((Dd)>>4)&1, ((imm)>>4)&7, (Dd)&15, 0b1110, 0, 0, (imm)&15))
#define VMOVQ_8(Dd, imm) EMIT(VMOV_igen(((imm)>>7)&1, ((Dd)>>4)&1, ((imm)>>4)&7, (Dd)&15, 0b1110, 1, 0, (imm)&15))
#define VLD1LANE_gen(D, Rn, Vd, size, index_align, Rm) (0b1111<<28 | 0b0100<<24 | 1<<23 | (D)<<22 | 0b10<<20 | (Rn)<<16 | (Vd)<<12 | (size)<<10 | (index_align)<<4 | (Rm))
#define VLD1LANE_8(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 0, (index)<<1, 15))
#define VLD1LANE_16(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 1, (index)<<2, 15))
@@ -644,6 +716,9 @@ Op is 20-27
#define VBICD(Dd, Dn, Dm) EMIT(VBIC_gen(((Dd)>>4)&1, (Dd)&15, ((Dn)>>4)&1, (Dn)&15, ((Dm)>>4)&1, (Dm)&15, 0))
#define VBICQ(Dd, Dn, Dm) EMIT(VBIC_gen(((Dd)>>4)&1, (Dd)&15, ((Dn)>>4)&1, (Dn)&15, ((Dm)>>4)&1, (Dm)&15, 1))
#define VBIC_igen(i, D, imm3, Vd, cmode, Q, imm4) (0b1111<<28 | 0b001<<25 | (i)<<24 | 1<<23 | (D)<<22 | (imm3)<<16 | (Vd)<<12 | (cmode)<<8 | (Q)<<6 | 0b11<<4 | (imm4))
#define VBICQ_16_imm(Dd, imm) EMIT(VBIC_16_imm(((imm)>>7)&1, (Dd>>4)&1, ((imm)>>4)&7, (Dd)&15, 0b1001, 1, (imm)&15))
#define VCEQ_I_gen(size, D, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 0<<23 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b1000<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | 1<<4 | (Vm))
#define VCEQ_8(Dd, Dn, Dm) EMIT(VCEQ_I_gen(0, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VCEQQ_8(Dd, Dn, Dm) EMIT(VCEQ_I_gen(0, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
@@ -766,6 +841,8 @@ Op is 20-27
#define VCVTn_S32_F32(Dd, Dm) EMIT(VCVT_NEON_gen(((Dd)>>4)&1, 2, (Dd)&15, 0b10, 0, ((Dm)>>4)&1, (Dm)&15))
#define VMULL_NEON_gen(U, D, size, Vn, Vd, op, N, M, Vm) (0b1111<<28 | 0b001<<25 | (U)<<24 | 1<<23 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b11<<10 | (op)<<9 | (N)<<7 | (M)<<5 | (Vm))
#define VMULL_S16_S8(Dd, Dn, Dm) EMIT(VMULL_NEON_gen(0, ((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, 0, ((Dn)>>4)&1, ((Dm)>>4)&1, (Dm)&15))
#define VMULL_U16_U8(Dd, Dn, Dm) EMIT(VMULL_NEON_gen(1, ((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, 0, ((Dn)>>4)&1, ((Dm)>>4)&1, (Dm)&15))
#define VMULL_S32_S16(Dd, Dn, Dm) EMIT(VMULL_NEON_gen(0, ((Dd)>>4)&1, 1, (Dn)&15, (Dd)&15, 0, ((Dn)>>4)&1, ((Dm)>>4)&1, (Dm)&15))
#define VMULL_U32_U16(Dd, Dn, Dm) EMIT(VMULL_NEON_gen(1, ((Dd)>>4)&1, 1, (Dn)&15, (Dd)&15, 0, ((Dn)>>4)&1, ((Dm)>>4)&1, (Dm)&15))
#define VMULL_S64_S32(Dd, Dn, Dm) EMIT(VMULL_NEON_gen(0, ((Dd)>>4)&1, 2, (Dn)&15, (Dd)&15, 0, ((Dn)>>4)&1, ((Dm)>>4)&1, (Dm)&15))
@@ -778,8 +855,8 @@ Op is 20-27
#define VMUL_16(Dd, Dn, Dm) EMIT(VMUL_NEON_gen(0, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VEXT_gen(D, Vn, Vd, imm4, N, Q, M, Vm) (0b1111<<28 | 0b0010<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (Vn)<<16 | (Vd)<<12 | (imm4)<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | (Vm))
#define VEXT_8(Dd, Dn, Dm, imm4) EMIT(VEXT_gen(((Dd)>>4)&1, (Dn)&15, (Dd)&15, imm4, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VEXTQ_8(Dd, Dn, Dm, imm4) EMIT(VEXT_gen(((Dd)>>4)&1, (Dn)&15, (Dd)&15, imm4, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VEXT_8(Dd, Dn, Dm, imm4) EMIT(VEXT_gen(((Dd)>>4)&1, (Dn)&15, (Dd)&15, (imm4), ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VEXTQ_8(Dd, Dn, Dm, imm4) EMIT(VEXT_gen(((Dd)>>4)&1, (Dn)&15, (Dd)&15, (imm4), ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VMVN_gen(D, size, Vd, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | (Vd)<<12 | 0b1011<<7 | (Q)<<6 | (M)<<5 | 0<<4 | (Vm))
#define VMVNQ(Dd, Dm) EMIT(VMVN_gen(((Dd)>>4)&1, 0, (Dd)&15, 1, ((Dm)>>4)&1, (Dm)&15))
@@ -809,6 +886,10 @@ Op is 20-27
#define VTBL1_8(Dd, Dn, Dm) EMIT(VTBL_gen(((Dd)>>4)&1, (Dn)&15, (Dd)&15, 0b00, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
// Vector Table lookup, take elements from Dn/Dn+1, and using lookup table Dm, put elements in Dd
#define VTBL2_8(Dd, Dn, Dm) EMIT(VTBL_gen(((Dd)>>4)&1, (Dn)&15, (Dd)&15, 0b01, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
// Vector Table lookup eXtension, take elements from Dn, and using lookup table Dm, put elements in Dd, outer element untouched
#define VTBLX1_8(Dd, Dn, Dm) EMIT(VTBL_gen(((Dd)>>4)&1, (Dn)&15, (Dd)&15, 0b00, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
// Vector Table lookup eXtension, take elements from Dn/Dn+1, and using lookup table Dm, put elements in Dd, outer element untouched
#define VTBLX2_8(Dd, Dn, Dm) EMIT(VTBL_gen(((Dd)>>4)&1, (Dn)&15, (Dd)&15, 0b01, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VRECPE_gen(D, size, Vd, F, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | 0b11<<16 | (Vd)<<12 | 0b010<<9 | (F)<<8 | (Q)<<6 | (M)<<5 | (Vm))
// Vector Reciprocal Estimate of Dm to Dd
@@ -818,11 +899,20 @@ Op is 20-27
// Vector Reciprocal Step of Dn and Dm to Dd
#define VRECPSQ_F32(Dd, Dn, Dm) EMIT(VRECPS_gen(((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VSWAP_gen(D, size, Vd, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<20 | (size)<<18 | 0b10<<16 | (Vd)<<12 | 0b0000<<7 | (Q)<<6 | (M)<<5 | (Vm))
#define VRSQRTE_gen(D, size, Vd, F, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | 0b11<<16 | (Vd)<<12 | 0b010<<9 | (F)<<8 | 1<<7 | (Q)<<6 | (M)<<5 | (Vm))
// Vector Reciprocal Square Root Estimate of Dm to Dd
#define VRSQRTEQ_F32(Dd, Dm) EMIT(VRSQRTE_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VRSQRTS_gen(D, size, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b0010<<24 | 0<<23 | (D)<<22 | 1<<21 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b1111<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | 1<<4 | (Vm))
// Vector Reciprocal Square Root Step of Dn and Dm to Dd
#define VRSQRTSQ_F32(Dd, Dn, Dm) EMIT(VRSQRTS_gen(((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VSWP_gen(D, size, Vd, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | 0b10<<16 | (Vd)<<12 | 0b0000<<7 | (Q)<<6 | (M)<<5 | (Vm))
// Swap Double vectors content
#define VSWAP(Dd, Dm) EMIT(VSWAP_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 0, ((Dm)>>4)&1, (Dm)&15)))
#define VSWP(Dd, Dm) EMIT(VSWP_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 0, ((Dm)>>4)&1, (Dm)&15))
// Swap Quad vectors content
#define VSWAPQ(Dd, Dm) EMIT(VSWAP_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 1, ((Dm)>>4)&1, (Dm)&15)))
#define VSWPQ(Dd, Dm) EMIT(VSWP_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 1, ((Dm)>>4)&1, (Dm)&15))
#define VQADD_gen(U, D, size, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b001<<25 | (U)<<24 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b0000<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | 1<<4 | (Vm))
// Add with saturation unsigned 8bits
@@ -903,4 +993,124 @@ Op is 20-27
#define VNEGN_F32(Dd, Dm) EMIT(VNEGN_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VNEGNQ_F32(Dd, Dm) EMIT(VNEGN_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VMINMAXF_gen(D, op, sz, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b0010<<24 | (D)<<22 | (op)<<21 | (sz)<<20 | (Vn)<<16 | (Vd)<<12 | 0b1111<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | (Vm))
#define VMINQ_F32(Dd, Dn, Dm) EMIT(VMINMAXF_gen(((Dd)>>4)&1, 1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VMAXQ_F32(Dd, Dn, Dm) EMIT(VMINMAXF_gen(((Dd)>>4)&1, 0, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VABD_gen(U, D, size, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 1<<25 | (U)<<24 | 0<<23 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b0111<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | (Vm))
// Compute absolute difference of U8
#define VABD_U8(Dd, Dn, Dm) EMIT(VABD_gen(1, ((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VABDQ_U8(Dd, Dn, Dm) EMIT(VABD_gen(1, ((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VPADAL_gen(D, size, Vd, op, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | (Vd)<<12 | 0b0110<<8 | (op)<<7 | (Q)<<6 | (M)<<5 | (Vm))
// Add pair of U8 from Dm, Add result in U16 in Dd (some position as U8U8)
#define VPADAL_U8(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 1, 0, ((Dm)>>4)&1, (Dm)&15))
// Add pair of U16 from Dm, Add result in U32 in Dd
#define VPADAL_U16(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b01, (Dd)&15, 1, 0, ((Dm)>>4)&1, (Dm)&15))
// Add pair of U32 from Dm, Add result in U64 in Dd
#define VPADAL_U32(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 1, 0, ((Dm)>>4)&1, (Dm)&15))
// Add pair of S8 from Dm, Add result in S16 in Dd (some position as S8S8)
#define VPADAL_S8(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
// Add pair of S16 from Dm, Add result in S32 in Dd
#define VPADAL_S16(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b01, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
// Add pair of S32 from Dm, Add result in S64 in Dd
#define VPADAL_S32(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
// Add pair of U8 from Dm, Add result in U16 in Dd (some position as U8U8)
#define VPADALQ_U8(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
// Add pair of U16 from Dm, Add result in U32 in Dd
#define VPADALQ_U16(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b01, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
// Add pair of U32 from Dm, Add result in U64 in Dd
#define VPADALQ_U32(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
// Add pair of S8 from Dm, Add result in S16 in Dd (some position as S8S8)
#define VPADALQ_S8(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
// Add pair of S16 from Dm, Add result in S32 in Dd
#define VPADALQ_S16(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b01, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
// Add pair of S32 from Dm, Add result in S64 in Dd
#define VPADALQ_S32(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
#define VPADDL_gen(D, size, Vd, op, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | (Vd)<<12 | 0b0010<<8 | (op)<<7 | (Q)<<6 | (M)<<5 | (Vm))
// Add pair of U8, store result in U16
#define VPADDL_U8(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 1, 0, ((Dm)>>4)&1, (Dm)&15))
// Add pair of U16, store result in U32
#define VPADDL_U16(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b01, (Dd)&15, 1, 0, ((Dm)>>4)&1, (Dm)&15))
// Add pair of U32, store result in U64
#define VPADDL_U32(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 1, 0, ((Dm)>>4)&1, (Dm)&15))
// Add pair of S8, store result in S16
#define VPADDL_S8(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
// Add pair of S16, store result in S32
#define VPADDL_S16(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b01, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
// Add pair of S32, store result in S64
#define VPADDL_S32(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
// Add pair of U8, store result in U16
#define VPADDLQ_U8(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
// Add pair of U16, store result in U32
#define VPADDLQ_U16(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b01, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
// Add pair of U32, store result in U64
#define VPADDLQ_U32(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
// Add pair of S8, store result in S16
#define VPADDLQ_S8(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
// Add pair of S16, store result in S32
#define VPADDLQ_S16(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b01, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
// Add pair of S32, store result in S64
#define VPADDLQ_S32(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
#define VPADD_gen(D, size, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b0010<<24 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b1011<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | 1<<4 | (Vm))
#define VPADD_8(Dd, Dn, Dm) EMIT(VPADD_gen(((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VPADD_16(Dd, Dn, Dm) EMIT(VPADD_gen(((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VPADD_32(Dd, Dn, Dm) EMIT(VPADD_gen(((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
// NO VPADDQ....
#define VPADD_Fgen(D, size, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b1101<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | 0<<4 | (Vm))
// Add pair of F32, store result in F32
#define VPADD_F32(Dd, Dn, Dm) EMIT(VPADD_gen(((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VMINMAX_gen(U, D, size, Vn, Vd, N, Q, M, op, Vm) (0b1111<<28 | 0b001<<25 | (U)<<24 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b110<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | (op)<<4 | (Vm))
#define VMIN_U8(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 1, (Dm)&15))
#define VMIN_U16(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 1, (Dm)&15))
#define VMIN_U32(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 1, (Dm)&15))
#define VMIN_U64(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b11, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 1, (Dm)&15))
#define VMIN_S8(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 1, (Dm)&15))
#define VMIN_S16(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 1, (Dm)&15))
#define VMIN_S32(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 1, (Dm)&15))
#define VMIN_S64(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b11, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 1, (Dm)&15))
#define VMINQ_U8(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 1, (Dm)&15))
#define VMINQ_U16(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 1, (Dm)&15))
#define VMINQ_U32(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 1, (Dm)&15))
#define VMINQ_U64(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b11, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 1, (Dm)&15))
#define VMINQ_S8(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 1, (Dm)&15))
#define VMINQ_S16(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 1, (Dm)&15))
#define VMINQ_S32(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 1, (Dm)&15))
#define VMINQ_S64(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b11, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 1, (Dm)&15))
#define VMAX_U8(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 0, (Dm)&15))
#define VMAX_U16(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 0, (Dm)&15))
#define VMAX_U32(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 0, (Dm)&15))
#define VMAX_U64(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b11, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 0, (Dm)&15))
#define VMAX_S8(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 0, (Dm)&15))
#define VMAX_S16(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 0, (Dm)&15))
#define VMAX_S32(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 0, (Dm)&15))
#define VMAX_S64(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b11, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 0, (Dm)&15))
#define VMAXQ_U8(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 0, (Dm)&15))
#define VMAXQ_U16(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 0, (Dm)&15))
#define VMAXQ_U32(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 0, (Dm)&15))
#define VMAXQ_U64(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b11, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 0, (Dm)&15))
#define VMAXQ_S8(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 0, (Dm)&15))
#define VMAXQ_S16(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 0, (Dm)&15))
#define VMAXQ_S32(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 0, (Dm)&15))
#define VMAXQ_S64(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b11, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 0, (Dm)&15))
#define VRHADD_gen(U, D, size, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 1<<25 | (U)<<24 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b0001<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | (Vm))
// Dd <= (Dn + Dm + 1)>>1
#define VRHADD_U8(Dd, Dn, Dm) EMIT(VRHADD_gen(1, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VRHADD_U16(Dd, Dn, Dm) EMIT(VRHADD_gen(1, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VRHADD_U32(Dd, Dn, Dm) EMIT(VRHADD_gen(1, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VRHADD_S8(Dd, Dn, Dm) EMIT(VRHADD_gen(0, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VRHADD_S16(Dd, Dn, Dm) EMIT(VRHADD_gen(0, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VRHADD_S32(Dd, Dn, Dm) EMIT(VRHADD_gen(0, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VRHADDQ_U8(Dd, Dn, Dm) EMIT(VRHADD_gen(1, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VRHADDQ_U16(Dd, Dn, Dm) EMIT(VRHADD_gen(1, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VRHADDQ_U32(Dd, Dn, Dm) EMIT(VRHADD_gen(1, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VRHADDQ_S8(Dd, Dn, Dm) EMIT(VRHADD_gen(0, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VRHADDQ_S16(Dd, Dn, Dm) EMIT(VRHADD_gen(0, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VRHADDQ_S32(Dd, Dn, Dm) EMIT(VRHADD_gen(0, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#endif //__ARM_EMITTER_H__
+9
View File
@@ -16,3 +16,12 @@ arm_epilog:
pop {r4-r11, pc}
//end, return...
//bx lr
.global arm_epilog_fast
arm_epilog_fast:
//restore all used register
//vpop {d8-d15}
pop {r4-r11, pc}
//end, return...
//bx lr
+594
View File
@@ -0,0 +1,594 @@
; TYPE fields separated by spaces Assembler syntax
; When there are mutiple assembler syntax (like for LDR (immediate)), separate them based on the bytes
; E.G. for LDR (immediate), there are 3 lines with the 3 different asm syntaxes
# Field options:
# --------------
# Syntax: ... field/coption1(coption2)* ... (inside fields)
# Where each c correspond to the option character
# and optionN to the Nth option value
# ---
# c = '0'..'9'/'A'..'F': option=[01]
# Force the cth bit (hex) of the field (starting from LSB) to be <option>
# c = '=': option=[01x]{field_len}
# Force the field to have the given bits (where x = anything, starts from MSB)
# Post-fields option:
# -------------------
# Syntax: [fields] @ typeoption1 args1 typeoption2 args2 @ [Assembler syntax]
# ---
# typeoption contains '=' (l=r): args1=((.*) )?([^, ]*),([^, ]*),([^, ]*)@
# Changes a value between two other depending on whether l == r
# \2 is init (suffixed by ';', optional), \3 is set to \4 if true or \5 if false
# (cf VMOV/VORR aka V\op\, VEOR/VBIF/VBIT/VBSL aka V\op\)
# The 'true regex' is typeoption=([^= ]*)(=([^= ]*))+
# args1=((.*) )?([^, ]*),(([^, ]*),)+([^, ]*)@
# with the number of typeoption:\2 being equal to the number of args1:\4
# <a>=<b>[=<c>...] <initialization> <variable-changed>,<changed-into-if-a=b>[,<changed-into-if-a=c>...],<changed-into-else>@
# OR
# typeoption is discarded and must be set to '=', args1=((.*) )?(@@ (( ?.*[^@])*)@ )+([^, ]*),(([^, ]*),)+([^, ]*)
# \2 is init (suffixed by ';', optional), \6 is set to \7 if true or \8 if false
# The difference with the simple switch is that \4 is the test (inside the `if`)
# If there are multiple @@s, there are multiple `if`s (separated by `else`s)
# The 'true regex' is [DISCARDED]typeoption==
# args1=((.*) )?(@@ (( ?.*[^@])*)@ )+([^, ]*),([^, ]*),([^, ]*)
# <.>=<.>[=<c>...] <initialization> @@ <test>@[ @@ <test2>@...] <variable-changed>,<changed-into-if-a=b>,<changed-into-else>
# OR
# args1=((.*) )?!@(( [^%]*[^%@])*)%(( ?[^%]*[^%@])*)@(( .*[^@])*)@(( .*[^@])*)@
# Replaced by '\1; if (<equality>) { \3\7\5; } else { \3\9\5; }'
# Meaning, <.=.> <initialization> !@ <common-left-part>%<common-right-part>@ <substitute-true>@ <substitute-false>@ <...>
# (cf VMOV/VORR, aka V\op\ with the lastop variable)
# You can also add more '=' with corresponding substitutes.
# You can also add more '%' with corresponding substitutes.
# ----
# Inside the assembler syntax, you can add \var\ to mark a variable to be replaced
# (Meaning, %s and `var` as argument to printf)
# Full syntax: \\(%[0-9+]*.)?(.*)\\
# If \1 != "", add \1 to the string in printf, and in any case append \2 as argument to printf
! HACKS: (list of notable differences between the doc and this file)
! ------
! In theory, (0) and (1) bits are as important as 0 and 1:
! > An instruction is UNPREDICTABLE if:
! > • It is declared as UNPREDICTABLE in an instruction description or in this chapter.
! > • The pseudocode for that encoding does not indicate that a different special case applies, and a bit marked (0)
! or (1) in the encoding diagram of an instruction is not 0 or 1 respectively.
! - ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition
! In practice, they are ignored here.
! SWP, SWPB, VMOV (VFPU): Rt2 (field and assembly) -> Rn (field and assembly)
! BKPT: must be AL, so cond (field) -> cond/=1110 (constrained field)
! PKHBT and PKHTB: {, LSL/ASR #<imm>} (assembly) -> {, <shift>} (assembly)
! PKHBT and PKHTB: immediate shift but shift & 1 -> ARMs (type)
! All NEON operations (advanced SIMD): limited, so multiply the lines
! VMOV (register): Vm ... Vm VMOV (field, assembly) -> Vn ... Vm @ m=n ...@ @ V\op\ (field, switchable var, assembly)
! VMOV is VORR constrained -> (removed VORR)
! VEOR, VBSL, VBIT, VBIF differ only depending on 2 bits: 0/1 0/1 ... VEOR -> @<2> ... @ ... @ V\op\ (field, switchable var, assembly)
! Three registers of different lengths (when having L and W variants): op (field) -> Q (field)
; ========== BEGINNING OF REGISTERED INSTRUCTIONS =========
# This instruction changes the instruction set to Thumb! Disabled (but valid)
#ARM_ 1 1 1 1 1 0 1 @<1> imm24 @ set imm24 = (imm24 << 2) + (param << 1)@ @ BLX <label>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 op 0 N Q M 0 Vm VH\(op ? "SUB" : "ADD")\<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 0 0 N Q M 1 Vm VQADD<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 0 1 N Q M 0 Vm VRHADD<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D 0 0 Vn Vd 0 0 0 1 N Q M 1 Vm VAND<c> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D 0 1 Vn Vd 0 0 0 1 N Q M 1 Vm VBIC<c> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D 1 0 Vn Vd 0 0 0 1 N Q M 1 Vm @ m=n const char* op op,"MOV","ORR"@ m=n char lastop[6] !@ %@ lastop[0] = '\0'@ sprintf(lastop, ", %s", vecname[(q << 5) + 0x20 + n])@ @ V\op\<c> <Qd>, <Qm>\lastop\
NEON 1 1 1 1 0 0 1 0 0 D 1 1 Vn Vd 0 0 0 1 N Q M 1 Vm VORN<c> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 1 0 D @<2> Vn Vd 0 0 0 1 N Q M 1 Vm @ param=0b00=0b01=0b10 const char* op op,"EOR","BSL","BIT","BIF"@ @ V\op\<c> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 1 0 N Q M 1 Vm VQSUB<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 1 1 N Q M op Vm @ op=0 const char* strict strict,"T","E"@ @ VCG\strict\<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 0 N Q M 0 Vm VSHL<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 0 N Q M 1 Vm VQSHL<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 1 N Q M 0 Vm VRSHL<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 1 N Q M 1 Vm VQRSHL<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 1 0 N Q M op Vm @ op=0 const char* opname opname,"MAX","MIN"@ @ V\opname\<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 1 1 N Q M 0 Vm VABD<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 1 1 N Q M 1 Vm VABA<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 op 0 D size Vn Vd 1 0 0 0 N Q M 0 Vm @ op=0 const char* opname opname,"ADD","SUB"@ @ V\opname\<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D size Vn Vd 1 0 0 0 N Q M 1 Vm VTST<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 1 0 D size Vn Vd 1 0 0 0 N Q M 1 Vm VCEQ<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 1 0 0 1 N Q M 0 Vm @ set size = 8 << size@ @ VML\(u ? "S" : "A")\<c>.I\%dsize\ <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 1 0 0 1 N Q M 1 Vm VMUL<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 1 0 1 0 N Q M op Vm @ op=0 const char* opname opname,"MAX","MIN"@ @ VP\opname\<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D size Vn Vd 1 0 1 1 N Q M 0 Vm VQDMULH<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 1 0 D size Vn Vd 1 0 1 1 N Q M 0 Vm VQRDMULH<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D size Vn Vd 1 0 1 1 N Q/=0 M 1 Vm VPADD<c>.<dt> <Dd>, <Dn>, <Dm>
NEON 1 1 1 1 0 0 1 0 0 D U sz/=0 Vn Vd 1 1 0 0 N Q M 1 Vm @ u=0 const char* y y,"A","S"@ @ VFM\y\<c>.F32 <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D U sz/=0 Vn Vd 1 1 0 1 N Q M 0 Vm @ u=0 const char* op op,"ADD","SUB"@ @ V\op\<c>.F32 <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 1 0 D 0 sz/=0 Vn Vd 1 1 0 1 N Q/=0 M 0 Vm VPADD.F32 <Dd>, <Dn>, <Dm>
NEON 1 1 1 1 0 0 1 1 0 D 1 sz/=0 Vn Vd 1 1 0 1 N Q M 0 Vm VABD.F32 <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D op sz/=0 Vn Vd 1 1 0 1 N Q M 1 Vm VML\(op ? "S" : "A")\<c>.F32 <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 1 0 D 0 sz/=0 Vn Vd 1 1 0 1 N Q M 1 Vm VMUL.F32 <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D 0 sz/=0 Vn Vd 1 1 1 0 N Q M 0 Vm VCEQ.F32 <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 1 0 D op sz/=0 Vn Vd 1 1 1 0 N Q M 0 Vm @ op=1 const char* strict strict,"T","E"@ @ VCG\strict\.F32 <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 1 0 D op sz/=0 Vn Vd 1 1 1 0 N Q M 1 Vm @ op=1 const char* strict strict,"T","E"@ @ VACG\strict\.F32 <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D op sz/=0 Vn Vd 1 1 1 1 N Q M 0 Vm @ op=0 const char* opname opname,"MAX","MIN"@ @ V\opname\.F32 <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 1 0 D op sz/=0 Vn Vd 1 1 1 1 N Q M 0 Vm @ op=0 const char* opname opname,"MAX","MIN"@ @ VP\opname\.F32 <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D 0 sz/=0 Vn Vd 1 1 1 1 N Q M 1 Vm VRECPS.F32 <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D 1 sz/=0 Vn Vd 1 1 1 1 N Q M 1 Vm VRSQRTS.F32 <Qd>, <Qn>, <Qm>
INVALIDATE 1 1 1 1 0 0 1 <1> 0 <23>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=0xx0 0 Q op/=0 1 imm4 VMOV<c>.<dt> <Qd>, #<imm>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=0xx1 0 Q op/=0 1 imm4 VORR<c>.<dt> <Qd>, #<imm>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=10x0 0 Q op/=0 1 imm4 VMOV<c>.<dt> <Qd>, #<imm>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=10x1 0 Q op/=0 1 imm4 VORR<c>.<dt> <Qd>, #<imm>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=11xx 0 Q op/=0 1 imm4 VMOV<c>.<dt> <Qd>, #<imm>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=0xx0 0 Q op/=1 1 imm4 VMVN<c>.<dt> <Qd>, #<imm>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=0xx1 0 Q op/=1 1 imm4 VBIC<c>.<dt> <Qd>, #<imm>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=10x0 0 Q op/=1 1 imm4 VMVN<c>.<dt> <Qd>, #<imm>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=10x1 0 Q op/=1 1 imm4 BIC<c>.<dt> <Qd>, #<imm>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=110x 0 Q op/=1 1 imm4 VMVN<c>.<dt> <Qd>, #<imm>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=1110 0 Q op/=1 1 imm4 VMOV<c>.<dt> <Qd>, #<imm>
;INVALIDATE 1 1 1 1 0 0 1 <1> 1 <1> 0 0 0 <3> <4> <4>/=1111 0 <1> <1>/=1 1 <4>
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <1> 0 0 0 <11> 0 <2> 1 <4>
# Special case for VMOVL (harder to do it on the documented place)
NEON 1 1 1 1 0 0 1 0 1 D 0 0 1 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S8 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 0 1 D 0 1 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S16 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 0 1 D 1 0 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S32 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 0 0 1 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U8 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 0 1 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U16 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 0 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U32 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 0 0 0 0 L Q M 1 Vm VSHR<c>.<dt> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 0 0 0 1 L Q M 1 Vm VSRA<c>.<dt> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 0 0 1 0 L Q M 1 Vm VRSHR<c>.<dt> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 0 0 1 1 L Q M 1 Vm VRSRA<c>.<dt> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 1 1 D imm6 Vd 0 1 0 0 L Q M 1 Vm VSRI<c>.<size> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 0 1 D Imm6 Vd 0 1 0 1 L Q M 1 Vm VSHL<c>.I<size> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 1 1 D Imm6 Vd 0 1 0 1 L Q M 1 Vm VSLI<c>.<size> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 U 1 D Imm6 Vd 0 1 1 op L Q M 1 Vm VQSHL\((u & op) ? "U" : "")\<c>.<dt> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 0 1 D imm6 Vd 1 0 0 0 0 0 M 1 Vm VSHRN<c>.I<size> <Dd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 0 1 D imm6 Vd 1 0 0 0 0 1 M 1 Vm VRSHRN<c>.I<size> <Dd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 1 0 0 op 0 0 M 1 Vm VQSHR\((u & op) ? "U" : "")\N<c>.<dt> <Dd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 1 0 0 op 0 1 M 1 Vm VQRSHR\((u & op) ? "U" : "")\N<c>.<dt> <Dd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 1 0 0 M 1 Vm VSHLL<c>.<dt> <Qd>, <Dm>, #\%d8 &l&l size\
NEON 1 1 1 1 0 0 1 U 1 D Imm6 Vd 1 0 1 0 0 0 M 1 Vm VSHLL<c>.<dt> <Qd>, <Dm>, #<imm>
; VCVT: if imm6 IN "0xxxxx" then UNDEFINED;
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <1> 0 <9> 1 1 1 <1> 0 <2> 1 <4>
NEON 1 1 1 1 0 0 1 0 1 D IMM6 Vd 1 1 1 0 0 Q M 1 Vm VCVT<c>.F32.S32 <Qd>, <Qm>, #<fbits>
NEON 1 1 1 1 0 0 1 0 1 D IMM6 Vd 1 1 1 1 0 Q M 1 Vm VCVT<c>.S32.F32 <Qd>, <Qm>, #<fbits>
NEON 1 1 1 1 0 0 1 1 1 D IMM6 Vd 1 1 1 0 0 Q M 1 Vm VCVT<c>.F32.U32 <Qd>, <Qm>, #<fbits>
NEON 1 1 1 1 0 0 1 1 1 D IMM6 Vd 1 1 1 1 0 Q M 1 Vm VCVT<c>.U32.F32 <Qd>, <Qm>, #<fbits>
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <18> 1 <4>
NEON 1 1 1 1 0 0 1 0 1 D 1 1 Vn Vd IMM4 N Q M 0 Vm VEXT<c>.8 <Qd>, <Qn>, <Qm>, #<imm>
# size + param < 3
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=11 0 0 <4> 0 0 0 <2> <2> 0 <4>
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=10 0 0 <4> 0 0 0 <2>/11 <2> 0 <4>
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=10 0 0 <4> 0 0 0 <2>/01 <2> 0 <4>
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=01 0 0 <4> 0 0 0 <2>/11 <2> 0 <4>
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=00 0 0 <4> 0 0 0 <2>/=11 <2> 0 <4>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 0 0 @<2> Q M 0 Vm VREV\%d16 &l&l param\<c>.\%d8 &l&l size\ <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 0 1 0 U Q M 0 Vm VPADDL<c>.<dt> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 0 0 0 Q M 0 Vm VCLS<c>.<dt> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 0 0 1 Q M 0 Vm VCLZ<c>.<dt> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=00 0 0 Vd 0 1 0 1 0 Q M 0 Vm VCNT<c>.8 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=00 0 0 Vd 0 1 0 1 1 Q M 0 Vm VMVN<c> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 1 0 U Q M 0 Vm VPADAL<c>.<dt> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 1 1 0 Q M 0 Vm VQABS<c>.<dt> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 1 1 1 Q M 0 Vm VQNEG<c>.<dt> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 0 0 0 Q M 0 Vm VCGT<c>.<dt> <Qd>, <Qm>, #0
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 0 0 1 Q M 0 Vm VCGE<c>.<dt> <Qd>, <Qm>, #0
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 0 1 0 Q M 0 Vm VCEQ<c>.<dt> <Qd>, <Qm>, #0
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 0 1 1 Q M 0 Vm VCLE<c>.<dt> <Qd>, <Qm>, #0
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 1 0 0 Q M 0 Vm VCLT<c>.<dt> <Qd>, <Qm>, #0
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 1 1 0 Q M 0 Vm VABS<c>.<dt> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 1 1 1 Q M 0 Vm VNEG<c>.<dt> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=00 1 0 Vd 0 0 0 0 0 Q M 0 Vm VSWP<c> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 0 0 1 Q M 0 Vm VTRN<c>.\%d8 &l&l size\ <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 0 1 0 Q M 0 Vm VUZP<c>.\%d8 &l&l size\ <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 0 1 1 Q M 0 Vm VZIP<c>.\%d8 &l&l size\ <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 0 0 0 M 0 Vm VMOVN<c>.<dt> <Dd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 0 0 1 M 0 Vm VQMOVUN<c>.S\%d16 &l&l size\ <Dd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 0 1 U M 0 Vm @ set u = 1 - u@ set ++size@ @ VQMOVN<c>.<dt> <Dd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 1 0 0 M 0 Vm VSHLL<c>.I\%d8 &l&l size\ <Qd>, <Dm>, #\%d8 &l&l size\
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=01 1 0 Vd 0 1 1 0 0 0 M 0 Vm VCVT<c>.F16.F32 <Dd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=01 1 0 Vd 0 1 1 1 0 0 M 0 Vm VCVT<c>.F32.F16 <Qd>, <Dm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 1 Vd 0 1 0 F 0 Q M 0 Vm VRECPE<c>.<dt> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 1 Vd 0 1 0 F 1 Q M 0 Vm VRSQRTE<c>.<dt> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=10 1 1 Vd 0 1 1 0 0 Q M 0 Vm VCVT<c>.F32.S32 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=10 1 1 Vd 0 1 1 0 1 Q M 0 Vm VCVT<c>.S32.F32 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=10 1 1 Vd 0 1 1 1 0 Q M 0 Vm VCVT<c>.F32.U32 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=10 1 1 Vd 0 1 1 1 1 Q M 0 Vm VCVT<c>.U32.F32 <Qd>, <Qm>
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <8> 0 <6> 0 <4>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 Vn Vd 1 0 @<2> N op M 0 Vm @ param=0b00 char list[10] !@ sprintf(list, %)@ "{%s}", vecname[0x20 + n]@ "{%s-%s}", vecname[0x20 + n], vecname[0x20 + n + param]@ @ VTB\(op ? "X" : "L")\<c>.8 <Dd>, \list\, <Dm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 imm4 Vd 1 1 0 0 0 Q M 0 Vm VDUP<c>.\%dsize\ <Qd>, <Dm[x]>
; size != 11
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <1> 1 1 <13> 0 <1> 0 <4>
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 0 0 0 Q N 0 M 0 Vm VADD\(q ? "W" : "L")\<c>.<dt> <qd>, <Qn>, <Dm>
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 0 0 1 Q N 0 M 0 Vm VSUB\(q ? "W" : "L")\<c>.<dt> <qd>, <Qn>, <Dm>
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 0 1 0 0 N 0 M 0 Vm @ set size = 16 << size@ @ VADDHN<c>.I\%dsize\ <Dd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D size Vn Vd 0 1 0 0 N 0 M 0 Vm VRADDHN<c>.<dt> <Dd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 0 1 0 1 N 0 M 0 Vm VABAL<c>.<dt> <Qd>, <Dn>, <Dm>
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 0 1 1 0 N 0 M 0 Vm VSUBHN<c>.<dt> <Dd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D size Vn Vd 0 1 1 0 N 0 M 0 Vm VRSUBHN<c>.<dt> <Dd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 0 1 1 1 N 0 M 0 Vm VABDL<c>.<dt> <Qd>, <Dn>, <Dm>
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 1 0 op 0 N 0 M 0 Vm VML\(op ? "S" : "A")\L<c>.<dt> <Qd>, <Dn>, <Dm>
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 1 0 op 1 N 0 M 0 Vm VQDML\(op ? "S" : "A")\L<c>.<dt> <Qd>, <Dn>, <Dm>
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 1 1 0 0 N 0 M 0 Vm VMULL<c>.<dt> <Qd>, <Dn>, <Dm>
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 1 1 0 1 N 0 M 0 Vm VQDMULL<c>.<dt> <Qd>, <Dn>, <Dm>
NEON 1 1 1 1 0 0 1 U/=0 1 D size/=00 Vn Vd 1 1 1 0 N 0 M 0 Vm @ set uint8_t size = 0@ @ VMULL<c>.<dt> <Qd>, <Dn>, <Dm>
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <16> 0 <1> 0 <4>
; Put after, otherwise some instructions are shadowed
NEON 1 1 1 1 0 0 1 Q 1 D size Vn Vd 0 op 0 F N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VML\(op ? "S" : "A")\<c>.<dt> <Qd>, <Qn>, <Dm[x]>
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 0 op 1 0 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VML\(op ? "S" : "A")\L<c>.<dt> <Qd>, <Dn>, <Dm[x]>
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 0 op 1 1 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VQDML\(op ? "S" : "A")\L<c>.<dt> <Qd>, <Dn>, <Dm[x]>
NEON 1 1 1 1 0 0 1 Q 1 D size Vn Vd 1 0 0 F N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VMUL<c>.<dt> <Qd>, <Qn>, <Dm[x]>
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 1 0 1 0 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VMULL<c>.<dt> <Qd>, <Qn>, <Dm[x]>
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 1 0 1 1 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VQDMULL<c>.<dt> <Qd>, <Qn>, <Dm[x]>
NEON 1 1 1 1 0 0 1 Q 1 D size Vn Vd 1 1 0 0 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VQDMULH<c>.<dt> <Qd>, <Qn>, <Dm[x]>
NEON 1 1 1 1 0 0 1 Q 1 D size Vn Vd 1 1 0 1 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VQRDMULH<c>.<dt> <Qd>, <Qn>, <Dm[x]>
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <16> 0 <1> 0 <4>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 0 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 1 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
;INVALIDATE 1 1 1 1 0 1 0 0 0 <1> 0 0 <22>
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 0 0 <8> 1 1 <10>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 0 @<4> 1 1 1 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 0 @<4> 1 1 0 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 0 @<4> Rm @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> Rm @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
;INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 0 0 <20>
;INVALIDATE 1 1 1 1 0 1 0 0 <2> 0 0 <20>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 0 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 1 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
;INVALIDATE 1 1 1 1 0 1 0 0 0 <1> 1 0 <22>
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 1 0 <8> 1 1 <10>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> 1 1 1 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> 1 1 0 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> Rm @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> Rm @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
;INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 1 0 <20>
;INVALIDATE 1 1 1 1 0 1 0 0 <2> 1 0 <20>
INVALIDATE 1 1 1 1 0 1 0 0 <3> 0 <20>
; ===== No more 1 1 1 1 ..., so invalidate all of them ====
INVALIDATE 1 1 1 1 <28>
ARMS cond 0 0 0 0 0 0 0 S Rn Rd imm5 type 0 Rm AND{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 0 0 0 0 S Rd (0) (0) (0) (0) Rm 1 0 0 1 Rn MUL{S}<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 0 0 0 U 0 0 0 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm STRH<c> <Rt>, [<Rn>], +/-<Rm>
ARM_ cond 0 0 0 0 U 0 0 0 Rn Rt (0) (0) (0) (0) 1 1 0 1 Rm LDRD<c> <Rt>, <Rt2>, [<Rn>], +/-<Rm>
ARM_ cond 0 0 0 0 U 0 0 0 Rn Rt (0) (0) (0) (0) 1 1 1 1 Rm STRD<c> <Rt>, <Rt2>, [<Rn>], +/-<Rm>
ARM_ cond 0 0 0 0 U 0 0 1 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm LDRH<c> <Rt>, [<Rn>], +/-<Rm>
ARM_ cond 0 0 0 0 U 0 0 1 Rn Rt (0) (0) (0) (0) 1 1 0 1 Rm LDRSB<c> <Rt>, [<Rn>], +/-<Rm>
ARM_ cond 0 0 0 0 U 0 0 1 Rn Rt (0) (0) (0) (0) 1 1 1 1 Rm LDRSH<c> <Rt>, [<Rn>], +/-<Rm>
ARMS cond 0 0 0 0 0 0 1 S Rn Rd imm5 type 0 Rm EOR{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 0 0 0 1 S Rd Ra Rm 1 0 0 1 Rn MLA{S}<c> <Rd>, <Rn>, <Rm>, <Ra>
ARM_ cond 0 0 0 0 U 0 1 0 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm STRHT<c> <Rt>, [<Rn>], +/-<Rm>
ARM_ cond 0 0 0 0 U 0 1 1 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm LDRHT<c> <Rt>, [<Rn>], +/-<Rm>
ARM_ cond 0 0 0 0 U 0 1 1 Rn Rt (0) (0) (0) (0) 1 1 0 1 Rm LDRSBT<c> <Rt>, [<Rn>], +/-<Rm>
ARM_ cond 0 0 0 0 U 0 1 1 Rn Rt (0) (0) (0) (0) 1 1 1 1 Rm LDRSHT<c> <Rt>, [<Rn>], +/-<Rm>
ARMS cond 0 0 0 0 0 1 0 S Rn Rd imm5 type 0 Rm SUB{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 0 0 1 0 0 RdHi RdLo Rm 1 0 0 1 Rn UMAAL<c> <RdLo>, <RdHi>, <Rn>, <Rm>
ARM_ cond 0 0 0 0 U 1 0 0 Rn Rt imm4H 1 0 1 1 imm4L STRH<c> <Rt>, [<Rn>], #+/-<imm8>
ARM_ cond 0 0 0 0 U 1 0 0 Rn Rt imm4H 1 1 0 1 imm4L LDRD<c> <Rt>, <Rt2>, [<Rn>], #+/-<imm8>
ARM_ cond 0 0 0 0 U 1 0 0 Rn Rt imm4H 1 1 1 1 imm4L STRD<c> <Rt>, <Rt2>, [<Rn>], #+/-<imm8>
ARM_ cond 0 0 0 0 U 1 0 1 Rn Rt imm4H 1 0 1 1 imm4L LDRH<c> <Rt>, [<Rn>], #+/-<imm8>
ARM_ cond 0 0 0 0 U 1 0 1 Rn Rt imm4H 1 1 0 1 imm4L LDRSB<c> <Rt>, [<Rn>], #+/-<imm8>
ARM_ cond 0 0 0 0 U 1 0 1 Rn Rt imm4H 1 1 1 1 imm4L LDRSH<c> <Rt>, [<Rn>], #+/-<imm8>
ARMS cond 0 0 0 0 0 1 1 S Rn Rd imm5 type 0 Rm RSB{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 0 0 1 1 0 Rd Ra Rm 1 0 0 1 Rn MLS<c> <Rd>, <Rn>, <Rm>, <Ra>
ARM_ cond 0 0 0 0 U 1 1 0 Rn Rt imm4H 1 0 1 1 imm4L STRHT<c> <Rt>, [<Rn>], #+/-<imm8>
ARM_ cond 0 0 0 0 U 1 1 1 Rn Rt imm4H 1 0 1 1 imm4L LDRHT<c> <Rt>, [<Rn>], #+/-<imm8>
ARM_ cond 0 0 0 0 U 1 1 1 Rn Rt imm4H 1 1 0 1 imm4L LDRSBT<c> <Rt>, [<Rn>], #+/-<imm8>
ARM_ cond 0 0 0 0 U 1 1 1 Rn Rt imm4H 1 1 1 1 imm4L LDRSHT<c> <Rt>, [<Rn>], #+/-<imm8>
ARMS cond 0 0 0 0 1 0 0 S Rn Rd imm5 type 0 Rm ADD{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 0 1 0 0 S RdHi RdLo Rm 1 0 0 1 Rn UMULL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
ARMS cond 0 0 0 0 1 0 1 S Rn Rd imm5 type 0 Rm ADC{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 0 1 0 1 S RdHi RdLo Rm 1 0 0 1 Rn UMLAL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
ARMS cond 0 0 0 0 1 1 0 S Rn Rd imm5 type 0 Rm SBC{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 0 1 1 0 S RdHi RdLo Rm 1 0 0 1 Rn SMULL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
ARMS cond 0 0 0 0 1 1 1 S Rn Rd imm5 type 0 Rm RSC{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 0 1 1 1 S RdHi RdLo Rm 1 0 0 1 Rn SMLAL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
ARM_ cond 0 0 0 1 0 0 0 0 Rd Ra Rm 1 0 0 0 Rn SMLABB<c> <Rd>, <Rn>, <Rm>, <Ra>
ARM_ cond 0 0 0 1 0 0 0 0 Rd Ra Rm 1 0 1 0 Rn SMLATB<c> <Rd>, <Rn>, <Rm>, <Ra>
ARM_ cond 0 0 0 1 0 0 0 0 Rd Ra Rm 1 1 0 0 Rn SMLABT<c> <Rd>, <Rn>, <Rm>, <Ra>
ARM_ cond 0 0 0 1 0 0 0 0 Rd Ra Rm 1 1 1 0 Rn SMLATT<c> <Rd>, <Rn>, <Rm>, <Ra>
ARM_ cond 0 0 0 1 0 0 0 0 Rn Rt (0) (0) (0) (0) 1 0 0 1 Rm SWP<c> <Rt>, <Rm>, [<Rn>]
ARM_ cond 0 0 0 1 U 0 W 0 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm STRH<c> <Rt>, [<Rn>, +/-<Rm>]{!}
ARM_ cond 0 0 0 1 U 0 W 0 Rn Rt (0) (0) (0) (0) 1 1 0 1 Rm LDRD<c> <Rt>, <Rt2>, [<Rn>, +/-<Rm>]{!}
ARM_ cond 0 0 0 1 U 0 W 0 Rn Rt (0) (0) (0) (0) 1 1 1 1 Rm STRD<c> <Rt>, <Rt2>, [<Rn>, +/-<Rm>]{!}
ARMS cond 0 0 0 1 0 0 0 1 Rn (0) (0) (0) (0) imm5 type 0 Rm TST<c> <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 1 U 0 W 1 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm LDRH<c> <Rt>, [<Rn>, +/-<Rm>]{!}
ARM_ cond 0 0 0 1 U 0 W 1 Rn Rt (0) (0) (0) (0) 1 1 0 1 Rm LDRSB<c> <Rt>, [<Rn>, +/-<Rm>]{!}
ARM_ cond 0 0 0 1 U 0 W 1 Rn Rt (0) (0) (0) (0) 1 1 1 1 Rm LDRSH<c> <Rt>, [<Rn>, +/-<Rm>]{!}
ARM_ cond 0 0 0 1 0 0 1 0 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) 0 0 0 1 Rm BX<c> <Rm>
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 0 Rm BXJ<c> <Rm>
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 1 Rm BLX<c> <Rm>
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 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>]{!}
ARMS cond 0 0 0 1 0 1 0 1 Rn (0) (0) (0) (0) imm5 type 0 Rm CMP<c> <Rn>, <Rm>{, <shift>}
ARMS cond 0 0 0 1 0 1 1 1 Rn (0) (0) (0) (0) imm5 type 0 Rm CMN<c> <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 1 U 1 W 1 Rn Rt imm4H 1 0 1 1 imm4L LDRH<c> <Rt>, [<Rn>, #+/-<imm8>]{!}
ARM_ cond 0 0 0 1 U 1 W 1 Rn Rt imm4H 1 1 0 1 imm4L LDRSB<c> <Rt>, [<Rn>, #+/-<imm8>]{!}
ARM_ cond 0 0 0 1 U 1 W 1 Rn Rt imm4H 1 1 1 1 imm4L LDRSH<c> <Rt>, [<Rn>, #+/-<imm8>]{!}
ARMS cond 0 0 0 1 1 0 0 S Rn Rd imm5 type 0 Rm ORR{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 1 1 0 0 0 Rn Rd (1) (1) (1) (1) 1 0 0 1 Rt STREX<c> <Rd>, <Rt>, [<Rn>]
ARM_ cond 0 0 0 1 1 0 0 1 Rn Rt (1) (1) (1) (1) 1 0 0 1 (1) (1) (1) (1) LDREX<c> <Rt>, [<Rn>]
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd 0 0 0 0 0 0 0 0 Rm MOV{S}<c> <Rd>, <Rm>
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd imm5 0 0 0 Rm LSL{S}<c> <Rd>, <Rm>, #<imm>
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd Rm 0 0 0 1 Rn LSL{S}<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd imm5 0 1 0 Rm LSR{S}<c> <Rd>, <Rm>, #<imm>
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd Rm 0 0 1 1 Rn LSR{S}<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd imm5 1 0 0 Rm ASR{S}<c> <Rd>, <Rm>, #<imm>
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd Rm 0 1 0 1 Rn ASR{S}<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd 0 0 0 0 0 1 1 0 Rm RRX{S}<c> <Rd>, <Rm>
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd imm5 1 1 0 Rm ROR{S}<c> <Rd>, <Rm>, #<imm>
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd Rm 0 1 1 1 Rn ROR{S}<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 0 0 1 1 0 1 0 Rn Rd (1) (1) (1) (1) 1 0 0 1 Rt STREXD<c> <Rd>, <Rt>, <Rt2>, [<Rn>]
ARM_ cond 0 0 0 1 1 0 1 1 Rn Rt (1) (1) (1) (1) 1 0 0 1 (1) (1) (1) (1) LDREXD<c> <Rt>, <Rt2>, [<Rn>]
ARMS cond 0 0 0 1 1 1 0 S Rn Rd imm5 type 0 Rm BIC{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 1 1 1 0 0 Rn Rd (1) (1) (1) (1) 1 0 0 1 Rt STREXB<c> <Rd>, <Rt>, [<Rn>]
ARM_ cond 0 0 0 1 1 1 0 1 Rn Rt (1) (1) (1) (1) 1 0 0 1 (1) (1) (1) (1) LDREXB<c> <Rt>, [<Rn>]
ARMS cond 0 0 0 1 1 1 1 S (0) (0) (0) (0) Rd imm5 type 0 Rm MVN{S}<c> <Rd>, <Rm>{, <shift>}
ARM_ cond 0 0 0 1 1 1 1 0 Rn Rd (1) (1) (1) (1) 1 0 0 1 Rt STREXH<c> <Rd>, <Rt>, [<Rn>]
ARM_ cond 0 0 0 1 1 1 1 1 Rn Rt (1) (1) (1) (1) 1 0 0 1 (1) (1) (1) (1) LDREXH<c> <Rt>, [<Rn>]
ARM_ cond 0 0 1 0 0 0 0 S Rn Rd imm12 AND{S}<c> <Rd>, <Rn>, #<const>
ARM_ cond 0 0 1 0 0 0 1 S Rn Rd imm12 EOR{S}<c> <Rd>, <Rn>, #<const>
ARM_ cond 0 0 1 0 0 1 0 S Rn Rd imm12 SUB{S}<c> <Rd>, <Rn>, #<const>
ARM_ cond 0 0 1 0 0 1 1 S Rn Rd imm12 RSB{S}<c> <Rd>, <Rn>, #<const>
ARM_ cond 0 0 1 0 1 0 0 S Rn Rd imm12 ADD{S}<c> <Rd>, <Rn>, #<const>
ARM_ cond 0 0 1 0 1 0 1 S Rn Rd imm12 ADC{S}<c> <Rd>, <Rn>, #<const>
ARM_ cond 0 0 1 0 1 1 0 S Rn Rd imm12 SBC{S}<c> <Rd>, <Rn>, #<const>
ARM_ cond 0 0 1 0 1 1 1 S Rn Rd imm12 RSC{S}<c> <Rd>, <Rn>, #<const>
ARM_ cond 0 0 1 1 0 0 0 0 imm4 Rd imm12 MOVW<c> <Rd>, #<imm16>
ARM_ cond 0 0 1 1 0 0 0 1 Rn (0) (0) (0) (0) imm12 TST<c> <Rn>, #<const>
ARM_ cond 0 0 1 1 0 0 1 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 0 0 0 0 0 NOP<c>
ARM_ cond 0 0 1 1 0 0 1 1 Rn (0) (0) (0) (0) imm12 TEQ<c> <Rn>, #<const>
ARM_ cond 0 0 1 1 0 1 0 0 imm4 Rd imm12 MOVT<c> <Rd>, #<imm16>
ARM_ cond 0 0 1 1 0 1 0 1 Rn (0) (0) (0) (0) imm12 CMP<c> <Rn>, #<const>
ARM_ cond 0 0 1 1 0 1 1 1 Rn (0) (0) (0) (0) imm12 CMN<c> <Rn>, #<const>
ARM_ cond 0 0 1 1 1 0 0 S Rn Rd imm12 ORR{S}<c> <Rd>, <Rn>, #<const>
ARM_ cond 0 0 1 1 1 0 1 S (0) (0) (0) (0) Rd imm12 MOV{S}<c> <Rd>, #<const>
ARM_ cond 0 0 1 1 1 1 0 S Rn Rd imm12 BIC{S}<c> <Rd>, <Rn>, #<const>
ARM_ cond 0 0 1 1 1 1 1 S (0) (0) (0) (0) Rd imm12 MVN{S}<c> <Rd>, #<const>
ARM_ cond 0 1 0 0 1 0 0 1 1 1 0 1 Rt 0 0 0 0 0 0 0 0 0 1 0 0 POP<c> {<Rt>}
ARM_ cond 0 1 0 0 U 0 0 0 Rn Rt imm12 STR<c> <Rt>, [<Rn>], #+/-<imm12>
ARM_ cond 0 1 0 0 U 0 0 1 Rn Rt imm12 LDR<c> <Rt>, [<Rn>], #+/-<imm12>
ARM_ cond 0 1 0 0 U 0 1 0 Rn Rt imm12 STRT<c> <Rt>, [<Rn>], #+/-<imm12>
ARM_ cond 0 1 0 0 U 0 1 1 Rn Rt imm12 LDRT<c> <Rt>, [<Rn>], #+/-<imm12>
ARM_ cond 0 1 0 0 U 1 0 0 Rn Rt imm12 STRB<c> <Rt>, [<Rn>], #+/-<imm12>
ARM_ cond 0 1 0 0 U 1 0 1 Rn Rt imm12 LDRB<c> <Rt>, [<Rn>], #+/-<imm12>
ARM_ cond 0 1 0 0 U 1 1 0 Rn Rt imm12 STRBT<c> <Rt>, [<Rn>], #+/-<imm12>
ARM_ cond 0 1 0 0 U 1 1 1 Rn Rt imm12 LDRBT<c> <Rt>, [<Rn>], #+/-<imm12>
ARM_ cond 0 1 0 1 0 0 1 0 1 1 0 1 Rt 0 0 0 0 0 0 0 0 0 1 0 0 PUSH<c> {<Rt>}
ARM_ cond 0 1 0 1 U 0 W 0 Rn Rt imm12 STR<c> <Rt>, [<Rn>, #+/-<imm12>]{!}
ARM_ cond 0 1 0 1 U 0 W 1 Rn Rt imm12 LDR<c> <Rt>, [<Rn>, #+/-<imm12>]{!}
ARM_ cond 0 1 0 1 U 1 W 0 Rn Rt imm12 STRB<c> <Rt>, [<Rn>, #+/-<imm12>]{!}
ARM_ cond 0 1 0 1 U 1 W 1 Rn Rt imm12 LDRB<c> <Rt>, [<Rn>, #+/-<imm12>]{!}
ARM_ cond 0 1 1 0 0 0 0 1 Rn Rd (1) (1) (1) (1) 0 1 0 1 Rm SSAX<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 1 1 0 0 0 0 1 Rn Rd (1) (1) (1) (1) 0 1 1 1 Rm SSUB16<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 1 1 0 0 0 0 1 Rn Rd (1) (1) (1) (1) 1 1 1 1 Rm SSUB8<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 1 1 0 0 1 0 1 Rn Rd (1) (1) (1) (1) 0 1 0 1 Rm USAX<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 1 1 0 0 1 0 1 Rn Rd (1) (1) (1) (1) 0 1 1 1 Rm USUB16<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 1 1 0 0 1 0 1 Rn Rd (1) (1) (1) (1) 1 1 1 1 Rm USUB8<c> <Rd>, <Rn>, <Rm>
ARMs cond 0 1 1 0 1 0 0 0 Rn Rd imm5 0 0 1 Rm PKHBT<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARMs cond 0 1 1 0 1 0 0 0 Rn Rd imm5 1 0 1 Rm PKHTB<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 1 1 0 1 0 0 0 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm SXTB16<c> <Rd>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 0 0 0 Rn Rd rotate (0) (0) 0 1 1 1 Rm SXTAB16<c> <Rd>, <Rn>, <Rm>{, <rotation>}
ARMs cond 0 1 1 0 1 0 1 sat_imm Rd imm5 sh 0 1 Rn SSAT<c> <Rd>, #<imm>, <Rn>{, <shift>}
ARM_ cond 0 1 1 0 1 0 1 0 sat_imm Rd (1) (1) (1) (1) 0 0 1 1 Rn SSAT16<c> <Rd>, #<imm>, <Rn>
ARM_ cond 0 1 1 0 1 0 1 0 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm SXTB<c> <Rd>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 0 1 0 Rn Rd rotate (0) (0) 0 1 1 1 Rm SXTAB<c> <Rd>, <Rn>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 0 1 1 (1) (1) (1) (1) Rd (1) (1) (1) (1) 0 0 1 1 Rm REV<c> <Rd>, <Rm>
ARM_ cond 0 1 1 0 1 0 1 1 (1) (1) (1) (1) Rd (1) (1) (1) (1) 1 0 1 1 Rm REV16<c> <Rd>, <Rm>
ARM_ cond 0 1 1 0 1 0 1 1 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm SXTH<c> <Rd>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 0 1 1 Rn Rd rotate (0) (0) 0 1 1 1 Rm SXTAH<c> <Rd>, <Rn>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 1 0 0 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm UXTB16<c> <Rd>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 1 0 0 Rn Rd rotate (0) (0) 0 1 1 1 Rm UXTAB16<c> <Rd>, <Rn>, <Rm>{, <rotation>}
ARMs cond 0 1 1 0 1 1 1 sat_imm Rd imm5 sh 0 1 Rn USAT<c> <Rd>, #<imm>, <Rn>{, <shift>}
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 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>}
ARMs cond 0 1 1 0 U 0 0 0 Rn Rt imm5 type 0 Rm STR<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
ARMs cond 0 1 1 0 U 0 0 1 Rn Rt imm5 type 0 Rm LDR<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
ARMs cond 0 1 1 0 U 0 1 0 Rn Rt imm5 type 0 Rm STRT<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
ARMs cond 0 1 1 0 U 0 1 1 Rn Rt imm5 type 0 Rm LDRT<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
ARMs cond 0 1 1 0 U 1 0 0 Rn Rt imm5 type 0 Rm STRB<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
ARMs cond 0 1 1 0 U 1 0 1 Rn Rt imm5 type 0 Rm LDRB<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
ARMs cond 0 1 1 0 U 1 1 0 Rn Rt imm5 type 0 Rm STRBT<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
ARMs cond 0 1 1 0 U 1 1 1 Rn Rt imm5 type 0 Rm LDRBT<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
ARMs cond 0 1 1 1 U 0 W 0 Rn Rt imm5 type 0 Rm STR<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
ARMs cond 0 1 1 1 U 0 W 1 Rn Rt imm5 type 0 Rm LDR<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
ARMs cond 0 1 1 1 U 1 W 0 Rn Rt imm5 type 0 Rm STRB<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
ARMs cond 0 1 1 1 U 1 W 1 Rn Rt imm5 type 0 Rm LDRB<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
ARM_ cond 0 1 1 1 1 0 0 0 Rd 1 1 1 1 Rm 0 0 0 1 Rn USAD8<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 1 1 1 1 0 0 0 Rd Ra Rm 0 0 0 1 Rn USADA8<c> <Rd>, <Rn>, <Rm>, <Ra>
ARM_ cond 0 1 1 1 1 1 0 msb Rd lsb 0 0 1 1 1 1 1 BFC<c> <Rd>, #<lsb>, #<width>
ARM_ cond 0 1 1 1 1 1 0 msb Rd lsb 0 0 1 Rn BFI<c> <Rd>, <Rn>, #<lsb>, #<width>
ARM_ cond 0 1 1 1 1 1 1 widthm1 Rd lsb 1 0 1 Rn UBFX<c> <Rd>, <Rn>, #<lsb>, #<width>
ARM_ cond 1 0 0 0 0 0 W 0 Rn/=1101 register_list STMED<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 0 0 0 W 0 Rn register_list STMDA<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 0 0 0 W 1 Rn/=1101 register_list LDMED<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 0 0 0 W 1 Rn register_list LDMDA<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 0 1 0 W 0 Rn/=1101 register_list STMEA<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 0 1 0 W 0 Rn register_list STM<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 0 1 0 0 1 Rn/=1101 register_list LDMEA<c> <Rn>, <registers>
ARM_ cond 1 0 0 0 1 0 1 1 1 1 0 1 register_list @ = const char* op @@ (reglist != 0) && ((reglist & (reglist - 1)) == 0)@ op,"POP","LDMEA"@ @ \op\<c> <registers>
ARM_ cond 1 0 0 0 1 0 W 1 Rn register_list LDM<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 1 0 0 0 0 Rn/=1101 register_list STMFD<c> <Rn>, <registers>
ARM_ cond 1 0 0 1 0 0 1 0 1 1 0 1 register_list @ = const char* op @@ (reglist != 0) && ((reglist & (reglist - 1)) == 0)@ op,"PUSH","STMFD"@ @ \op\<c> <registers>
ARM_ cond 1 0 0 1 0 0 W 0 Rn register_list STMDB<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 1 0 0 W 1 Rn/=1101 register_list LDMFD<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 1 0 0 W 1 Rn register_list LDMDB<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 1 1 0 W 0 Rn/=1101 register_list STMFA<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 1 1 0 W 0 Rn register_list STMIB<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 1 1 0 W 1 Rn/=1101 register_list LDMFA<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 1 1 0 W 1 Rn register_list LDMIB<c> <Rn>{!}, <registers>
ARM_ cond 1 0 1 0 imm24 B<c> <label>
ARM_ cond 1 0 1 1 imm24 BL<c> <label>
VFPU cond 1 1 0 0 0 1 0 0 Rn Rt 1 0 1 0 0 0 M 1 Vm VMOV<c> <Sm>, <Sm1>, <Rt>, <Rn>
VFPU cond 1 1 0 0 0 1 0 1 Rn Rt 1 0 1 0 0 0 M 1 Vm VMOV<c> <Rt>, <Rn>, <Sm>, <Sm1>
VFPU cond 1 1 0 0 0 1 0 0 Rn Rt 1 0 1 1 0 0 M 1 Vm VMOV<c> <Dm>, <Rt>, <Rn>
VFPU cond 1 1 0 0 0 1 0 1 Rn Rt 1 0 1 1 0 0 M 1 Vm VMOV<c> <Rt>, <Rn>, <Dm>
;INVALIDATE <4> 1 1 0 0 0 1 0 <9> 1 0 1 <9>
INVALIDATE <4> 1 1 0 0 0 <11> 1 0 1 <9>
INVALIDATE <4> 1 1 0 0 0 <11> 1 0 1 <9>
INVALIDATE <4> 1 1 0 1 1 <1> 1 <9> 1 0 1 <9>
INVALIDATE <4> 1 1 0 1 1 <1> 1 <9> 1 0 1 <9>
VFPU cond 1 1 0 1 0 D 1 0 1 1 0 1 Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FSTMX<c> <LIst>
VFPU cond 1 1 0 1 0 D 1 0 1 1 0 1 Vd 1 0 1 sz imm8 VPUSH<c> <list>
VFPU cond 1 1 0 1 U D 0 0 Rn Vd 1 0 1 sz imm8 VSTR<c> <Dd>, [<Rn>{, #+/-<imm>}]
VFPU cond 1 1 0 @<2> D W 0 Rn Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FSTM\(param == 0b01 ? "IA" : "DB")\X<c> <Rn>{!}, <LIst>
VFPU cond 1 1 0 @<2> D W 0 Rn Vd 1 0 1 sz imm8 VSTM\(param == 0b01 ? "IA" : "DB")\<c> <Rn>{!}, <list>
VFPU cond 1 1 0 0 1 D 1 1 1 1 0 1 Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FLDMX<c> <LIst>
VFPU cond 1 1 0 0 1 D 1 1 1 1 0 1 Vd 1 0 1 sz imm8 VPOP<c> <list>
VFPU cond 1 1 0 1 0 D 0 1 1 1 1 1 Vd 1 0 1 sz 0 0 0 0 0 0 0 0 VLDR<c> <Dd>, [PC, #-0]
VFPU cond 1 1 0 1 U D 0 1 1 1 1 1 Vd 1 0 1 sz imm8 VLDR<c> <Dd>, <label>
VFPU cond 1 1 0 1 U D 0 1 Rn Vd 1 0 1 sz imm8 VLDR<c> <Dd>, [<Rn>{, #+/-<imm>}]
VFPU cond 1 1 0 @<2> D W 1 Rn Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FLDM\(param == 0b01 ? "IA" : "DB")\X<c> <Rn>{!}, <LIst>
VFPU cond 1 1 0 @<2> D W 1 Rn Vd 1 0 1 sz imm8 VLDM\(param == 0b01 ? "IA" : "DB")\<c> <Rn>{!}, <list>
INVALIDATE <4> 1 1 0 <25>
INVALIDATE <4> 1 1 1 0 0 0 <1> 0 <8> 1 0 1 1 <1> 1 0 1 (0) (0) (0) (0)
;INVALIDATE <4> 1 1 1 0 1 <2> 0 <8> 1 0 1 1 <1> 0 <1> 1 (0) (0) (0) (0)
VFPU cond 1 1 1 0 0 0 0 0 Vn Rt 1 0 1 0 N (0) (0) 1 (0) (0) (0) (0) VMOV<c> <Sn>, <Rt>
VFPU cond 1 1 1 0 1 1 1 0 0 0 0 1 Rt 1 0 1 0 (0) (0) (0) 1 (0) (0) (0) (0) VMSR<c> FPSCR, <Rt>
VFPU cond 1 1 1 0 0 @<2> 0 Vd Rt 1 0 1 1 D @<2> 1 (0) (0) (0) (0) @ set uint8_t opc = (param1_2 << 2) + param2_2@ = uint8_t shift @@ (opc & 0b1000) == 0b1000@ @@ (opc & 0b1001) == 0b0001@ @@ (opc & 0b1011) == 0b0000@ shift,0,1,2,0xFF@ set uint8_t decodedImm = (opc & 0x7) >> shift@ @ VMOV<c>.\%d8 &l&l shift\ <Dd[x]>, <Rt>
VFPU cond 1 1 1 0 1 0 Q 0 Vd Rt 1 0 1 1 D 0 0 1 (0) (0) (0) (0) VDUP<c>.32 <Qd>, <Rt>
VFPU cond 1 1 1 0 1 0 Q 0 Vd Rt 1 0 1 1 D 0 1 1 (0) (0) (0) (0) VDUP<c>.16 <Qd>, <Rt>
VFPU cond 1 1 1 0 1 1 Q 0 Vd Rt 1 0 1 1 D 0 0 1 (0) (0) (0) (0) VDUP<c>.8 <Qd>, <Rt>
VFPU cond 1 1 1 0 0 0 0 1 Vn Rt 1 0 1 0 N (0) (0) 1 (0) (0) (0) (0) VMOV<c> <Rt>, <Sn>
VFPU cond 1 1 1 0 1 1 1 1 0 0 0 1 Rt 1 0 1 0 (0) (0) (0) 1 (0) (0) (0) (0) VMRS<c> <Rt>, FPSCR
VFPU cond 1 1 1 0 U @<2> 1 Vn Rt 1 0 1 1 N @<2> 1 (0) (0) (0) (0) @ set uint8_t opc = (u << 3) + (param1_2 << 2) + param2_2@ = uint8_t shift, size @@ (opc & 0b01000) == 0b01000@ @@ (opc & 0b01001) == 0b00001@ @@ (opc & 0b11011) == 0b00000@ shift,0,1,2,0xFF;size,0,1,2,4@ set uint8_t decodedImm = (opc & 0x7) >> shift@ @ VMOV<c>.<dt> <Rt>, <Dn[x]>
INVALIDATE <4> 1 1 1 0 <12> 1 0 1 <4> 1 <4>
VFPU cond 1 1 1 0 0 D 0 0 Vn Vd 1 0 1 sz N op M 0 Vm VML\(op ? "S" : "A")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
VFPU cond 1 1 1 0 0 D 0 1 Vn Vd 1 0 1 sz N op M 0 Vm VNML\(op ? "S" : "A")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
VFPU cond 1 1 1 0 0 D 1 0 Vn Vd 1 0 1 sz N 0 M 0 Vm VMUL<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
VFPU cond 1 1 1 0 0 D 1 0 Vn Vd 1 0 1 sz N 1 M 0 Vm VNMUL<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
VFPU cond 1 1 1 0 0 D 1 1 Vn Vd 1 0 1 sz N 0 M 0 Vm VADD<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
VFPU cond 1 1 1 0 0 D 1 1 Vn Vd 1 0 1 sz N 1 M 0 Vm VSUB<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
VFPU cond 1 1 1 0 1 D 0 0 Vn Vd 1 0 1 sz N 0 M 0 Vm VDIV<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
VFPU cond 1 1 1 0 1 D 0 1 Vn Vd 1 0 1 sz N op M 0 Vm VFNM\(op ? "A" : "S")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
VFPU cond 1 1 1 0 1 D 1 0 Vn Vd 1 0 1 sz N op M 0 Vm VFM\(op ? "S" : "A")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
!/VFPU cond 1 1 1 0 1 x 1 1 opc2 <4> 1 0 1 <1> - - <1> 0 opc4 Table A7-17
VFPU cond 1 1 1 0 1 D 1 1 @<4> Vd 1 0 1 0 (0) 0 (0) 0 @<4> @ set int8_t sign = (param1_4 >> 3) ? -1 : 1@ set uint8_t exp = ((param1_4 & 0b111) ^ 0b100)@ set float mantissa = 16 + param2_4@ set float imm = sign * (1 << exp) * mantissa / 128.@ @ VMOV<c>.F32 <Sd>, #\%fimm\
VFPU cond 1 1 1 0 1 D 1 1 @<4> Vd 1 0 1 1 (0) 0 (0) 0 @<4> @ set int8_t sign = (param1_4 >> 3) ? -1 : 1@ set uint8_t exp = ((param1_4 & 0b111) ^ 0b100)@ set double mantissa = 16 + param2_4@ set double imm = sign * (1 << exp) * mantissa / 128.@ @ VMOV<c>.F64 <Dd>, #\%fimm\
VFPU cond 1 1 1 0 1 D 1 1 0 0 0 0 Vd 1 0 1 sz 0 1 M 0 Vm VMOV<c>.F\(size ? "64" : "32")\ <Dd>, <Dm>
VFPU cond 1 1 1 0 1 D 1 1 0 0 0 0 Vd 1 0 1 sz 1 1 M 0 Vm VABS<c>.F\(size ? "64" : "32")\ <Dd>, <Dm>
VFPU cond 1 1 1 0 1 D 1 1 0 0 0 1 Vd 1 0 1 sz 0 1 M 0 Vm VNEG<c>.F\(size ? "64" : "32")\ <Dd>, <Dm>
VFPU cond 1 1 1 0 1 D 1 1 0 0 0 1 Vd 1 0 1 sz 1 1 M 0 Vm VSQRT<c>.F\(size ? "64" : "32")\ <Dd>, <Dm>
VFPU cond 1 1 1 0 1 D 1 1 0 0 1 0 Vd 1 0 1 (0) @<1> 1 M 0 Vm VCVT\(param ? "T" : "B")\<c>.F32.F16 <Sd>, <Sm>
VFPU cond 1 1 1 0 1 D 1 1 0 0 1 1 Vd 1 0 1 (0) @<1> 1 M 0 Vm VCVT\(param ? "T" : "B")\<c>.F16.F32 <Sd>, <Sm>
VFPU cond 1 1 1 0 1 D 1 1 0 1 0 0 Vd 1 0 1 sz op 1 M 0 Vm VCMP\(op ? "E" : "")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dm>
VFPU cond 1 1 1 0 1 D 1 1 0 1 0 1 Vd 1 0 1 sz op 1 (0) 0 (0) (0) (0) (0) VCMP\(op ? "E" : "")\<c>.F\(size ? "64" : "32")\ <Dd>, #0.0
VFPU cond 1 1 1 0 1 D 1 1 0 1 1 1 Vd 1 0 1 0 1 1 M 0 Vm VCVT<c>.F64.F32 <Dd>, <Sm>
VFPU cond 1 1 1 0 1 D 1 1 0 1 1 1 Vd 1 0 1 1 1 1 M 0 Vm VCVT<c>.F32.F64 <Sd>, <Dm>
VFPU cond 1 1 1 0 1 D 1 1 1 0 0 0 Vd 1 0 1 sz op 1 M 0 Vm VCVT<c>.F\(size ? "64" : "32")\.\(op ? "S" : "U")\32 <Dd>, <Sm>
VFPU cond 1 1 1 0 1 D 1 1 1 0 1 U Vd 1 0 1 sz op 1 i 0 imm4 @ set uint8_t td = (u << 2) + op + 1@ td=0b001=0b010=0b101 const char* Td Td,"S16","U16","S32","U32"@ set imm5 = (16 << op) - (imm5 >> 4) - ((imm5 & 0xF) << 1)@ @ VCVT<c>.F\(size ? "64" : "32")\.\Td\ <Dd>, <Dd>, #<imm>
VFPU cond 1 1 1 0 1 D 1 1 1 1 0 U Vd 1 0 1 sz op 1 M 0 Vm VCVT\(op ? "" : "R")\<c>.\(u ? "U" : "S")\32.F\(size ? "64" : "32")\ <Sd>, <Dm>
VFPU cond 1 1 1 0 1 D 1 1 1 1 1 U Vd 1 0 1 sz op 1 i 0 imm4 @ set uint8_t td = (u << 2) + op + 1@ td=0b001=0b010=0b101 const char* Td Td,"S16","U16","S32","U32"@ set imm5 = (16 << op) - (imm5 >> 4) - ((imm5 & 0xF) << 1)@ @ VCVT<c>.\Td\.F\(size ? "64" : "32")\ <Dd>, <Dd>, #<imm>
;INVALIDATE <4> 1 1 1 0 1 <1> 1 1 <8> 1 0 1 <4> 0 <4>
;INVALIDATE <4> 1 1 1 0 <12> 1 0 1 <4> 0 <4>
; ============= END OF REGISTERED INSTRUCTIONS ============
INVALIDATE <32>
+1
View File
@@ -11,6 +11,7 @@
.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}
Executable → Regular
+5047 -886
View File
File diff suppressed because it is too large. Load diff
+474 -66
View File
@@ -3,7 +3,6 @@
#include <pthread.h>
#include <errno.h>
#include "debug.h"
#include "box86context.h"
#include "dynarec.h"
@@ -17,6 +16,7 @@
#include "x86trace.h"
#include "dynablock.h"
#include "dynablock_private.h"
#include "dynarec_private.h"
#include "elfloader.h"
#ifdef ARM
#include "dynarec_arm.h"
@@ -28,34 +28,124 @@
KHASH_MAP_INIT_INT(dynablocks, dynablock_t*)
KHASH_SET_INIT_INT(mark)
dynablocklist_t* NewDynablockList(uintptr_t base, uintptr_t text, int textsz)
uint32_t X31_hash_code(void* addr, int len)
{
if(!len) return 0;
uint8_t* p = (uint8_t*)addr;
int32_t h = *p;
for (--len, ++p; len; --len, ++p) h = (h << 5) - h + (int32_t)*p;
return (uint32_t)h;
}
dynablocklist_t* NewDynablockList(uintptr_t base, uintptr_t text, int textsz, int nolinker, int direct)
{
dynablocklist_t* ret = (dynablocklist_t*)calloc(1, sizeof(dynablocklist_t));
ret->blocks = kh_init(dynablocks);
ret->blocks = (nolinker && direct)?NULL:kh_init(dynablocks);
ret->base = base;
ret->text = text;
ret->textsz = textsz;
ret->nolinker = nolinker;
pthread_rwlock_init(&ret->rwlock_blocks, NULL);
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);}
}
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, %swith %d son(s)\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size, db->father, db->tablesz, db->marks?"with marks, ":"", db->sons_size);
db->done = 0;
// remove from direct if there
uintptr_t startdb = db->parent->text;
uintptr_t enddb = db->parent->text + db->parent->textsz;
if(db->parent->direct) {
uintptr_t addr = (uintptr_t)db->x86_addr;
if(addr>=startdb && addr<enddb)
db->parent->direct[addr-startdb] = NULL;
}
// remove from hash if there
if (db->parent->blocks) {
khint_t kdb;
kdb = kh_get(dynablocks, db->parent->blocks, (uintptr_t) db->x86_addr - db->parent->base);
if(kdb!=kh_end(db->parent->blocks))
kh_del(dynablocks, db->parent->blocks, kdb);
}
if(db->marks) {
// Follow mark and set arm_linker instead
khint_t k;
kh_foreach_key(db->marks, k,
void** p = (void**)(uintptr_t)k;
dynarec_log(LOG_DEBUG, " -- resettable(%p)\n", p);
resettable(p);
);
// free mark
kh_destroy(mark, db->marks);
db->marks = NULL;
}
for(int i=0; i<db->tablesz; i+=4) {
dynablock_t* p = (dynablock_t*)db->table[i+3];
dynarec_log(LOG_DEBUG, " -- table[%d+3] = %p ", i, p);
if(p && p!=db && p->marks) {
khint_t kd = kh_get(mark, p->marks, (uintptr_t)(&db->table[i+0]));
if(kd!=kh_end(p->marks)) {
kh_del(mark, p->marks, kd);
dynarec_log(LOG_DEBUG, "cleaned");
}
else {dynarec_log(LOG_DEBUG, "not found");}
}
dynarec_log(LOG_DEBUG, "\n");
}
// remove and free the sons
for (int i=0; i<db->sons_size; ++i) {
dynablock_t *son = db->sons[i];
db->sons[i] = NULL;
FreeDynablock(son);
}
// only the father free the DynarecMap
if(!db->father) {
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->block, db->size);
FreeDynarecMap((uintptr_t)db->block, db->size);
}
free(db->sons);
free(db->table);
free(db);
}
}
void FreeDynablockList(dynablocklist_t** dynablocks)
{
if(!dynablocks)
return;
if(!*dynablocks)
return;
dynarec_log(LOG_INFO, "Free %d Blocks from Dynablocklist (with %d buckets)%s\n", kh_size((*dynablocks)->blocks), kh_n_buckets((*dynablocks)->blocks), ((*dynablocks)->direct)?" With Direct mapping enabled":"");
dynarec_log(LOG_INFO, "Free %d Blocks from Dynablocklist (with %d buckets, nolinker=%d) %s\n", (*dynablocks)->blocks?kh_size((*dynablocks)->blocks):0, (*dynablocks)->blocks?kh_n_buckets((*dynablocks)->blocks):0, (*dynablocks)->nolinker, ((*dynablocks)->direct)?" With Direct mapping enabled":"");
dynablock_t* db;
kh_foreach_value((*dynablocks)->blocks, db,
free(db->table);
free(db);
);
kh_destroy(dynablocks, (*dynablocks)->blocks);
if((*dynablocks)->direct)
if((*dynablocks)->blocks) {
// create a list of the parent db to delete (because there are sons in the middle that will be invalid if father is removed)
dynablock_t** list = (dynablock_t**)calloc(kh_size((*dynablocks)->blocks), sizeof(dynablock_t*));
int n = 0;
kh_foreach_value((*dynablocks)->blocks, db,
if(!db->father) list[n++] = db;
);
for (int i=0; i<n; ++i)
FreeDynablock(list[i]);
kh_destroy(dynablocks, (*dynablocks)->blocks);
(*dynablocks)->blocks = NULL;
free(list);
}
if((*dynablocks)->direct) {
for (int i=0; i<(*dynablocks)->textsz; ++i) {
if((*dynablocks)->direct[i] && !(*dynablocks)->direct[i]->father)
FreeDynablock((*dynablocks)->direct[i]);
}
free((*dynablocks)->direct);
}
(*dynablocks)->direct = 0;
pthread_rwlock_destroy(&(*dynablocks)->rwlock_blocks);
@@ -64,9 +154,260 @@ void FreeDynablockList(dynablocklist_t** dynablocks)
*dynablocks = NULL;
}
void MarkDynablock(dynablock_t* db)
{
if(db) {
if(db->father)
db = db->father; // mark only father
if(db->marks && !db->need_test) {
// Follow mark and set arm_linker instead
khint_t k;
kh_foreach_key(db->marks, k,
void** p = (void**)(uintptr_t)k;
resettable(p);
);
// free mark
kh_clear(mark, db->marks);
}
db->need_test = 1;
}
}
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 RemoveMark(void** table)
{
// remove old value if any
dynablock_t *old = (dynablock_t*)table[3];
if(old && old->father)
old = old->father;
if(old && old->marks) {
khint_t kd = kh_get(mark, old->marks, (uintptr_t)table);
if(kd!=kh_end(old->marks))
kh_del(mark, old->marks, kd);
}
table[3] = NULL;
}
// source is linked to dest (i.e. source->table[x] = dest->block), so add a "mark" in dest, add a "linked" info to source
void AddMark(dynablock_t* source, dynablock_t* dest, void** table)
{
int ret;
// remove old value if any
dynablock_t *old = (dynablock_t*)table[3];
if(old && old->father)
old = old->father;
if(old && old->marks) {
khint_t kd = kh_get(mark, old->marks, (uintptr_t)table);
if(kd!=kh_end(old->marks))
kh_del(mark, old->marks, kd);
}
// add mark if needed
if(dest->father)
dest = dest->father;
if(dest->marks) {
kh_put(mark, dest->marks, (uintptr_t)table, &ret);
table[3] = (void*)dest;
} else
table[3] = NULL;
}
void MarkDynablockList(dynablocklist_t** dynablocks)
{
if(!dynablocks)
return;
if(!*dynablocks)
return;
dynarec_log(LOG_DEBUG, "Marked %d Blocks from Dynablocklist (with %d buckets, nolinker=%d) %p:0x%x %s\n", (*dynablocks)->blocks?(kh_size((*dynablocks)->blocks)):0, (*dynablocks)->blocks?(kh_n_buckets((*dynablocks)->blocks)):0, (*dynablocks)->nolinker, (void*)(*dynablocks)->text, (*dynablocks)->textsz, ((*dynablocks)->direct)?" With Direct mapping enabled":"");
dynablock_t* db;
if((*dynablocks)->blocks) {
kh_foreach_value((*dynablocks)->blocks, db,
MarkDynablock(db);
);
}
if((*dynablocks)->direct) {
for (int i=0; i<(*dynablocks)->textsz; ++i) {
MarkDynablock((*dynablocks)->direct[i]);
}
}
}
void ProtectkDynablockList(dynablocklist_t** dynablocks)
{
if(!dynablocks)
return;
if(!*dynablocks)
return;
dynarec_log(LOG_DEBUG, "Protect %d Blocks from Dynablocklist (with %d buckets, nolinker=%d) %p:0x%x %s\n", (*dynablocks)->blocks?(kh_size((*dynablocks)->blocks)):0, (*dynablocks)->blocks?(kh_n_buckets((*dynablocks)->blocks)):0, (*dynablocks)->nolinker, (void*)(*dynablocks)->text, (*dynablocks)->textsz, ((*dynablocks)->direct)?" With Direct mapping enabled":"");
dynablock_t* db;
if((*dynablocks)->blocks) {
kh_foreach_value((*dynablocks)->blocks, db,
ProtectDynablock(db);
);
}
if((*dynablocks)->direct) {
for (int i=0; i<(*dynablocks)->textsz; ++i) {
ProtectDynablock((*dynablocks)->direct[i]);
}
}
}
uintptr_t StartDynablockList(dynablocklist_t* db)
{
if(db)
return db->text;
return 0;
}
uintptr_t EndDynablockList(dynablocklist_t* db)
{
if(db)
return db->text+db->textsz;
return 0;
}
void FreeDirectDynablock(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)
for(uintptr_t i = start; i<end; ++i)
if(dynablocks->direct[i-startdb]) {
FreeDynablock(dynablocks->direct[i-startdb]);
}
}
void MarkDirectDynablock(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)
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
}
void FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
{
if(!dynablocks)
return;
if(dynablocks->direct)
FreeDirectDynablock(dynablocks, addr, size);
if(dynablocks->blocks) {
dynablock_t* db;
uintptr_t s, e;
kh_foreach_value(dynablocks->blocks, db,
s = (uintptr_t)db->x86_addr;
e = (uintptr_t)db->x86_addr+db->x86_size-1;
if((s>=addr && s<(addr+size)) || (e>=addr && e<(addr+size)))
ProtectDynablock(db);
);
}
}
void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
{
if(!dynablocks)
return;
if(dynablocks->direct)
MarkDirectDynablock(dynablocks, addr, size);
if(dynablocks->blocks) {
dynablock_t* db;
uintptr_t s, e;
kh_foreach_value(dynablocks->blocks, db,
s = (uintptr_t)db->x86_addr;
e = (uintptr_t)db->x86_addr+db->x86_size-1;
if((s>=addr && s<(addr+size)) || (e>=addr && e<(addr+size)))
MarkDynablock(db);
);
}
}
dynablock_t* FindDynablockDynablocklist(void* addr, dynablocklist_t* dynablocks)
{
if(!dynablocks)
return NULL;
if(dynablocks->direct)
for(int i=0; i<dynablocks->textsz; ++i) {
if(dynablocks->direct[i]) {
dynablock_t* db = dynablocks->direct[i];
uintptr_t s = (uintptr_t)db->block;
uintptr_t e = (uintptr_t)db->block+db->size;
if(s>=(uintptr_t)addr && e<(uintptr_t)addr)
return db->father?db->father:db;
}
}
if(dynablocks->blocks) {
dynablock_t* db;
uintptr_t s, e;
kh_foreach_value(dynablocks->blocks, db,
s = (uintptr_t)db->block;
e = (uintptr_t)db->block+db->size;
if((uintptr_t)addr>=s && (uintptr_t)addr<e)
return db->father?db->father:db;
);
}
return NULL;
}
dynablock_t* FindDynablockFromNativeAddress(void* addr)
{
// unoptimized search through all dynablockslist for the dynablock that contains native addr (NULL if not found)
// search "volatile" dynarec first
dynablock_t *ret = NULL;
for(int idx=0; idx<65536 && !ret; ++idx)
if(my_context->dynmap[idx])
ret = FindDynablockDynablocklist(addr, my_context->dynmap[idx]->dynablocks);
if(ret)
return ret;
// search elfs
for(int idx=0; idx<my_context->elfsize && !ret; ++idx)
ret = FindDynablockDynablocklist(addr, GetDynablocksFromElf(my_context->elfs[idx]));
// last, search context dynablocks
if(my_context->dynablocks)
ret = FindDynablockDynablocklist(addr, my_context->dynablocks);
return ret;
}
void ConvertHash2Direct(dynablocklist_t* dynablocks)
{
if(dynablocks->textsz==0 || dynablocks->text==0)
if(dynablocks->textsz==0 || dynablocks->text==0 || !dynablocks->blocks)
return; // nothing to do
// create the new set
dynablock_t **direct = (dynablock_t**)calloc(dynablocks->textsz, sizeof(dynablock_t*));
@@ -76,13 +417,14 @@ void ConvertHash2Direct(dynablocklist_t* dynablocks)
khint_t k;
dynablock_t* db;
uintptr_t key;
uintptr_t start = dynablocks->text-dynablocks->base;
uintptr_t end = dynablocks->text + dynablocks->textsz-dynablocks->base;
uintptr_t start = dynablocks->text;
uintptr_t end = start + dynablocks->textsz;
kh_foreach(dynablocks->blocks, key, db,
key += dynablocks->base;
if(key>=start && key<end)
direct[key-start] = db;
else {
k = kh_put(dynablocks, blocks, key, &ret);
k = kh_put(dynablocks, blocks, key-dynablocks->base, &ret);
if(ret) { // don't try to insert if already done...
kh_value(blocks, k) = db;
}
@@ -95,71 +437,65 @@ void ConvertHash2Direct(dynablocklist_t* dynablocks)
}
#define MAGIC_SIZE 256
/*
return NULL if block is not found / cannot be created.
Don't create if create==0
*/
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t* current)
dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int with_marks, int* created)
{
// try the quickest way first: get parent of current and check if ok!
dynablocklist_t *dynablocks = NULL;
dynablock_t* block = NULL;
if(current) {
dynablocks = current->parent;
if(dynablocks->direct && addr>=dynablocks->text && addr<=dynablocks->text+dynablocks->textsz) {
block = dynablocks->direct[addr-dynablocks->text];
if(block)
return block;
}
if(!(addr>=dynablocks->text && addr<=dynablocks->text+dynablocks->textsz))
dynablocks = NULL;
}
// nope, lets do the long way
if(!dynablocks)
dynablocks = GetDynablocksFromAddress(emu->context, addr);
if(!dynablocks)
if(!dynablocks) {
dynarec_log(LOG_INFO, "Warning: Ask to create a dynblock with a NULL dynablocklist (addr=%p)\n", (void*)addr);
*created = 0;
return NULL;
// check direct first, without lock
if(dynablocks->direct && addr>=dynablocks->text && addr<=dynablocks->text+dynablocks->textsz)
block = dynablocks->direct[addr-dynablocks->text];
if(block)
return block;
// nope, put rwlock in read mode and check hash
pthread_rwlock_rdlock(&dynablocks->rwlock_blocks);
// but first, check again just in case it has been created while waiting for mutex
if(dynablocks->direct && addr>=dynablocks->text && addr<=dynablocks->text+dynablocks->textsz)
block = dynablocks->direct[addr-dynablocks->text];
if(block) {
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
return block;
}
// check if the block exist
khint_t k;
int ret;
khint_t k = kh_get(dynablocks, dynablocks->blocks, addr-dynablocks->base);
if(k!=kh_end(dynablocks->blocks)) {
/*atomic_store(&dynalock, 0);*/
block = kh_value(dynablocks->blocks, k);
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
return block;
dynablock_t* block = NULL;
// first, check if it exist in direct access mode
if(dynablocks->direct && (addr>=dynablocks->text) && (addr<(dynablocks->text+dynablocks->textsz))) {
block = dynablocks->direct[addr-dynablocks->text];
if(block) {
dynarec_log(LOG_DUMP, "Block already exist in Direct Map\n");
*created = 0;
return block;
}
}
// unlock now
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
// Blocks doesn't exist. If creation is not allow, just return NULL
if(!create)
if(dynablocks->blocks) {
pthread_rwlock_rdlock(&dynablocks->rwlock_blocks);
// check if the block exist
khint_t k;
k = kh_get(dynablocks, dynablocks->blocks, addr-dynablocks->base);
if(k!=kh_end(dynablocks->blocks)) {
block = kh_value(dynablocks->blocks, k);
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
dynarec_log(LOG_DUMP, "Block already exist in Hash Map\n");
*created = 0;
return block;
}
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
}
if (!*created)
return block;
// Lock as write now!
pthread_rwlock_wrlock(&dynablocks->rwlock_blocks);
// create and add new block
dynarec_log(LOG_DEBUG, "Ask for DynaRec Block creation @%p\n", addr);
if(dynablocks->direct && addr>=dynablocks->text && addr<=dynablocks->text+dynablocks->textsz)
{
dynarec_log(LOG_DUMP, "Ask for DynaRec Block creation @%p\n", (void*)addr);
if(dynablocks->direct && (addr>=dynablocks->text) && (addr<(dynablocks->text+dynablocks->textsz))) {
block = dynablocks->direct[addr-dynablocks->text] = (dynablock_t*)calloc(1, sizeof(dynablock_t));
} else {
if(dynablocks->nolinker && ((addr<dynablocks->text) || (addr>=(dynablocks->text+dynablocks->textsz)))) {
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
//dynarec_log(LOG_INFO, "Warning: Refused to create a Direct Block that is out-of-bound: dynablocks=%p (%p:%p), addr=%p\n", dynablocks, (void*)(dynablocks->text), (void*)(dynablocks->text+dynablocks->textsz), (void*)addr);
//*created = 0;
//return NULL;
return AddNewDynablock(getDBFromAddress(addr), addr, with_marks, created);
}
k = kh_put(dynablocks, dynablocks->blocks, addr-dynablocks->base, &ret);
if(!ret) {
// Ooops, block is already there? retreive it and bail out
dynarec_log(LOG_DUMP, "Block already exist in Hash Map\n");
block = kh_value(dynablocks->blocks, k);
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
*created = 0;
return block;
}
block = kh_value(dynablocks->blocks, k) = (dynablock_t*)calloc(1, sizeof(dynablock_t));
@@ -168,12 +504,84 @@ dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t*
ConvertHash2Direct(dynablocks);
}
block->parent = dynablocks;
// add mark if needed
if(with_marks)
block->marks = kh_init(mark);
// create an empty block first, so if other thread want to execute the same block, they can, but using interpretor path
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
*created = 1;
return block;
}
/*
return NULL if block is not found / cannot be created.
Don't create if create==0
*/
static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t* current)
{
// try the quickest way first: get parent of current and check if ok!
dynablocklist_t *dynablocks = NULL;
dynablock_t* block = NULL;
if(current) {
dynablocks = current->parent;
if(!(addr>=dynablocks->text && addr<(dynablocks->text+dynablocks->textsz)))
dynablocks = NULL;
else if(dynablocks->direct && (addr>=dynablocks->text) && (addr<(dynablocks->text+dynablocks->textsz))) {
block = dynablocks->direct[addr-dynablocks->text];
if(block)
return block;
}
}
// nope, lets do the long way
if(!dynablocks)
dynablocks = GetDynablocksFromAddress(emu->context, addr);
if(!dynablocks)
return NULL;
// check direct first, without lock
if(dynablocks->direct && (addr>=dynablocks->text) && (addr<(dynablocks->text+dynablocks->textsz)))
block = dynablocks->direct[addr-dynablocks->text];
if(block)
return block;
int created = create;
block = AddNewDynablock(dynablocks, addr, (dynablocks->nolinker)&&(dynablocks->direct), &created);
if(!created || !create)
return block; // existing block...
if(box86_dynarec_dump)
pthread_mutex_lock(&my_context->mutex_lock);
// fill the block
FillBlock(emu, block, addr);
dynarec_log(LOG_DEBUG, " --- DynaRec Block created @%p (%p, 0x%x bytes)\n", addr, block->block, block->size);
block->x86_addr = (void*)addr;
FillBlock(block);
if(box86_dynarec_dump)
pthread_mutex_unlock(&my_context->mutex_lock);
dynarec_log(LOG_DEBUG, " --- DynaRec Block %s @%p:%p (%p, 0x%x bytes, %swith %d son(s))\n", created?"created":"recycled", (void*)addr, (void*)(addr+block->x86_size), block->block, block->size, block->marks?"with Marks, ":"", block->sons_size);
return block;
}
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t** current)
{
dynablock_t *db = internalDBGetBlock(emu, addr, create, *current);
if(db && (db->need_test || (db->father && db->father->need_test))) {
dynablock_t *father = db->father?db->father:db;
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)%s with %d son(s)\n", father, father->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->marks?" with Mark,":"", father->sons_size);
// no more current if it gets invalidated too
if(*current && father->x86_addr>=(*current)->x86_addr && (father->x86_addr+father->x86_size)<(*current)->x86_addr)
*current = NULL;
// Free father, it's now invalid!
FreeDynablock(father);
// start again... (will create a new block)
db = internalDBGetBlock(emu, addr, create, *current);
} else {
father->need_test = 0;
protectDB((uintptr_t)father->x86_addr, father->x86_size);
}
}
return db;
}
+19 -9
View File
@@ -1,25 +1,35 @@
#ifndef __DYNABLOCK_PRIVATE_H_
#define __DYNABLOCK_PRIVATE_H_
typedef struct dynablocklist_s dynablocklist_t;
typedef struct dynablocklist_s dynablocklist_t;
typedef struct kh_dynablocks_s kh_dynablocks_t;
typedef struct kh_mark_s kh_mark_t;
typedef struct dynablock_s {
dynablocklist_t *parent;
void* block;
int size;
uintptr_t* table;
int tablesz;
int done;
dynablocklist_t* parent;
kh_mark_t* marks; // List of blocks that marked this block
void* block;
int size;
void* x86_addr;
int x86_size;
uint32_t hash;
int need_test;
uintptr_t* table;
int tablesz;
int done;
int isize;
dynablock_t** sons; // sons (kind-of dummy dynablock...)
int sons_size;
dynablock_t* father; // set only in the case of a son
} dynablock_t;
typedef struct kh_dynablocks_s kh_dynablocks_t;
typedef struct dynablocklist_s {
kh_dynablocks_t *blocks;
pthread_rwlock_t rwlock_blocks;
uintptr_t base;
uintptr_t text;
int textsz;
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)
} dynablocklist_t;
+64 -45
View File
@@ -20,57 +20,72 @@
#endif
#ifdef ARM
void arm_prolog(x86emu_t* emu, void* addr);
void arm_epilog();
void arm_linker();
int arm_tableupdate(void* jump, uintptr_t addr, void** table);
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)
{
dynablock_t* block = DBGetBlock(emu, addr, 1, NULL); // keep a copy of parent block?
int r;
if(block==0) {
dynablock_t* current = (dynablock_t*)table[2];
if(current->father)
current = current->father;
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(table[3]) {
//dynarec_log(LOG_DEBUG, "--- Remove mark from %p (%p)\n", current, table[3]);
RemoveMark(table);
}
if(!block) {
// no block, don't try again, ever
#ifdef ARM
r = arm_tableupdate(arm_epilog, addr, table);
if(r) dynarec_log(LOG_DEBUG, "Linker: failed to set table data @%p, for emu=%p\n", table, emu);
#else
table[0] = arm_epilog;
table[1] = addr;
#endif
return arm_epilog;
tableupdate(arm_epilog, addr, table);
return arm_epilog_fast;
}
if(!block->done) {
// not finished yet... leave linker
#ifdef ARM
r = arm_tableupdate(arm_linker, addr, table);
if(r) dynarec_log(LOG_DEBUG, "Linker: failed to set table data @%p, for emu=%p\n", table, emu);
#else
table[0] = arm_linker;
table[1] = addr;
#endif
return arm_epilog;
//tableupdate(arm_linker, addr, table);
return arm_epilog_fast;
}
if(!block->block) {
// null block, but done, go to epilog
#ifdef ARM
r = arm_tableupdate(arm_epilog, addr, table);
if(r) dynarec_log(LOG_DEBUG, "Linker: failed to set table data @%p, for emu=%p\n", table, emu);
#else
table[0] = arm_epilog;
table[1] = addr;
#endif
return arm_epilog;
// null block, but done: go to epilog, no linker here
tableupdate(arm_epilog, addr, table);
return arm_epilog_fast;
}
dynablock_t *father = block->father?block->father:block;
if(!block->parent->nolinker || (current && father->marks)) {
//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 or if marks is possibe
if(current && father->marks && current!=father)
AddMark(current, father, table);
tableupdate(block->block, addr, table);
}
#ifdef ARM
r = arm_tableupdate(block->block, addr, table);
if(r) dynarec_log(LOG_DEBUG, "Linker: failed to set table data @%p, for emu=%p\n", table, emu);
#else
table[0] = block->block;
table[1] = addr;
#endif
return block->block;
}
#endif
@@ -93,15 +108,17 @@ void DynaCall(x86emu_t* emu, uintptr_t addr)
R_EIP = addr;
emu->df = d_none;
dynablock_t* block = NULL;
dynablock_t* current = NULL;
while(!emu->quit) {
block = DBGetBlock(emu, R_EIP, 1, block);
block = DBGetBlock(emu, R_EIP, 1, &current);
current = (block && !block->parent->nolinker)?block:NULL;
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", R_EIP, emu);
dynarec_log(LOG_DEBUG, "Calling Interpretor @%p, emu=%p\n", (void*)R_EIP, emu);
Run(emu, 1);
} else {
dynarec_log(LOG_DEBUG, "Calling DynaRec Block @%p (%p) emu=%p\n", R_EIP, block->block, emu);
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);
CHECK_FLAGS(emu);
// block is here, let's run it!
#ifdef ARM
@@ -140,15 +157,17 @@ int DynaRun(x86emu_t* emu)
#ifdef DYNAREC
else {
dynablock_t* block = NULL;
dynablock_t* current = NULL;
while(!emu->quit) {
block = DBGetBlock(emu, R_EIP, 1, block);
block = DBGetBlock(emu, R_EIP, 1, &current);
current = (block && !block->parent->nolinker)?block:NULL;
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", R_EIP, emu);
dynarec_log(LOG_DEBUG, "Running Interpretor @%p, emu=%p\n", (void*)R_EIP, emu);
Run(emu, 1);
} else {
dynarec_log(LOG_DEBUG, "Running DynaRec Block @%p (%p) emu=%p\n", R_EIP, block->block, emu);
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);
// block is here, let's run it!
#ifdef ARM
arm_prolog(emu, block->block);
+183 -25
View File
@@ -2,6 +2,7 @@
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include "debug.h"
#include "box86context.h"
@@ -18,27 +19,141 @@
#include "dynablock_private.h"
#include "dynarec_arm.h"
#include "dynarec_arm_private.h"
#include "elfloader.h"
void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const char* name) {
uint8_t *ip = (uint8_t*)inst->addr;
if(ip[0]==0xcc && ip[1]=='S' && ip[2]=='C') {
uint32_t a = *(uint32_t*)(ip+3);
if(a==0) {
dynarec_log(LOG_NONE, "%p: Exit x86emu\n", (void*)ip);
dynarec_log(LOG_NONE, "%s%p: Exit x86emu%s\n", (box86_dynarec_dump>1)?"\e[1m":"", (void*)ip, (box86_dynarec_dump>1)?"\e[m":"");
} else {
dynarec_log(LOG_NONE, "%p: Native call to %p\n", (void*)ip, (void*)a);
dynarec_log(LOG_NONE, "%s%p: Native call to %p%s\n", (box86_dynarec_dump>1)?"\e[1m":"", (void*)ip, (void*)a, (box86_dynarec_dump>1)?"\e[m":"");
}
} else {
if(dec) {
dynarec_log(LOG_NONE, "%p: %s\n", inst->addr, DecodeX86Trace(dec, inst->addr));
dynarec_log(LOG_NONE, "%s%p: %s", (box86_dynarec_dump>1)?"\e[1m":"", ip, DecodeX86Trace(dec, inst->addr));
} else {
dynarec_log(LOG_NONE, "%p: ", inst->addr);
dynarec_log(LOG_NONE, "%s%p: ", (box86_dynarec_dump>1)?"\e[1m":"", ip);
for(int i=0; i<inst->size; ++i) {
dynarec_log(LOG_NONE, "%02X ", ip[i]);
}
dynarec_log(LOG_NONE, " %s\n", name);
dynarec_log(LOG_NONE, " %s", name);
}
// print Call function name if possible
if(ip[0]==0xE8 || ip[0]==0xE9) { // Call / Jmp
uintptr_t nextaddr = (uintptr_t)ip + 5 + *((int32_t*)(ip+1));
printFunctionAddr(nextaddr, "=> ");
} else if(ip[0]==0xFF) {
if(ip[1]==0x25) {
uintptr_t nextaddr = (uintptr_t)ip + 6 + *((int32_t*)(ip+2));
printFunctionAddr(nextaddr, "=> ");
}
}
// end of line and colors
dynarec_log(LOG_NONE, "%s\n", (box86_dynarec_dump>1)?"\e[m":"");
}
}
void add_next(dynarec_arm_t *dyn, uintptr_t addr) {
if(dyn->next_sz == dyn->next_cap) {
dyn->next_cap += 16;
dyn->next = (uintptr_t*)realloc(dyn->next, dyn->next_cap*sizeof(uintptr_t));
}
for(int i=0; i<dyn->next_sz; ++i)
if(dyn->next[i]==addr)
return;
dyn->next[dyn->next_sz++] = addr;
}
uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr) {
// get closest, but no addresses befores
uintptr_t best = 0;
int i = 0;
while((i<dyn->next_sz) && (best!=addr)) {
if(dyn->next[i]<addr) { // remove the address, it's before current address
memmove(dyn->next+i, dyn->next+i+1, (dyn->next_sz-i-1)*sizeof(uintptr_t));
--dyn->next_sz;
} else {
if((dyn->next[i]<best) || !best)
best = dyn->next[i];
++i;
}
}
return best;
}
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)
return is_nops(dyn, addr+1, n-1);
if(n>1 && PK(0)==0x66) // if opcode start with 0x66, and there is more after, than is *can* be a NOP
return is_nops(dyn, addr+1, n-1);
if(n>2 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x00)
return is_nops(dyn, addr+3, n-3);
if(n>2 && PK(0)==0x8d && PK(1)==0x76 && PK(2)==0x00) // lea esi, [esi]
return is_nops(dyn, addr+3, n-3);
if(n>3 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x40 && PK(3)==0x00)
return is_nops(dyn, addr+4, n-4);
if(n>3 && PK(0)==0x8d && PK(1)==0x74 && PK(2)==0x26 && PK(3)==0x00)
return is_nops(dyn, addr+4, n-4);
if(n>4 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x44 && PK(3)==0x00 && PK(4)==0x00)
return is_nops(dyn, addr+5, n-5);
if(n>5 && PK(0)==0x8d && PK(1)==0xb6 && PK(2)==0x00 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00)
return is_nops(dyn, addr+6, n-6);
if(n>6 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x80 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00 && PK(6)==0x00)
return is_nops(dyn, addr+7, n-7);
if(n>6 && PK(0)==0x8d && PK(1)==0xb4 && PK(2)==0x26 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00 && PK(6)==0x00) // lea esi, [esi+0]
return is_nops(dyn, addr+7, n-7);
if(n>7 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x84 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00 && PK(6)==0x00 && PK(7)==0x00)
return is_nops(dyn, addr+8, n-8);
return 0;
#undef PK
}
uint32_t needed_flags(dynarec_arm_t *dyn, int ninst, uint32_t setf, int recurse)
{
if(ninst == dyn->size || (recurse==5))
return X_ALL; // no more instructions, or too many jmp loop, stop
uint32_t needed = dyn->insts[ninst].x86.use_flags;
if(needed) {
setf &= ~needed;
if(!setf) // all flags already used, no need to continue
return needed;
}
if(!needed && !dyn->insts[ninst].x86.set_flags && !dyn->insts[ninst].x86.jmp_insts) {
int start = ninst;
int end = ninst;
while(end<dyn->size && !dyn->insts[end].x86.use_flags && !dyn->insts[end].x86.set_flags && !dyn->insts[end].x86.jmp_insts)
++end;
needed = needed_flags(dyn, end, setf, recurse);
for(int i=start; i<end; ++i)
dyn->insts[i].x86.need_flags = needed;
return needed;
}
if(dyn->insts[ninst].x86.set_flags && (dyn->insts[ninst].x86.state_flags!=SF_MAYSET)) {
if((setf & ~dyn->insts[ninst].x86.set_flags) == 0)
return needed; // all done, gives all the flags needed
setf |= dyn->insts[ninst].x86.set_flags; // add new flags to continue
}
int jinst = dyn->insts[ninst].x86.jmp_insts;
if(dyn->insts[ninst].x86.jmp) {
dyn->insts[ninst].x86.need_flags = (jinst==-1)?X_PEND:needed_flags(dyn, jinst, setf, recurse+1);
if(dyn->insts[ninst].x86.use_flags) // conditionnal jump
dyn->insts[ninst].x86.need_flags |= needed_flags(dyn, ninst+1, setf, recurse);
} else
dyn->insts[ninst].x86.need_flags = needed_flags(dyn, ninst+1, setf, recurse);
if(dyn->insts[ninst].x86.state_flags==SF_MAYSET)
needed |= dyn->insts[ninst].x86.need_flags;
else
needed |= (dyn->insts[ninst].x86.need_flags & ~dyn->insts[ninst].x86.set_flags);
if(needed == (X_PEND|X_ALL))
needed = X_ALL;
return needed;
}
void arm_pass0(dynarec_arm_t* dyn, uintptr_t addr);
@@ -46,15 +161,18 @@ void arm_pass1(dynarec_arm_t* dyn, uintptr_t addr);
void arm_pass2(dynarec_arm_t* dyn, uintptr_t addr);
void arm_pass3(dynarec_arm_t* dyn, uintptr_t addr);
void FillBlock(x86emu_t* emu, dynablock_t* block, uintptr_t addr) {
void* FillBlock(dynablock_t* block) {
// init the helper
uintptr_t addr = (uintptr_t)block->x86_addr;
dynarec_arm_t helper = {0};
helper.emu = emu;
helper.nolinker = box86_dynarec_linker?(block->parent->nolinker):1;
helper.start = addr;
arm_pass0(&helper, addr);
if(!helper.size) {
dynarec_log(LOG_DEBUG, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
block->done = 1;
return;
free(helper.next);
return (void*)block;
}
helper.cap = helper.size+3; // needs epilog handling
helper.insts = (instruction_arm_t*)calloc(helper.cap, sizeof(instruction_arm_t));
@@ -80,44 +198,84 @@ void FillBlock(x86emu_t* emu, dynablock_t* block, uintptr_t addr) {
helper.insts[i].x86.jmp_insts = k;
}
}
// remove useless flags calulation
for(int i=0; i<helper.size; ++i)
if(helper.insts[i].x86.flags==X86_FLAGS_CHANGE) {
int done = 0;
for(int i2=i+1; i2<helper.size+1 && done==0; ++i2) {
if(helper.insts[i2].x86.barrier || helper.insts[i2].x86.jmp)
done = 1;
else if(helper.insts[i2].x86.flags==X86_FLAGS_USE)
done = 1;
else if(helper.insts[i2].x86.flags==X86_FLAGS_CHANGE) {
done = 1;
helper.insts[i].x86.flags=X86_FLAGS_NONE;
}
}
if(helper.insts[i].x86.set_flags && !helper.insts[i].x86.need_flags) {
helper.insts[i].x86.need_flags = needed_flags(&helper, i+1, helper.insts[i].x86.set_flags, 0);
if((helper.insts[i].x86.need_flags&X_PEND) && (helper.insts[i].x86.state_flags==SF_MAYSET))
helper.insts[i].x86.need_flags = X_ALL;
}
// pass 2, instruction size
arm_pass2(&helper, addr);
// ok, now allocate mapped memory, with executable flag on
int sz = helper.arm_size;
void* p = (void*)AllocDynarecMap(emu->context, sz);
void* p = (void*)AllocDynarecMap(sz, block->parent->nolinker);
if(p==NULL) {
free(helper.insts);
return;
free(helper.next);
return (void*)block;
}
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)
dynarec_log(LOG_DEBUG, "Emitting %d bytes for %d x86 bytes\n", helper.arm_size, helper.isize);
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);
printFunctionAddr(helper.start, " => ");
dynarec_log(LOG_NONE, "%s\n", (box86_dynarec_dump>1)?"\e[m":"");
}
helper.arm_size = 0;
arm_pass3(&helper, addr);
if(sz!=helper.arm_size) {printf_log(LOG_NONE, "BOX86: Warning, size difference in block between pass2 (%d) & pass3 (%d)!\n", sz, helper.arm_size);}
// all done...
__builtin___clear_cache(p, p+helper.arm_size); // need to clear the cache before execution...
__builtin___clear_cache(p, p+sz); // need to clear the cache before execution...
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->need_test = 0;
block->x86_addr = (void*)start;
block->x86_size = end-start;
if(box86_dynarec_largest<block->x86_size)
box86_dynarec_largest = block->x86_size;
block->hash = (helper.nolinker)?X31_hash_code(block->x86_addr, block->x86_size):0;
// fill sons if any
dynablock_t** sons = NULL;
int sons_size = 0;
if(helper.sons_size) {
sons = (dynablock_t**)calloc(helper.sons_size, sizeof(dynablock_t*));
for (int i=0; i<helper.sons_size; ++i) {
int created = 1;
dynablock_t *son = AddNewDynablock(block->parent, helper.sons_x86[i], 0, &created);
if(created) { // avoid breaking a working block! also, block could be outside this parent...
son->block = helper.sons_arm[i];
son->x86_addr = (void*)helper.sons_x86[i];
son->x86_size = end-helper.sons_x86[i];
if(!son->x86_size) {printf_log(LOG_NONE, "Warning, son with null x86 size! (@%p / ARM=%p)", son->x86_addr, son->block);}
son->father = block;
son->done = 1;
sons[sons_size++] = son;
}
}
if(sons_size) {
block->sons = sons;
block->sons_size = sons_size;
} else
free(sons);
}
if(block->parent->nolinker)
protectDB((uintptr_t)block->x86_addr, block->x86_size);
block->done = 1;
return (void*)block;
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+155
View File
@@ -0,0 +1,155 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <pthread.h>
#include <errno.h>
#include "debug.h"
#include "box86context.h"
#include "dynarec.h"
#include "emu/x86emu_private.h"
#include "emu/x86run_private.h"
#include "x86run.h"
#include "x86emu.h"
#include "box86stack.h"
#include "callback.h"
#include "emu/x86run_private.h"
#include "x86trace.h"
#include "dynarec_arm.h"
#include "dynarec_arm_private.h"
#include "arm_printer.h"
#include "dynarec_arm_helper.h"
uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
{
uint8_t opcode = F8;
uint8_t nextop;
int32_t i32;
uint32_t u32;
uint8_t gd, ed;
uint8_t wback;
int fixedaddress;
switch(opcode) {
case 0x33:
INST_NAME("XOR Gd, FS:Ed");
SETFLAGS(X_ALL, SF_SET);
grab_fsdata(dyn, addr, ninst, x12);
nextop = F8;
GETGD;
GETEDO(x12);
emit_xor32(dyn, ninst, gd, ed, x3, x12);
break;
case 0x3B:
INST_NAME("CMP Gd, FS:Ed");
SETFLAGS(X_ALL, SF_SET);
grab_fsdata(dyn, addr, ninst, x12);
nextop = F8;
GETGD;
GETEDO(x12);
emit_cmp32(dyn, ninst, gd, ed, x3, x12);
break;
case 0x89:
INST_NAME("MOV FS:Ed, Gd");
grab_fsdata(dyn, addr, ninst, x12);
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);
}
break;
case 0x8B:
INST_NAME("MOV Gd, FS:Ed");
grab_fsdata(dyn, addr, ninst, x12);
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);
}
break;
case 0x8F:
INST_NAME("POP FS:Ed");
grab_fsdata(dyn, addr, ninst, x12);
nextop = F8;
if((nextop&0xC0)==0xC0) {
POP(xESP, (1<<(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);
}
break;
case 0xA1:
INST_NAME("MOV EAX, FS:Id");
grab_fsdata(dyn, addr, ninst, x1);
i32 = F32S;
if(i32>-4096 && i32<4096) {
LDR_IMM9(xEAX, x1, i32);
} else {
MOV32(x2, i32);
ADD_REG_LSL_IMM5(x1, x1, x2, 0);
LDR_IMM9(xEAX, x1, 0);
}
break;
case 0xA3:
INST_NAME("MOV FS:Od, EAX");
grab_fsdata(dyn, addr, ninst, x1);
u32 = F32;
MOV32(x2, u32);
ADD_REG_LSL_IMM5(x2, x1, x2, 0);
STR_IMM9(xEAX, x2, 0);
break;
case 0xC7:
INST_NAME("MOV FS:Ed, Id");
grab_fsdata(dyn, addr, ninst, x12);
nextop=F8;
if((nextop&0xC0)==0xC0) { // reg <= i32
i32 = F32S;
ed = xEAX+(nextop&7);
MOV32(ed, i32);
} else { // mem <= i32
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
i32 = F32S;
MOV32(x3, i32);
STR_REG_LSL_IMM5(x3, ed, x12, 0);
}
break;
case 0xFF:
nextop = F8;
grab_fsdata(dyn, addr, ninst, x12);
switch((nextop>>3)&7) {
case 6: // Push Ed
INST_NAME("PUSH Ed");
if((nextop&0xC0)==0xC0) { // reg
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);
}
break;
default:
DEFAULT;
}
break;
default:
DEFAULT;
}
return addr;
}
+30 -13
View File
@@ -28,24 +28,42 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
int32_t i32;
uint32_t u32;
uint8_t gd, ed;
uint8_t wback, wb1, wb2;
uint8_t wback;
int fixedaddress;
switch(opcode) {
case 0x33:
case 0x03:
INST_NAME("ADD Gd, GS:Ed");
SETFLAGS(X_ALL, SF_SET);
grab_tlsdata(dyn, addr, ninst, x12);
INST_NAME("GS:XOR Gd, Ed");
nextop = F8;
GETGD;
GETEDO(x12);
XOR_REG_LSL_IMM8(gd, gd, ed, 0);
UFLAG_RES(gd);
UFLAG_DF(1, d_xor32);
UFLAGS(0);
emit_add32(dyn, ninst, gd, ed, x3, x12);
break;
case 0x2B:
INST_NAME("SUB Gd, GS:Ed");
SETFLAGS(X_ALL, SF_SET);
grab_tlsdata(dyn, addr, ninst, x12);
nextop = F8;
GETGD;
GETEDO(x12);
emit_sub32(dyn, ninst, gd, ed, x3, x12);
break;
case 0x33:
INST_NAME("XOR Gd, GS:Ed");
SETFLAGS(X_ALL, SF_SET);
grab_tlsdata(dyn, addr, ninst, x12);
nextop = F8;
GETGD;
GETEDO(x12);
emit_xor32(dyn, ninst, gd, ed, x3, x12);
break;
case 0x89:
grab_tlsdata(dyn, addr, ninst, x12);
INST_NAME("MOV GS:Ed, Gd");
grab_tlsdata(dyn, addr, ninst, x12);
nextop=F8;
GETGD;
if((nextop&0xC0)==0xC0) { // reg <= reg
@@ -57,8 +75,8 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 0x8B:
grab_tlsdata(dyn, addr, ninst, x12);
INST_NAME("MOV Gd, GS:Ed");
grab_tlsdata(dyn, addr, ninst, x12);
nextop=F8;
GETGD;
if((nextop&0xC0)==0xC0) { // reg <= reg
@@ -70,8 +88,8 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 0xA1:
grab_tlsdata(dyn, addr, ninst, x1);
INST_NAME("MOV EAX, GS:Id");
grab_tlsdata(dyn, addr, ninst, x1);
i32 = F32S;
if(i32>-4096 && i32<4096) {
LDR_IMM9(xEAX, x1, i32);
@@ -83,8 +101,8 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 0xA3:
grab_tlsdata(dyn, addr, ninst, x1);
INST_NAME("MOV GS:Od, EAX");
grab_tlsdata(dyn, addr, ninst, x1);
u32 = F32;
MOV32(x2, u32);
ADD_REG_LSL_IMM5(x2, x1, x2, 0);
@@ -92,8 +110,8 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 0xC7:
grab_tlsdata(dyn, addr, ninst, x12);
INST_NAME("MOV GS:Ed, Id");
grab_tlsdata(dyn, addr, ninst, x12);
nextop=F8;
if((nextop&0xC0)==0xC0) { // reg <= i32
i32 = F32S;
@@ -108,7 +126,6 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
default:
*ok = 0;
DEFAULT;
}
return addr;
File diff suppressed because it is too large. Load diff
+392 -66
View File
@@ -29,7 +29,7 @@
} else { \
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0); \
a = fpu_get_scratch_quad(dyn); \
VLD1Q_64(a, ed); \
VLD1Q_8(a, ed); \
}
#define GETGX(a) \
gd = (nextop&0x38)>>3; \
@@ -39,17 +39,22 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
{
uint8_t opcode = F8;
uint8_t nextop, u8;
int32_t i32, i32_;
int16_t i16;
uint16_t u16;
int32_t i32;
uint8_t gd, ed;
uint8_t wback, wb1, wb2;
uint8_t wback, wb1;
uint8_t eb1, eb2;
int v0, v1;
int q0, q1;
int d0, d1;
int s0, s1;
int d0;
int s0;
int fixedaddress;
int parity;
MAYUSE(d0);
MAYUSE(q1);
MAYUSE(eb1);
MAYUSE(eb2);
switch(opcode) {
case 0x10:
@@ -94,7 +99,6 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
GETGX(v0);
if((nextop&0xC0)==0xC0) {
// access register instead of memory is bad opcode!
*ok = 0;
DEFAULT;
return addr;
}
@@ -107,7 +111,6 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
GETGX(v0);
if((nextop&0xC0)==0xC0) {
// access register instead of memory is bad opcode!
*ok = 0;
DEFAULT;
return addr;
}
@@ -126,14 +129,25 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
VLDR_64(v0+1, ed, fixedaddress);
}
break;
case 0x15:
INST_NAME("UNPCKHPD Gx, Ex");
nextop = F8;
GETGX(v0);
VMOVD(v0, v0+1);
if((nextop&0xC0)==0xC0) {
v1 = sse_get_reg(dyn, ninst, x1, nextop&7);
VMOVD(v0+1, v1+1);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023-4, 3);
VLDR_64(v0+1, ed, fixedaddress+4);
}
break;
case 0x16:
INST_NAME("MOVHPD Gx, Ed");
nextop = F8;
GETGX(v0);
if((nextop&0xC0)==0xC0) {
// access register instead of memory is bad opcode!
*ok = 0;
DEFAULT;
return addr;
}
@@ -146,7 +160,6 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
GETGX(v0);
if((nextop&0xC0)==0xC0) {
// access register instead of memory is bad opcode!
*ok = 0;
DEFAULT;
return addr;
}
@@ -191,17 +204,56 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
// no special check...
case 0x2F:
if(opcode==0x2F) {INST_NAME("COMISD Gx, Ex");} else {INST_NAME("UCOMISD Gx, Ex");}
UFLAGS(0);
SETFLAGS(X_ALL, SF_SET);
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(q0);
VCMP_F64(v0, q0);
FCOMI(x1, x2);
UFLAGS(1);
break;
case 0x3A: // these are some SSE3 opcodes
case 0x38: // SSSE3 opcodes
nextop = F8;
switch(nextop) {
case 0x00:
INST_NAME("PSHUFB Gx, Ex");
nextop = F8;
GETGX(q0);
q1 = fpu_get_scratch_quad(dyn);
if((nextop&0xC0)==0xC0) {
v0 = sse_get_reg(dyn, ninst, x1, nextop&7);
VMOVQ(q1, v0);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
VLD1Q_64(q1, ed);
}
v1 = fpu_get_scratch_quad(dyn);
VMOVQ_8(v1, 0b10001111);
VANDQ(q1, q1, v1); // mask the index
VMOVQ(v1, q0);
VTBL2_8(q0+0, v1, q1+0);
VTBL2_8(q0+1, v1, q1+1);
break;
case 0x04:
INST_NAME("PMADDUBSW Gx,Ex");
nextop = F8;
GETGX(q0);
GETEX(q1);
v0 = fpu_get_scratch_quad(dyn);
VMULL_U16_U8(v0, q0+0, q1+0);
VPADDLQ_U16(v0, v0);
VQMOVN_S32(q0+0, v0);
VMULL_U16_U8(v0, q0+1, q1+1);
VPADDLQ_U16(v0, v0);
VQMOVN_S32(q0+1, v0);
break;
default:
DEFAULT;
}
break;
case 0x3A: // these are some more SSSE3 opcodes
opcode = F8;
switch(opcode) {
case 0x0F:
@@ -220,13 +272,12 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
}
break;
default:
*ok = 0;
DEFAULT;
}
break;
#define GO(GETFLAGS, NO, YES) \
USEFLAG(1); \
#define GO(GETFLAGS, NO, YES, F) \
READFLAGS(F); \
GETFLAGS; \
nextop=F8; \
GETGD; \
@@ -243,107 +294,107 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
INST_NAME("CMOVO Gw, Ew");
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_OF]));
CMPS_IMM8(x2, 1)
, cNE, cEQ)
, cNE, cEQ, 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)
, cEQ, cNE, 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)
, cNE, cEQ, 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)
, cEQ, cNE, 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)
, cNE, cEQ, 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)
, cEQ, cNE, 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_IMM8(x2, x2, x3, 0);
, cEQ, cNE)
ORRS_REG_LSL_IMM5(x2, x2, x3, 0);
, 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_IMM8(x2, x2, x3, 0);
, cNE, cEQ)
ORRS_REG_LSL_IMM5(x2, x2, x3, 0);
, 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)
, cNE, cEQ, 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)
, cEQ, cNE, 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)
, cNE, cEQ, 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)
, cEQ, cNE, 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]));
CMPS_REG_LSL_IMM5(x1, x2, 0)
, cEQ, cNE)
, 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]));
CMPS_REG_LSL_IMM5(x1, x2, 0)
, cNE, cEQ)
, 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]));
XOR_REG_LSL_IMM8(x1, x1, x2, 0);
XOR_REG_LSL_IMM5(x1, x1, x2, 0);
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORRS_REG_LSL_IMM8(x2, x1, x2, 0);
, cEQ, cNE)
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]));
XOR_REG_LSL_IMM8(x1, x1, x2, 0);
XOR_REG_LSL_IMM5(x1, x1, x2, 0);
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORRS_REG_LSL_IMM8(x2, x1, x2, 0);
, cNE, cEQ)
ORRS_REG_LSL_IMM5(x2, x1, x2, 0);
, cNE, cEQ, X_OF|X_SF|X_ZF)
break;
#undef GO
@@ -404,7 +455,55 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
fpu_putback_single_reg(dyn, ninst, v0, 1, s0);
VEOR(v0+1, v0+1, v0+1);
break;
case 0x5B:
INST_NAME("CVTPS2DQ Gx, Ex");
nextop = F8;
GETGX(v0);
GETEX(v1);
VCVTQ_F32_S32(v0, v1);
break;
case 0x5C:
INST_NAME("SUBPD Gx, Ex");
nextop = F8;
GETEX(q0);
GETGX(v0);
VSUB_F64(v0, v0, q0);
VSUB_F64(v0+1, v0+1, q0+1);
break;
case 0x5D:
INST_NAME("MINPD Gx, Ex");
nextop = F8;
GETEX(q0);
GETGX(v0);
// 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);
VCMP_F64(v0+1, q0+1);
VMRS_APSR();
VMOVcond_64(cPL, v0+1, q0+1);
break;
case 0x5E:
INST_NAME("DIVPD Gx, Ex");
nextop = F8;
GETEX(q0);
GETGX(v0);
VDIV_F64(v0, v0, q0);
VDIV_F64(v0+1, v0+1, q0+1);
break;
case 0x5F:
INST_NAME("MAXPD Gx, Ex");
nextop = F8;
GETEX(q0);
GETGX(v0);
// 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);
VCMP_F64(q0+1, v0+1);
VMRS_APSR();
VMOVcond_64(cPL, v0+1, q0+1);
break;
case 0x60:
INST_NAME("PUNPCKLBW Gx,Ex");
nextop = F8;
@@ -435,7 +534,14 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
} else q1 = q0;
VZIPQ_32(v0, q1);
break;
case 0x63:
INST_NAME("PACKSSWB Gx,Ex");
nextop = F8;
GETGX(q0);
GETEX(q1);
VQMOVN_S16(q0+0, q0);
VQMOVN_S16(q0+1, q1);
break;
case 0x64:
INST_NAME("PCMPGTB Gx,Ex");
nextop = F8;
@@ -742,7 +848,6 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
}
break;
default:
*ok = 0;
DEFAULT;
}
break;
@@ -838,11 +943,16 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
}
break;
default:
*ok = 0;
DEFAULT;
}
break;
case 0x74:
INST_NAME("PCMPEQB Gx,Ex");
nextop = F8;
GETGX(v0);
GETEX(q0);
VCEQQ_8(v0, v0, q0);
break;
case 0x75:
INST_NAME("PCMPEQW Gx,Ex");
nextop = F8;
@@ -867,10 +977,9 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
ed = xEAX + (nextop&7);
VMOVfrDx_32(ed, v0, 0);
} else {
d0 = fpu_get_scratch_double(dyn);
VMOVD(d0, v0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
VSTR_32(d0*2, ed, fixedaddress);
VMOVfrDx_32(x2, v0, 0); // to avoid Bus Error, using regular store
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
STR_IMM9(x2, ed, fixedaddress);
}
break;
case 0x7F:
@@ -888,8 +997,8 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
case 0xA3:
INST_NAME("BT Ew, Gw");
SETFLAGS(X_CF, SF_SET);
nextop = F8;
USEFLAG(1);
GETGD; // there is an AND below, so 32bits is the same (no need for GETGW)
GETEW(x1);
AND_IMM8(x2, gd, 15);
@@ -906,6 +1015,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
INST_NAME("SHLD Ew, Gw, CL");
UXTB(x3, xECX, 0);
}
SETFLAGS(X_ALL, SF_SET);
GETEWW(x12, x1);
GETGW(x2);
if(opcode==0xA4) {
@@ -914,13 +1024,12 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
}
CALL(shld16, x1, (1<<wback));
EWBACKW(x1);
UFLAGS(1);
break;
case 0xAB:
INST_NAME("BTS Ew, Gw");
SETFLAGS(X_CF, SF_SET);
nextop = F8;
USEFLAG(1);
GETGD; // there is an AND below, to 32bits is the same
GETEW(x12);
AND_IMM8(x2, gd, 15);
@@ -941,6 +1050,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
INST_NAME("SHRD Ew, Gw, CL");
UXTB(x3, xECX, 0);
}
SETFLAGS(X_ALL, SF_SET);
GETEWW(x12, x1);
GETGW(x2);
if(opcode==0xAC) {
@@ -949,11 +1059,11 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
}
CALL(shrd16, x1, (1<<wback));
EWBACKW(x1);
UFLAGS(1);
break;
case 0xAF:
INST_NAME("IMUL Gw,Ew");
SETFLAGS(X_ALL, SF_PENDING);
nextop = F8;
UFLAG_DF(x1, d_imul16);
if((nextop&0xC0)==0xC0) {
@@ -967,13 +1077,12 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
SMULBB(x2, gd, ed);
UFLAG_RES(x2);
BFI((xEAX+((nextop&0x38)>>3)), x2, 0, 16);
UFLAGS(0);
break;
case 0xB3:
INST_NAME("BTR Ew, Gw");
SETFLAGS(X_CF, SF_SET);
nextop = F8;
USEFLAG(1);
GETGD; // there is an AND below, to 32bits is the same
GETEW(x12);
AND_IMM8(x2, gd, 15);
@@ -1004,8 +1113,8 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
case 0xBB:
INST_NAME("BTC Ew, Gw");
SETFLAGS(X_CF, SF_SET);
nextop = F8;
USEFLAG(1);
GETGD; // there is an AND below, to 32bits is the same
GETEW(x12);
AND_IMM8(x2, gd, 15);
@@ -1018,38 +1127,38 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
break;
case 0xBC:
INST_NAME("BSF Ew,Gw");
SETFLAGS(X_ZF, SF_SET);
nextop = F8;
GETEW(x1); // Get EW
TSTS_REG_LSL_IMM8(x1, x1, 0);
TSTS_REG_LSL_IMM5(x1, x1, 0);
XOR_IMM8_COND(cEQ, x1, x1, 1);
B_MARK(cEQ);
RBIT(x1, x1); // reverse
CLZ(x2, x1); // x2 gets leading 0 == BSF
BFI(xEAX+((nextop&0x38)>>3), x2, 0, 16);
XOR_REG_LSL_IMM8(x1, x1, x1, 0); //ZF not set
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));
UFLAGS(1);
break;
case 0xBD:
INST_NAME("BSR Ew,Gw");
SETFLAGS(X_ZF, SF_SET);
nextop = F8;
GETEW(x1); // Get EW
TSTS_REG_LSL_IMM8(x1, x1, 0);
TSTS_REG_LSL_IMM5(x1, x1, 0);
XOR_IMM8_COND(cEQ, x1, x1, 1);
B_MARK(cEQ);
MOV_REG_LSL_IMM5(x1, x1, 16); // put bits on top
CLZ(x2, x1); // x2 gets leading 0
RSB_IMM8(x2, x2, 15); // complement
BFI(xEAX+((nextop&0x38)>>3), x2, 0, 16);
XOR_REG_LSL_IMM8(x1, x1, x1, 0); //ZF not set
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));
UFLAGS(1);
break;
case 0xBE:
INST_NAME("MOVSX Gw, Eb");
@@ -1067,6 +1176,45 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
BFI(gd, x1, 0, 16);
break;
case 0xC2:
INST_NAME("CMPPD Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(d0);
u8 = F8;
// 0
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 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 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);
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 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 7: MVN_COND_REG_LSL_IMM5(cVC, x2, x2, 0); break; // not NaN
}
VMOVtoV_D(v0+1, x2, x2);
break;
case 0xC4:
INST_NAME("PINSRW Gx,Ed,Ib");
nextop = F8;
@@ -1101,16 +1249,45 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
GETGX(v0);
GETEX(v1);
u8 = F8;
q0 = fpu_get_scratch_quad(dyn);
if(v0==v1 && u8==0) {
VMOVD(q0+1, q0);
} else {
q0 = fpu_get_scratch_quad(dyn);
VMOVD(q0, v0+(u8&1));
VMOVD(q0+1, v1+((u8>>1)&1));
VMOVQ(v0, q0);
}
break;
case 0xD1:
INST_NAME("PSRLW Gx,Ex");
nextop = F8;
GETGX(q0);
GETEX(q1);
v0 = fpu_get_scratch_quad(dyn);
VMOVD(v0, q1);
VMOVD(v0+1, q1);
VQMOVN_S64(v0, v0); // 2*q1 in 32bits now
VMOVD(v0+1, v0);
VQMOVN_S32(v0, v0); // 4*q1 in 16bits now
VNEGN_16(v0, v0); // because we want SHR and not SHL
VMOVD(v0+1, v0);
VSHLQ_U16(q0, q0, v0);
break;
case 0xD2:
INST_NAME("PSRLD Gx,Ex");
nextop = F8;
GETGX(q0);
GETEX(q1);
v0 = fpu_get_scratch_quad(dyn);
VMOVD(v0, q1);
VMOVD(v0+1, q1);
VQMOVN_S64(v0, v0); // 2*q1 in 32bits now
VNEGN_32(v0, v0); // because we want SHR and not SHL
VMOVD(v0+1, v0);
VSHLQ_U32(q0, q0, v0);
break;
case 0xD4:
INST_NAME("PADDQ Gx,Ex");
nextop = F8;
@@ -1129,13 +1306,22 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
INST_NAME("MOVQ Ex,Gx");
nextop = F8;
GETGX(q0);
parity = getedparity(dyn, ninst, addr, nextop, 3);
if((nextop&0xC0)==0xC0) {
q1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
VMOVD(q1, q0);
VEOR(q1+1, q1+1, q1+1);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
VSTR_64(q0, ed, fixedaddress);
// can be unaligned sometimes
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
VSTR_64(q0, ed, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);
VMOVfrV_D(x2, x3, q0);
STR_IMM9(x2, ed, fixedaddress+0);
STR_IMM9(x3, ed, fixedaddress+4);
}
}
break;
@@ -1161,7 +1347,21 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
GETEX(q0);
VANDQ(v0, v0, q0);
break;
case 0xDC:
INST_NAME("PADDUSB Gx,Ex");
nextop = F8;
GETGX(q0);
GETEX(q1);
VQADDQ_U8(q0, q0, q1);
break;
case 0xDE:
INST_NAME("PMAXUB Gx, Ex");
nextop = F8;
GETGX(q0);
GETEX(q1);
VMAXQ_U8(q0, q0, q1);
break;
case 0xDF:
INST_NAME("PANDN Gx,Ex");
nextop = F8;
@@ -1169,7 +1369,78 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
GETEX(q0);
VBICQ(v0, q0, v0);
break;
case 0xE0:
INST_NAME("PAVGB Gx,Ex");
nextop = F8;
GETGX(v0);
GETEX(q0);
VRHADDQ_U8(v0, v0, q0);
break;
case 0xE1:
INST_NAME("PSRAW Gx,Ex");
nextop = F8;
GETGX(q0);
GETEX(q1);
v0 = fpu_get_scratch_quad(dyn);
VMOVD(v0, q1);
VMOVD(v0+1, q1);
VQMOVN_S64(v0, v0); // 2*q1 in 32bits now
VMOVD(v0+1, v0);
VQMOVN_S32(v0, v0); // 4*q1 in 16bits now
VNEGN_16(v0, v0); // because we want SHR and not SHL
VMOVD(v0+1, v0);
VSHLQ_S16(q0, q0, v0);
break;
case 0xE2:
INST_NAME("PSRAD Gx,Ex");
nextop = F8;
GETGX(q0);
GETEX(q1);
v0 = fpu_get_scratch_quad(dyn);
VMOVD(v0, q1);
VMOVD(v0+1, q1);
VQMOVN_S64(v0, v0); // 2*q1 in 32bits now
VNEGN_32(v0, v0); // because we want SHR and not SHL
VMOVD(v0+1, v0);
VSHLQ_S32(q0, q0, v0);
break;
case 0xE3:
INST_NAME("PAVGW Gx,Ex");
nextop = F8;
GETGX(v0);
GETEX(q0);
VRHADDQ_U16(v0, v0, q0);
break;
case 0xE5:
INST_NAME("PMULHW Gx,Ex");
nextop = F8;
GETGX(v0);
GETEX(v1);
q0 = fpu_get_scratch_quad(dyn);
VMULL_S32_S16(q0, v0, v1);
VUZP_16(q0, q0+1);
VMOVD(v0, q0+1);
VMULL_S32_S16(q0, v0+1, v1+1);
VUZP_16(q0, q0+1);
VMOVD(v0+1, q0+1);
break;
case 0xE6:
INST_NAME("CVTTPD2DQ Gx, Ex");
nextop = F8;
GETGX(q0);
GETEX(q1);
if(q0<16) {
VCVT_S32_F64(q0*2, q1);
VCVT_S32_F64(q0*2+1, q1+1);
} else {
d0 = fpu_get_scratch_double(dyn);
VCVT_S32_F64(d0*2, q1);
VCVT_S32_F64(d0*2+1, q1+1);
VMOVD(q0, d0);
}
VEOR(q0+1, q0+1, q0+1);
break;
case 0xE7:
INST_NAME("MOVNTDQ Ex, Gx");
nextop = F8;
@@ -1183,6 +1454,20 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
VST1Q_32(v0, ed);
}
break;
case 0xE8:
INST_NAME("PSUBSB Gx,Ex");
nextop = F8;
GETGX(v0);
GETEX(q0);
VQSUBQ_S8(v0, v0, q0);
break;
case 0xE9:
INST_NAME("PSUBSW Gx,Ex");
nextop = F8;
GETGX(v0);
GETEX(q0);
VQSUBQ_S16(v0, v0, q0);
break;
case 0xEB:
INST_NAME("POR Gx,Ex");
@@ -1191,6 +1476,20 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
GETEX(q0);
VORRQ(v0, v0, q0);
break;
case 0xEC:
INST_NAME("PADDSB Gx,Ex");
nextop = F8;
GETGX(v0);
GETEX(q0);
VQADDQ_S8(v0, v0, q0);
break;
case 0xED:
INST_NAME("PADDSW Gx,Ex");
nextop = F8;
GETGX(v0);
GETEX(q0);
VQADDQ_S16(v0, v0, q0);
break;
case 0xEF:
INST_NAME("PXOR Gx,Ex");
@@ -1217,6 +1516,34 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
VTRN_32(q1, q1+1); // transpose EX
VMULL_U64_U32(v0, q0, q1);
break;
case 0xF5:
INST_NAME("PMADDWD Gx, Ex");
nextop = F8;
GETGX(v0);
GETEX(v1);
if((nextop&0xC0)==0xC0) {
q1 = fpu_get_scratch_quad(dyn);
VMOVQ(q1, v1);
} else {
q1 = v1;
}
VUZP_16(v0, v0+1);
VUZP_16(q1, q1+1);
VSWP(v0, q1+1);
VMULL_S32_S16(q1, q1, q1+1);
VMULL_S32_S16(v0, v0, v0+1);
VADDQ_32(v0, v0, q1);
break;
case 0xF6:
INST_NAME("PSADBW Gx, Ex");
nextop = F8;
GETGX(q0);
GETEX(q1);
VABDQ_U8(q0, q0, q1);
VPADDLQ_U8(q0, q0);
VPADDLQ_U16(q0, q0);
VPADDLQ_U32(q0, q0);
break;
case 0xF8:
INST_NAME("PSUBB Gx,Ex");
@@ -1269,7 +1596,6 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
break;
default:
*ok = 0;
DEFAULT;
}
return addr;
+9 -17
View File
@@ -24,17 +24,12 @@
uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
{
uint8_t opcode = F8;
uint8_t nextop, u8;
uint8_t nextop;
int8_t i8;
uint32_t u32;
int32_t i32;
int16_t i16;
uint16_t u16;
uint8_t gd, ed;
uint8_t wback, wb1, wb2;
int fixedaddress;
switch(opcode) {
MAYUSE(i32);
nextop = F8;
switch(nextop) {
#define GO(NO, YES) \
@@ -54,31 +49,30 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
}
case 0xE0:
INST_NAME("LOOPNZ (16bits)");
USEFLAG(1);
READFLAGS(X_ZF);
i8 = F8S;
UXTH(x1, xECX, 0);
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_IMM8(x1, x1, 0);
TSTS_REG_LSL_IMM5(x1, x1, 0);
GO(cNE, cEQ);
break;
case 0xE1:
INST_NAME("LOOPZ (16bits)");
USEFLAG(1);
READFLAGS(X_ZF);
i8 = F8S;
UXTH(x1, xECX, 0);
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_IMM8(x1, x1, 0);
TSTS_REG_LSL_IMM5(x1, x1, 0);
GO(cEQ, cNE);
break;
case 0xE2:
INST_NAME("LOOP (16bits)");
USEFLAG(1);
i8 = F8S;
UXTH(x1, xECX, 0);
SUBS_IMM8(x1, x1, 1);
@@ -87,16 +81,14 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 0xE3:
INST_NAME("JCXZ");
USEFLAG(1);
i8 = F8S;
UXTH(x1, xECX, 0);
TSTS_REG_LSL_IMM8(x1, x1, 0);
TSTS_REG_LSL_IMM5(x1, x1, 0);
GO(cNE, cEQ);
break;
#undef GO
default:
*ok = 0;
DEFAULT;
}
return addr;
+76 -27
View File
@@ -26,17 +26,19 @@
uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
{
uint8_t nextop = F8;
uint8_t u8;
uint32_t u32;
int32_t i32;
int16_t i16;
uint16_t u16;
uint8_t gd, ed;
uint8_t wback, wb1, wb2;
int v1, v2, v3;
int s0, s1, s2;
int d0, d1;
uint8_t ed;
uint8_t wback;
int v1, v2;
int s0;
int d1;
int fixedaddress;
int parity;
MAYUSE(d1);
MAYUSE(s0);
MAYUSE(v1);
MAYUSE(v2);
MAYUSE(ed);
switch(nextop) {
case 0xC0:
@@ -152,30 +154,48 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0:
INST_NAME("FADD ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
GETED;
s0 = fpu_get_scratch_single(dyn);
d1 = fpu_get_scratch_double(dyn);
VMOVtoV(s0, ed);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
VLDR_32(s0, ed, fixedaddress);
} else {
GETED;
VMOVtoV(s0, ed);
}
VCVT_F64_F32(d1, s0);
VADD_F64(v1, v1, d1);
break;
case 1:
INST_NAME("FMUL ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
GETED;
s0 = fpu_get_scratch_single(dyn);
d1 = fpu_get_scratch_double(dyn);
VMOVtoV(s0, ed);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
VLDR_32(s0, ed, fixedaddress);
} else {
GETED;
VMOVtoV(s0, ed);
}
VCVT_F64_F32(d1, s0);
VMUL_F64(v1, v1, d1);
break;
case 2:
INST_NAME("FCOM ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
GETED;
s0 = fpu_get_scratch_single(dyn);
d1 = fpu_get_scratch_double(dyn);
VMOVtoV(s0, ed);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
VLDR_32(s0, ed, fixedaddress);
} else {
GETED;
VMOVtoV(s0, ed);
}
VCVT_F64_F32(d1, s0);
VCMP_F64(v1, d1);
FCOM(x1, x2);
@@ -183,10 +203,16 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 3:
INST_NAME("FCOMP ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
GETED;
s0 = fpu_get_scratch_single(dyn);
d1 = fpu_get_scratch_double(dyn);
VMOVtoV(s0, ed);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
VLDR_32(s0, ed, fixedaddress);
} else {
GETED;
VMOVtoV(s0, ed);
}
VCVT_F64_F32(d1, s0);
VCMP_F64(v1, d1);
FCOM(x1, x2);
@@ -195,45 +221,68 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 4:
INST_NAME("FSUB ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
GETED;
s0 = fpu_get_scratch_single(dyn);
d1 = fpu_get_scratch_double(dyn);
VMOVtoV(s0, ed);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
VLDR_32(s0, ed, fixedaddress);
} else {
GETED;
VMOVtoV(s0, ed);
}
VCVT_F64_F32(d1, s0);
VSUB_F64(v1, v1, d1);
break;
case 5:
INST_NAME("FSUBR ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
GETED;
s0 = fpu_get_scratch_single(dyn);
d1 = fpu_get_scratch_double(dyn);
VMOVtoV(s0, ed);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
VLDR_32(s0, ed, fixedaddress);
} else {
GETED;
VMOVtoV(s0, ed);
}
VCVT_F64_F32(d1, s0);
VSUB_F64(v1, d1, v1);
break;
case 6:
INST_NAME("FDIV ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
GETED;
s0 = fpu_get_scratch_single(dyn);
d1 = fpu_get_scratch_double(dyn);
VMOVtoV(s0, ed);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
VLDR_32(s0, ed, fixedaddress);
} else {
GETED;
VMOVtoV(s0, ed);
}
VCVT_F64_F32(d1, s0);
VDIV_F64(v1, v1, d1);
break;
case 7:
INST_NAME("FDIVR ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
GETED;
s0 = fpu_get_scratch_single(dyn);
d1 = fpu_get_scratch_double(dyn);
VMOVtoV(s0, ed);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
VLDR_32(s0, ed, fixedaddress);
} else {
GETED;
VMOVtoV(s0, ed);
}
VCVT_F64_F32(d1, s0);
VDIV_F64(v1, d1, v1);
break;
default:
*ok = 0;
DEFAULT;
}
}
+47 -26
View File
@@ -34,17 +34,18 @@ static 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)
{
uint8_t nextop = F8;
uint8_t u8;
uint32_t u32;
int32_t i32;
int16_t i16;
uint16_t u16;
uint8_t gd, ed;
uint8_t wback, wb1, wb2;
uint8_t ed;
uint8_t wback, wb1;
int fixedaddress;
int v1, v2, v3;
int s0, s1, s2;
int v1, v2;
int s0;
int i1, i2, i3;
int parity;
MAYUSE(s0);
MAYUSE(v2);
MAYUSE(v1);
switch(nextop) {
case 0xC0:
@@ -262,7 +263,6 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xF5:
case 0xF6:
case 0xF7:
*ok = 0;
DEFAULT;
break;
@@ -271,37 +271,59 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0:
INST_NAME("FLD ST0, float[ED]");
v1 = x87_do_push(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
s0 = fpu_get_scratch_single(dyn);
// to avoid bus error
//VLDR_32(s0, ed, 0);
LDR_IMM9(x2, ed, fixedaddress);
VMOVtoV(s0, x2);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
VLDR_32(s0, ed, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
LDR_IMM9(x2, ed, fixedaddress);
VMOVtoV(s0, x2);
}
VCVT_F64_F32(v1, s0);
break;
case 2:
INST_NAME("FST float[ED], ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
s0 = fpu_get_scratch_single(dyn);
VCVT_F32_F64(s0, v1);
// to avoid bus error...
//VSTR_32(s0, ed, 0);
VMOVfrV(x2, s0);
STR_IMM9(x2, ed, fixedaddress);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
VSTR_32(s0, ed, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
VMOVfrV(x2, s0);
STR_IMM9(x2, ed, fixedaddress);
}
break;
case 3:
INST_NAME("FSTP float[ED], ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
s0 = fpu_get_scratch_single(dyn);
VCVT_F32_F64(s0, v1);
// to avoid bus error...
//VSTR_32(s0, ed, 0);
VMOVfrV(x2, s0);
STR_IMM9(x2, ed, fixedaddress);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
VSTR_32(s0, ed, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
VMOVfrV(x2, s0);
STR_IMM9(x2, ed, fixedaddress);
}
x87_do_pop(dyn, ninst);
break;
case 4:
INST_NAME("FLDENV Ed");
fpu_purgecache(dyn, ninst, x1, x2, x3); // maybe only x87, not SSE?
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
if(ed!=x1) {
MOV_REG(x1, ed);
}
MOVW(x2, 0);
CALL(fpu_loadenv, -1, 0);
break;
case 5:
INST_NAME("FLDCW Ew");
GETEW(x1);
@@ -318,7 +340,6 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
EWBACK;
break;
default:
*ok = 0;
DEFAULT;
}
}
+20 -17
View File
@@ -26,17 +26,21 @@
uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
{
uint8_t nextop = F8;
uint8_t u8;
uint32_t u32;
int32_t i32;
int16_t i16;
uint16_t u16;
uint8_t gd, ed;
uint8_t wback, wb1, wb2;
uint8_t ed;
uint8_t wback;
int v1, v2;
int d0;
int s0;
int fixedaddress;
MAYUSE(s0);
MAYUSE(d0);
MAYUSE(v2);
MAYUSE(v1);
MAYUSE(ed);
MAYUSE(i32);
switch(nextop) {
case 0xC0:
case 0xC1:
@@ -47,11 +51,11 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xC6:
case 0xC7:
INST_NAME("FCMOVB ST0, STx");
USEFLAG(1);
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_IMM8(x1, x1, 0);
TSTS_REG_LSL_IMM5(x1, x1, 0);
VMOVcond_64(cNE, v1, v2); // F_CF==1
break;
case 0xC8:
@@ -63,11 +67,11 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xCE:
case 0xCF:
INST_NAME("FCMOVE ST0, STx");
USEFLAG(1);
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_IMM8(x1, x1, 0);
TSTS_REG_LSL_IMM5(x1, x1, 0);
VMOVcond_64(cNE, v1, v2); // F_ZF==1
break;
case 0xD0:
@@ -79,12 +83,12 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xD6:
case 0xD7:
INST_NAME("FCMOVBE ST0, STx");
USEFLAG(1);
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_IMM8(x1, x1, x2, 0);
ORRS_REG_LSL_IMM5(x1, x1, x2, 0);
VMOVcond_64(cNE, v1, v2); // F_CF==1 | F_ZF==1
break;
case 0xD8:
@@ -96,17 +100,17 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xDE:
case 0xDF:
INST_NAME("FCMOVU ST0, STx");
USEFLAG(1);
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_IMM8(x1, x1, 0);
TSTS_REG_LSL_IMM5(x1, x1, 0);
VMOVcond_64(cNE, v1, v2); // F_PF==1
break;
case 0xE9:
INST_NAME("FUCOMPP ST0, STx");
INST_NAME("FUCOMPP ST0, ST1");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
v2 = x87_get_st(dyn, ninst, x1, x2, 1);
VCMP_F64(v1, v2);
FCOM(x1, x2);
x87_do_pop(dyn, ninst);
@@ -123,7 +127,6 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xF8:
case 0xF9:
case 0xFD:
*ok = 0;
DEFAULT;
break;
+28 -26
View File
@@ -22,22 +22,22 @@
#include "dynarec_arm_functions.h"
#include "dynarec_arm_helper.h"
static double maxint32 = (double)0x7fffffff;
uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
{
uint8_t nextop = F8;
uint8_t u8;
uint32_t u32;
int32_t i32;
int16_t i16;
uint16_t u16;
uint8_t gd, ed;
uint8_t wback, wb1, wb2;
int v1, v2, v3;
int s0, s1, s2;
int d0;
uint8_t ed;
uint8_t wback;
int v1, v2;
int s0;
int fixedaddress;
int parity;
MAYUSE(s0);
MAYUSE(v1);
MAYUSE(v2);
MAYUSE(i32);
switch(nextop) {
case 0xC0:
@@ -49,11 +49,11 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xC6:
case 0xC7:
INST_NAME("FCMOVNB ST0, STx");
USEFLAG(1);
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_IMM8(x1, x1, 0);
TSTS_REG_LSL_IMM5(x1, x1, 0);
VMOVcond_64(cEQ, v1, v2); // F_CF==0
break;
case 0xC8:
@@ -65,11 +65,11 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xCE:
case 0xCF:
INST_NAME("FCMOVNE ST0, STx");
USEFLAG(1);
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_IMM8(x1, x1, 0);
TSTS_REG_LSL_IMM5(x1, x1, 0);
VMOVcond_64(cEQ, v1, v2); // F_ZF==0
break;
case 0xD0:
@@ -81,12 +81,12 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xD6:
case 0xD7:
INST_NAME("FCMOVNBE ST0, STx");
USEFLAG(1);
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_IMM8(x1, x1, x2, 0);
ORRS_REG_LSL_IMM5(x1, x1, x2, 0);
VMOVcond_64(cEQ, v1, v2); // F_CF==0 | F_ZF==0
break;
case 0xD8:
@@ -98,11 +98,11 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xDE:
case 0xDF:
INST_NAME("FCMOVNU ST0, STx");
USEFLAG(1);
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_IMM8(x1, x1, 0);
TSTS_REG_LSL_IMM5(x1, x1, 0);
VMOVcond_64(cEQ, v1, v2); // F_PF==0
break;
case 0xE2:
@@ -127,12 +127,11 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xEE:
case 0xEF:
INST_NAME("FUCOMI ST0, STx");
UFLAGS(0);
SETFLAGS(X_ALL, SF_SET);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VCMP_F64(v1, v2);
FCOMI(x1, x2);
UFLAGS(1);
break;
case 0xF0:
case 0xF1:
@@ -143,12 +142,11 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xF6:
case 0xF7:
INST_NAME("FCOMI ST0, STx");
UFLAGS(0);
SETFLAGS(X_ALL, SF_SET);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VCMP_F64(v1, v2);
FCOMI(x1, x2);
UFLAGS(1);
break;
case 0xE0:
@@ -157,7 +155,6 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xE5:
case 0xE6:
case 0xE7:
*ok = 0;
DEFAULT;
break;
@@ -166,9 +163,15 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0:
INST_NAME("FILD ST0, Ed");
v1 = x87_do_push(dyn, ninst);
GETED;
s0 = fpu_get_scratch_single(dyn);
VMOVtoV(s0, ed);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
VLDR_32(s0, ed, fixedaddress);
} else {
GETED;
VMOVtoV(s0, ed);
}
VCVT_F64_S32(v1, s0);
break;
case 1:
@@ -267,7 +270,6 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
x87_do_pop(dyn, ninst);
break;
default:
*ok = 0;
DEFAULT;
}
}
+89 -26
View File
@@ -26,17 +26,16 @@
uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
{
uint8_t nextop = F8;
uint8_t u8;
uint32_t u32;
int32_t i32;
int16_t i16;
uint16_t u16;
uint8_t gd, ed;
uint8_t wback, wb1, wb2;
int v1, v2, v3;
int s0, s1;
int d0, d1;
uint8_t wback;
int v1, v2;
int d1;
int fixedaddress;
int parity;
MAYUSE(d1);
MAYUSE(v2);
MAYUSE(v1);
switch(nextop) {
case 0xC0:
case 0xC1:
@@ -150,34 +149,66 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0:
INST_NAME("FADD ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
d1 = fpu_get_scratch_double(dyn);
VLDR_64(d1, wback, fixedaddress);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
VLDR_64(d1, wback, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
LDR_IMM9(x2, wback, fixedaddress);
LDR_IMM9(x3, wback, fixedaddress+4);
VMOVtoV_D(d1, x2, x3);
}
VADD_F64(v1, v1, d1);
break;
case 1:
INST_NAME("FMUL ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
d1 = fpu_get_scratch_double(dyn);
VLDR_64(d1, wback, fixedaddress);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
VLDR_64(d1, wback, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
LDR_IMM9(x2, wback, fixedaddress);
LDR_IMM9(x3, wback, fixedaddress+4);
VMOVtoV_D(d1, x2, x3);
}
VMUL_F64(v1, v1, d1);
break;
case 2:
INST_NAME("FCOM ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
d1 = fpu_get_scratch_double(dyn);
VLDR_64(d1, wback, fixedaddress);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
VLDR_64(d1, wback, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
LDR_IMM9(x2, wback, fixedaddress);
LDR_IMM9(x3, wback, fixedaddress+4);
VMOVtoV_D(d1, x2, x3);
}
VCMP_F64(v1, d1);
FCOM(x1, x2);
break;
case 3:
INST_NAME("FCOMP ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
d1 = fpu_get_scratch_double(dyn);
VLDR_64(d1, wback, fixedaddress);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
VLDR_64(d1, wback, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
LDR_IMM9(x2, wback, fixedaddress);
LDR_IMM9(x3, wback, fixedaddress+4);
VMOVtoV_D(d1, x2, x3);
}
VCMP_F64(v1, d1);
FCOM(x1, x2);
x87_do_pop(dyn, ninst);
@@ -185,33 +216,65 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 4:
INST_NAME("FSUB ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
d1 = fpu_get_scratch_double(dyn);
VLDR_64(d1, wback, fixedaddress);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
VLDR_64(d1, wback, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
LDR_IMM9(x2, wback, fixedaddress);
LDR_IMM9(x3, wback, fixedaddress+4);
VMOVtoV_D(d1, x2, x3);
}
VSUB_F64(v1, v1, d1);
break;
case 5:
INST_NAME("FSUBR ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
d1 = fpu_get_scratch_double(dyn);
VLDR_64(d1, wback, fixedaddress);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
VLDR_64(d1, wback, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
LDR_IMM9(x2, wback, fixedaddress);
LDR_IMM9(x3, wback, fixedaddress+4);
VMOVtoV_D(d1, x2, x3);
}
VSUB_F64(v1, d1, v1);
break;
case 6:
INST_NAME("FDIV ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
d1 = fpu_get_scratch_double(dyn);
VLDR_64(d1, wback, fixedaddress);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
VLDR_64(d1, wback, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
LDR_IMM9(x2, wback, fixedaddress);
LDR_IMM9(x3, wback, fixedaddress+4);
VMOVtoV_D(d1, x2, x3);
}
VDIV_F64(v1, v1, d1);
break;
case 7:
INST_NAME("FDIVR ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
d1 = fpu_get_scratch_double(dyn);
VLDR_64(d1, wback, fixedaddress);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
VLDR_64(d1, wback, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
LDR_IMM9(x2, wback, fixedaddress);
LDR_IMM9(x3, wback, fixedaddress+4);
VMOVtoV_D(d1, x2, x3);
}
VDIV_F64(v1, d1, v1);
break;
}
+50 -17
View File
@@ -27,15 +27,13 @@
uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
{
uint8_t nextop = F8;
uint8_t u8;
uint32_t u32;
int32_t i32;
int16_t i16;
uint16_t u16;
uint8_t gd, ed;
uint8_t wback, wb1, wb2;
int fixedaddress;
int v1, v2, v3;
int parity;
uint8_t ed;
int v1, v2;
MAYUSE(v2);
MAYUSE(v1);
switch(nextop) {
case 0xC0:
@@ -133,7 +131,6 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xFD:
case 0xFE:
case 0xFF:
*ok = 0;
DEFAULT;
break;
@@ -147,9 +144,16 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
VLDR_64(v1, ed, fixedaddress);
#else
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 255, 0);
LDRD_IMM8(x2, ed, fixedaddress);
VMOVtoV_D(v1, x2, x3);
parity = getedparity(dyn, ninst, addr, nextop, 3);
if (parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
VLDR_64(v1, ed, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);
LDR_IMM9(x2, ed, fixedaddress);
LDR_IMM9(x3, ed, fixedaddress + 4);
VMOVtoV_D(v1, x2, x3);
}
#endif
break;
case 1:
@@ -163,18 +167,47 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 2:
INST_NAME("FST double");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
VSTR_64(v1, ed, fixedaddress); // check alignment?
parity = getedparity(dyn, ninst, addr, nextop, 3);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
VSTR_64(v1, ed, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);
VMOVfrV_D(x2, x3, v1);
STR_IMM9(x2, ed, fixedaddress);
STR_IMM9(x3, ed, fixedaddress+4);
}
break;
case 3:
INST_NAME("FSTP double");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
VSTR_64(v1, ed, fixedaddress); // check alignment?
parity = getedparity(dyn, ninst, addr, nextop, 3);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
VSTR_64(v1, ed, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);
VMOVfrV_D(x2, x3, v1);
STR_IMM9(x2, ed, fixedaddress);
STR_IMM9(x3, ed, fixedaddress+4);
}
x87_do_pop(dyn, ninst);
break;
case 4:
INST_NAME("FRSTOR m108byte");
fpu_purgecache(dyn, ninst, x1, x2, x3);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
if(ed!=x1) {MOV_REG(x1, ed);}
CALL(arm_frstor, -1, 0);
break;
case 6:
INST_NAME("FSAVE m108byte");
fpu_purgecache(dyn, ninst, x1, x2, x3);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
if(ed!=x1) {MOV_REG(x1, ed);}
CALL(arm_fsave, -1, 0);
break;
default:
*ok = 0;
DEFAULT;
}
}
+4 -12
View File
@@ -25,16 +25,10 @@
uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
{
uint8_t nextop = F8;
uint8_t u8;
uint32_t u32;
int32_t i32;
int16_t i16;
uint16_t u16;
uint8_t gd, ed;
uint8_t wback, wb1, wb2;
int v1, v2, v3;
int s0, s1, s2;
int fixedaddress;
int v1, v2;
MAYUSE(v2);
MAYUSE(v1);
switch(nextop) {
case 0xC0:
@@ -146,7 +140,6 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xDD:
case 0xDE:
case 0xDF:
*ok = 0;
DEFAULT;
break;
@@ -154,7 +147,6 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
default:
switch((nextop>>3)&7) {
default:
*ok = 0;
DEFAULT;
}
}
+11 -14
View File
@@ -28,17 +28,18 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
{
uint8_t nextop = F8;
uint8_t u8;
uint32_t u32;
int32_t i32;
int16_t i16;
uint16_t u16;
uint8_t gd, ed;
uint8_t wback, wb1, wb2;
int v1, v2, v3;
int s0, s1;
int d0;
uint8_t wback;
uint8_t ed;
int v1, v2;
int s0;
int fixedaddress;
MAYUSE(s0);
MAYUSE(v2);
MAYUSE(v1);
MAYUSE(i32);
switch(nextop) {
case 0xE0:
INST_NAME("FNSTSW AX");
@@ -57,13 +58,12 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xEE:
case 0xEF:
INST_NAME("FUCOMIP ST0, STx");
UFLAGS(0);
SETFLAGS(X_ALL, SF_SET);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VCMP_F64(v1, v2);
FCOMI(x1, x2);
x87_do_pop(dyn, ninst);
UFLAGS(1);
break;
case 0xF0:
case 0xF1:
@@ -74,13 +74,12 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xF6:
case 0xF7:
INST_NAME("FCOMIP ST0, STx");
UFLAGS(0);
SETFLAGS(X_ALL, SF_SET);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VCMP_F64(v1, v2);
FCOMI(x1, x2);
x87_do_pop(dyn, ninst);
UFLAGS(1);
break;
case 0xC0:
@@ -130,7 +129,6 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xFD:
case 0xFE:
case 0xFF:
*ok = 0;
DEFAULT;
break;
@@ -235,7 +233,6 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
x87_do_pop(dyn, ninst);
break;
default:
*ok = 0;
DEFAULT;
}
}
+1066
View File
File diff suppressed because it is too large. Load diff
+2291
View File
File diff suppressed because it is too large. Load diff
+280
View File
@@ -0,0 +1,280 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <pthread.h>
#include <errno.h>
#include "debug.h"
#include "box86context.h"
#include "dynarec.h"
#include "emu/x86emu_private.h"
#include "emu/x86run_private.h"
#include "x86run.h"
#include "x86emu.h"
#include "box86stack.h"
#include "callback.h"
#include "emu/x86run_private.h"
#include "x86trace.h"
#include "dynarec_arm.h"
#include "dynarec_arm_private.h"
#include "arm_printer.h"
#include "../tools/bridge_private.h"
#include "dynarec_arm_functions.h"
#include "dynarec_arm_helper.h"
// 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)
{
IFX(X_PEND) {
MOVW(s3, c);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
MOVW(s4, d_shl32);
} else IFX(X_ALL) {
MOVW(s4, d_none);
}
IFX(X_PEND|X_ALL) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
}
if(c==0) {
IFX(F_OF) {
MOVW(s4, 0);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
}
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
return;
}
IFX(X_CF) {
UBFX(s3, s1, c, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
}
IFX(X_ZF|X_OF) {
MOVS_REG_LSL_IMM5(s1, s1, c);
} else {
MOV_REG_LSL_IMM5(s1, s1, c);
}
IFX(X_PEND) {
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]));
}
IFX(X_SF) {
UBFX(s3, s1, 31, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_SF]));
}
IFX(X_OF) {
if(c==1) {
IFX(X_SF) {} else {UBFX(s3, s1, 31, 1);}
XOR_IMM8_COND(cCS, s3, s3, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_OF]));
} else {
MOVW(s4, 0);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
}
}
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 SHR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
void emit_shr32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
{
IFX(X_PEND) {
MOVW(s3, c);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
MOVW(s4, d_shr32);
} else IFX(X_ALL) {
MOVW(s4, d_none);
}
IFX(X_PEND|X_ALL) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
}
if(!c) {
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
return;
}
IFX(X_ZF|X_CF) {
MOVS_REG_LSR_IMM5(s1, s1, c);
} else {
MOV_REG_LSR_IMM5(s1, s1, c);
}
IFX(X_PEND) {
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]));
}
IFX(X_CF) {
MOVW_COND(cCC, s3, 0);
MOVW_COND(cCS, s3, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
}
IFX(X_SF) {
UBFX(s3, s1, 31, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_SF]));
}
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]));
}
}
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 SAR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
void emit_sar32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
{
IFX(X_PEND) {
MOVW(s3, c);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
MOVW(s4, d_sar32);
} else IFX(X_ALL) {
MOVW(s4, d_none);
}
IFX(X_PEND|X_ALL) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
}
if(!c) {
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
return;
}
IFX(X_ZF|X_CF) {
MOVS_REG_ASR_IMM5(s1, s1, c);
} else {
MOV_REG_ASR_IMM5(s1, s1, c);
}
IFX(X_PEND) {
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]));
}
IFX(X_CF) {
MOVW_COND(cCC, s3, 0);
MOVW_COND(cCS, s3, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
}
IFX(X_SF) {
UBFX(s3, s1, 31, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_SF]));
}
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 ROL32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
void emit_rol32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
{
IFX(X_PEND) {
MOVW(s3, c);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
MOVW(s4, d_rol32);
} else IFX(X_ALL) {
MOVW(s4, d_none);
}
IFX(X_PEND|X_ALL) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
}
if(!c) {
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
return;
}
MOV_REG_ROR_IMM5(s1, s1, 32-c);
IFX(X_PEND) {
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]));
}
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]));
}
}
}
// emit ROR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
void emit_ror32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
{
IFX(X_PEND) {
MOVW(s3, c);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
MOVW(s4, d_ror32);
} else IFX(X_ALL) {
MOVW(s4, d_none);
}
IFX(X_PEND|X_ALL) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
}
if(!c) {
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
return;
}
MOV_REG_ROR_IMM5(s1, s1, c);
IFX(X_PEND) {
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]));
}
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]));
}
}
}
+484
View File
@@ -0,0 +1,484 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <pthread.h>
#include <errno.h>
#include "debug.h"
#include "box86context.h"
#include "dynarec.h"
#include "emu/x86emu_private.h"
#include "emu/x86run_private.h"
#include "x86run.h"
#include "x86emu.h"
#include "box86stack.h"
#include "callback.h"
#include "emu/x86run_private.h"
#include "x86trace.h"
#include "dynarec_arm.h"
#include "dynarec_arm_private.h"
#include "arm_printer.h"
#include "../tools/bridge_private.h"
#include "dynarec_arm_functions.h"
#include "dynarec_arm_helper.h"
// 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) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
MOVW(s4, d_cmp32);
} else {
MOVW(s4, 0);
}
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
SUBS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 - s2
IFX(X_PEND) {
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
}
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]));
}
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]));
}
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]));
}
IFX(X_SF) {
UBFX(s4, s3, 31, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
}
// and now the tricky ones (and mostly unused), PF and AF
IFX(X_AF) {
// bc = (res & (~d | s)) | (~d & s)
MVN_REG_LSL_IMM5(s4, s1, 0); // s4 = ~d
ORR_REG_LSL_IMM5(s4, s4, s2, 0); // s4 = ~d | s
AND_REG_LSL_IMM5(s4, s4, s3, 0); // s4 = res & (~d | s)
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
}
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
IFX(X_CF|X_AF) {
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));
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]));
}
}
// 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) {
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(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_OF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
}
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]));
}
IFX(X_SF) {
UBFX(s4, s3, 31, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
}
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 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) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
MOVW(s3, d_cmp16);
} else {
MOVW(s3, 0);
}
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df)); // reset flags
SUB_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 - s2
IFX(X_PEND) {
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]));
}
IFX(X_SF) {
UBFX(s4, s3, 15, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
}
// bc = (res & (~d | s)) | (~d & s)
IFX(X_CF|X_AF|X_OF) {
MVN_REG_LSL_IMM5(s4, s1, 0); // s4 = ~d
ORR_REG_LSL_IMM5(s4, s4, s2, 0); // s4 = ~d | s
AND_REG_LSL_IMM5(s4, s4, s3, 0); // s4 = res & (~d | s)
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
}
IFX(X_AF) {
UBFX(s4, s3, 3, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // 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
}
}
// 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));
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]));
}
}
// 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));
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
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);
}
// 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_OF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF])); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 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]));
}
IFX(X_SF) {
UBFX(s4, s1, 15, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
}
// 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 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);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
} else {
MOVW(s4, 0);
}
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
SUB_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 - s2
IFX(X_PEND) {
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]));
}
IFX(X_SF) {
UBFX(s4, s3, 7, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
}
// bc = (res & (~d | s)) | (~d & s)
IFX(X_CF|X_AF|X_OF) {
MVN_REG_LSL_IMM5(s4, s1, 0); // s4 = ~d
ORR_REG_LSL_IMM5(s4, s4, s2, 0); // s4 = ~d | s
AND_REG_LSL_IMM5(s4, s4, s3, 0); // s4 = res & (~d | s)
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
}
IFX(X_AF) {
UBFX(s4, s3, 3, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // 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
}
}
// 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));
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]));
}
}
// 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);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
STR_IMM9(s4, xEmu, offsetof(x86emu_t, op2));
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df));
} else {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
}
// 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_OF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF])); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
}
IFX(X_ZF) {
TSTS_IMM8(s1, 0xff);
MOVW_COND(cEQ, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
}
IFX(X_SF) {
UBFX(s4, s1, 7, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
}
// 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 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));
} else {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
}
IFX(X_OF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
}
IFX(X_CF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF]));
}
ANDS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 & s2
IFX(X_PEND) {
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]));
}
IFX(X_SF) {
UBFX(s4, s3, 31, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
}
// 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));
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]));
}
}
// 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));
} else {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
}
IFX(X_OF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
}
IFX(X_CF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF]));
}
ANDS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 & s2
IFX(X_PEND) {
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]));
}
IFX(X_SF) {
UBFX(s4, s3, 15, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
}
// 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));
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]));
}
}
// 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));
} else {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
}
IFX(X_OF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
}
IFX(X_CF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF]));
}
ANDS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 & s2
IFX(X_PEND) {
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]));
}
IFX(X_SF) {
UBFX(s4, s3, 7, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
}
// 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));
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]));
}
}
-8
View File
@@ -25,14 +25,6 @@
uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
{
uint8_t nextop = PK(0); // don't increment addr
uint8_t u8;
uint32_t u32;
int32_t i32;
int16_t i16;
uint16_t u16;
uint8_t gd, ed;
uint8_t wback, wb1, wb2;
int fixedaddress;
int locked = 0;
switch(nextop) {
// generic case
+47 -19
View File
@@ -22,32 +22,41 @@
#include "dynarec_arm_functions.h"
#include "dynarec_arm_helper.h"
// Get Ex as a double, not a quad
// Get Ex as a double, not a quad (warning, x2 and x3 may get used)
#define GETEX(a) \
if((nextop&0xC0)==0xC0) { \
a = sse_get_reg(dyn, ninst, x1, nextop&7); \
} else { \
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3); \
parity = getedparity(dyn, ninst, addr, nextop, 3); \
a = fpu_get_scratch_double(dyn); \
VLDR_64(a, ed, fixedaddress); \
if(parity) { \
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3); \
VLDR_64(a, ed, fixedaddress); \
} else { \
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);\
LDR_IMM9(x2, ed, fixedaddress+0); \
LDR_IMM9(x3, ed, fixedaddress+4); \
VMOVtoV_D(a, x2, x3); \
} \
}
uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
{
uint8_t nextop = F8;
uint8_t u8;
int32_t i32, i32_;
int16_t i16;
uint32_t u32;
uint16_t u16;
uint8_t gd, ed;
uint8_t wback, wb1, wb2;
uint8_t eb1, eb2;
uint8_t wback;
int v0, v1;
int q0, q1;
int d0, d1;
int s0, s1;
int s0;
int fixedaddress;
int parity;
MAYUSE(s0);
MAYUSE(d1);
MAYUSE(d0);
switch(nextop) {
case 0x10:
@@ -256,6 +265,26 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
}
break;
case 0x7C:
INST_NAME("HADDPS Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
if((nextop&0xC0)==0xC0) {
v1 = sse_get_reg(dyn, ninst, x1, nextop&7);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
v1 = fpu_get_scratch_quad(dyn);
VLD1Q_64(v1, ed);
}
VPADD_F32(v0, v0, v0+1);
if(v0==v1) {
VMOVD(v0+1, v0);
} else {
VPADD_F32(v0+1, v1, v1+1);
}
break;
case 0xC2:
INST_NAME("CMPSD Gx, Ex");
nextop = F8;
@@ -267,20 +296,19 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
MOVW(x2, 0);
u8 = F8;
switch(u8&7) {
case 0: MVN_COND_REG_LSL_IMM8(cEQ, x2, x2, 0); break; // Equal
case 1: MVN_COND_REG_LSL_IMM8(cCC, x2, x2, 0); break; // Less than
case 2: MVN_COND_REG_LSL_IMM8(cLS, x2, x2, 0); break; // Less or equal
case 3: MVN_COND_REG_LSL_IMM8(cVS, x2, x2, 0); break; // NaN
case 4: MVN_COND_REG_LSL_IMM8(cNE, x2, x2, 0); break; // Not Equal (or unordered on ARM, not on X86...)
case 5: MVN_COND_REG_LSL_IMM8(cPL, x2, x2, 0); break; // Greater or equal or unordered
case 6: MVN_COND_REG_LSL_IMM8(cHI, x2, x2, 0); break; // Greater or unordered
case 7: MVN_COND_REG_LSL_IMM8(cVC, x2, x2, 0); break; // not NaN
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 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 7: MVN_COND_REG_LSL_IMM5(cVC, x2, x2, 0); break; // not NaN
}
VMOVtoV_D(v0, x2, x2);
break;
default:
*ok = 0;
DEFAULT;
}
return addr;
+218 -146
View File
@@ -34,27 +34,42 @@
} \
a *= 2; \
} else { \
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3); \
a = fpu_get_scratch_single(dyn); \
VLDR_32(a, ed, fixedaddress); \
b = fpu_get_scratch_double(dyn); \
a = b*2; \
parity = getedparity(dyn, ninst, addr, nextop, 2); \
if(parity) { \
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 0); \
VLDR_32(a, ed, fixedaddress); \
} else { \
GETED; \
VMOVtoV(a, ed); \
} \
}
#define GETGX(a) \
gd = (nextop&0x38)>>3; \
a = sse_get_reg(dyn, ninst, x1, gd)
uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
{
uint8_t opcode = F8;
uint8_t nextop, u8;
int32_t i32, i32_;
int32_t i32;
uint32_t u32;
int16_t i16;
uint16_t u16;
uint8_t gd, ed;
uint8_t wback, wb1, wb2;
uint8_t eb1, eb2;
uint8_t wback;
int fixedaddress;
int v0, v1;
int s0, s1;
int s0, s1, s2;
int d0, d1;
int q0, q1;
int q0;
int parity;
MAYUSE(s1);
MAYUSE(s2);
MAYUSE(i32);
switch(opcode) {
case 0x10:
@@ -117,6 +132,17 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
STR_IMM9(x2, ed, fixedaddress);
}
break;
case 0x1E:
INST_NAME("NOP / ENDBR32 / ENDBR64");
nextop = F8;
FAKEED;
break;
case 0x1F:
INST_NAME("REP NOP");
nextop = F8;
FAKEED;
break;
case 0x2A:
INST_NAME("CVTSI2SS Gx, Ed");
@@ -186,104 +212,118 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
case 0x51:
INST_NAME("SQRTSS Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(s0, d0);
if(v0<16)
d1 = v0;
else {
d1 = fpu_get_scratch_double(dyn);
VMOV_64(d1, v0);
}
VSQRT_F32(d1*2, s0);
if(v0!=d1) {
VMOV_64(v0, d1);
GETGX(v0);
GETEX(s1, v1);
if(v0==v1)
d0 = s1/2;
else
if(v0<16)
d0 = v0;
else {
d0 = fpu_get_scratch_double(dyn);
VMOV_64(d0, v0);
}
s0 = d0*2;
VSQRT_F32(s0, s1);
if(v0!=d0) {
VMOV_64(v0, d0);
}
break;
case 0x52:
INST_NAME("RSQRTSS Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(s0, d0);
if(v0<16)
d1 = v0;
else {
d1 = fpu_get_scratch_double(dyn);
VMOV_64(d1, v0);
}
s1 = fpu_get_scratch_single(dyn);
GETGX(v0);
GETEX(s1, v1);
if(v0==v1)
d0 = s1/2;
else
if(v0<16)
d0 = v0;
else {
d0 = fpu_get_scratch_double(dyn);
VMOV_64(d0, v0);
}
s0 = d0*2;
s2 = fpu_get_scratch_single(dyn);
// so here: F32: Imm8 = abcd efgh that gives => aBbbbbbc defgh000 00000000 00000000
// and want 1.0f = 0x3f800000
// so 00111111 10000000 00000000 00000000
// a = 0, b = 1, c = 1, d = 1, efgh=0
// 0b01110000
VMOV_i_32(s1, 0b01110000);
VDIV_F32(s0, s1, s0);
VSQRT_F32(d1*2, s0);
if(v0!=d1) {
VMOV_64(v0, d1);
VMOV_i_32(s2, 0b01110000);
VSQRT_F32(s0, s1);
VDIV_F32(s0, s2, s0);
if(v0!=d0) {
VMOV_64(v0, d0);
}
break;
case 0x53:
INST_NAME("RCPSS Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(s0, d0);
if(v0<16)
d1 = v0;
else {
d1 = fpu_get_scratch_double(dyn);
VMOV_64(d1, v0);
}
s1 = fpu_get_scratch_single(dyn);
VMOV_i_32(s1, 0b01110000);
VDIV_F32(d1*2, s1, s0);
if(v0!=d1) {
VMOV_64(v0, d1);
GETGX(v0);
GETEX(s1, v1);
if(v0==v1)
d0 = s1/2;
else
if(v0<16)
d0 = v0;
else {
d0 = fpu_get_scratch_double(dyn);
VMOV_64(d0, v0);
}
s0 = d0*2;
s2 = fpu_get_scratch_single(dyn);
VMOV_i_32(s2, 0b01110000);
VDIV_F32(s0, s2, s1);
if(v0!=d0) {
VMOV_64(v0, d0);
}
break;
case 0x58:
INST_NAME("ADDSS Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(s0, d0);
if(v0<16)
d1 = v0;
else {
d1 = fpu_get_scratch_double(dyn);
VMOV_64(d1, v0);
}
VADD_F32(d1*2, d1*2, s0);
if(v0!=d1) {
VMOV_64(v0, d1);
GETGX(v0);
GETEX(s1, v1);
if(v0==v1)
d0 = s1/2;
else
if(v0<16)
d0 = v0;
else {
d0 = fpu_get_scratch_double(dyn);
VMOV_64(d0, v0);
}
s0 = d0*2;
VADD_F32(s0, s0, s1);
if(v0!=d0) {
VMOV_64(v0, d0);
}
break;
case 0x59:
INST_NAME("MULSS Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(s0, d0);
if(v0<16)
d1 = v0;
else {
d1 = fpu_get_scratch_double(dyn);
VMOV_64(d1, v0);
}
VMUL_F32(d1*2, d1*2, s0);
if(v0!=d1) {
VMOV_64(v0, d1);
GETGX(v0);
GETEX(s1, v1);
if(v0==v1)
d0 = s1/2;
else
if(v0<16)
d0 = v0;
else {
d0 = fpu_get_scratch_double(dyn);
VMOV_64(d0, v0);
}
s0 = d0*2;
VMUL_F32(s0, s0, s1);
if(v0!=d0) {
VMOV_64(v0, d0);
}
break;
case 0x5A:
INST_NAME("CVTSS2SD Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETGX(v0);
GETEX(s0, d0);
VCVT_F64_F32(v0, s0);
break;
@@ -304,75 +344,87 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
case 0x5C:
INST_NAME("SUBSS Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(s0, d0);
if(v0<16)
d1 = v0;
else {
d1 = fpu_get_scratch_double(dyn);
VMOV_64(d1, v0);
}
VSUB_F32(d1*2, d1*2, s0);
if(v0!=d1) {
VMOV_64(v0, d1);
GETGX(v0);
GETEX(s1, v1);
if(v0==v1)
d0 = s1/2;
else
if(v0<16)
d0 = v0;
else {
d0 = fpu_get_scratch_double(dyn);
VMOV_64(d0, v0);
}
s0 = d0*2;
VSUB_F32(s0, s0, s1);
if(v0!=d0) {
VMOV_64(v0, d0);
}
break;
case 0x5D:
INST_NAME("MINSS Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(s0, d0);
if(v0<16)
d1 = v0;
else {
d1 = fpu_get_scratch_double(dyn);
VMOV_64(d1, v0);
}
GETGX(v0);
GETEX(s1, v1);
if(v0==v1)
d0 = s1/2;
else
if(v0<16)
d0 = v0;
else {
d0 = fpu_get_scratch_double(dyn);
VMOV_64(d0, v0);
}
s0 = d0*2;
// MINSS: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
VCMP_F32(d1*2, s0);
VCMP_F32(s0, s1);
VMRS_APSR();
VMOVcond_32(cPL, d1*2, s0);
if(v0!=d1) {
VMOV_64(v0, d1);
VMOVcond_32(cPL, s0, s1);
if(v0!=d0) {
VMOV_64(v0, d0);
}
break;
case 0x5E:
INST_NAME("DIVSS Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(s0, d0);
if(v0<16)
d1 = v0;
else {
d1 = fpu_get_scratch_double(dyn);
VMOV_64(d1, v0);
}
VDIV_F32(d1*2, d1*2, s0);
if(v0!=d1) {
VMOV_64(v0, d1);
GETGX(v0);
GETEX(s1, v1);
if(v0==v1)
d0 = s1/2;
else
if(v0<16)
d0 = v0;
else {
d0 = fpu_get_scratch_double(dyn);
VMOV_64(d0, v0);
}
s0 = d0*2;
VDIV_F32(s0, s0, s1);
if(v0!=d0) {
VMOV_64(v0, d0);
}
break;
case 0x5F:
INST_NAME("MAXSS Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(s0, d0);
if(v0<16)
d1 = v0;
else {
d1 = fpu_get_scratch_double(dyn);
VMOV_64(d1, v0);
}
GETGX(v0);
GETEX(s1, v1);
if(v0==v1)
d0 = s1/2;
else
if(v0<16)
d0 = v0;
else {
d0 = fpu_get_scratch_double(dyn);
VMOV_64(d0, v0);
}
s0 = d0*2;
// MAXSS: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
VCMP_F32(s0, d1*2);
VCMP_F32(s1, s0);
VMRS_APSR();
VMOVcond_32(cPL, d1*2, s0);
if(v0!=d1) {
VMOV_64(v0, d1);
VMOVcond_32(cPL, s0, s1);
if(v0!=d0) {
VMOV_64(v0, d0);
}
break;
@@ -465,37 +517,57 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
}
break;
case 0xBC:
INST_NAME("TZCNT Gd, Ed");
SETFLAGS(X_CF|X_ZF, SF_SET);
nextop = F8;
GETED;
GETGD;
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));
break;
case 0xC2:
INST_NAME("CMPSS Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(s0, d0);
if(v0<16)
d1 = v0;
else {
d1 = fpu_get_scratch_double(dyn);
VMOV_64(d1, v0);
}
VCMP_F32(d1*2, s0);
GETGX(v0);
GETEX(s1, v1);
if(v0==v1)
d0 = s1/2;
else
if(v0<16)
d0 = v0;
else {
d0 = fpu_get_scratch_double(dyn);
VMOV_64(d0, v0);
}
s0 = d0*2;
VCMP_F32(s0, s1);
VMRS_APSR();
MOVW(x2, 0);
u8 = F8;
switch(u8&7) {
case 0: MVN_COND_REG_LSL_IMM8(cEQ, x2, x2, 0); break; // Equal
case 1: MVN_COND_REG_LSL_IMM8(cCC, x2, x2, 0); break; // Less than
case 2: MVN_COND_REG_LSL_IMM8(cLS, x2, x2, 0); break; // Less or equal
case 3: MVN_COND_REG_LSL_IMM8(cVS, x2, x2, 0); break; // NaN
case 4: MVN_COND_REG_LSL_IMM8(cNE, x2, x2, 0); break; // Not Equal (or unordered on ARM, not on X86...)
case 5: MVN_COND_REG_LSL_IMM8(cPL, x2, x2, 0); break; // Greater or equal or unordered
case 6: MVN_COND_REG_LSL_IMM8(cHI, x2, x2, 0); break; // Greater or unordered
case 7: MVN_COND_REG_LSL_IMM8(cVC, x2, x2, 0); break; // not NaN
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 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 7: MVN_COND_REG_LSL_IMM5(cVC, x2, x2, 0); break; // not NaN
}
VMOVtoDx_32(v0, 0, x2);
break;
default:
*ok = 0;
DEFAULT;
}
return addr;
+108 -90
View File
@@ -5,6 +5,9 @@
#include <errno.h>
#include <string.h>
#include <math.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include "debug.h"
#include "box86context.h"
@@ -135,97 +138,71 @@ void arm_fld(x86emu_t* emu, uint8_t* ed)
STld(0).ref = ST0.ll;
}
void arm_cpuid(x86emu_t* emu, uint32_t tmp32u)
void arm_ud(x86emu_t* emu)
{
switch(tmp32u) {
case 0x0:
// emulate a P4
R_EAX = 0x80000004;
// return GenuineIntel
R_EBX = 0x756E6547;
R_EDX = 0x49656E69;
R_ECX = 0x6C65746E;
break;
case 0x1:
R_EAX = 0x00000101; // familly and all
R_EBX = 0; // Brand indexe, CLFlush, Max APIC ID, Local APIC ID
R_EDX = 1 // fpu
| 1<<8 // cmpxchg8
| 1<<11 // sep (sysenter & sysexit)
| 1<<15 // cmov
| 1<<19 // clflush (seems to be with SSE2)
| 1<<23 // mmx
//| 1<<24 // fxsr (fxsave, fxrestore)
| 1<<25 // SSE
| 1<<26 // SSE2
;
R_ECX = 1<<12 // fma
| 1<<13 // cx16 (cmpxchg16)
; // also 1<<0 is SSE3 and 1<<9 is SSSE3
break;
case 0x2: // TLB and Cache info. Sending 1st gen P4 info...
R_EAX = 0x665B5001;
R_EBX = 0x00000000;
R_ECX = 0x00000000;
R_EDX = 0x007A7000;
break;
case 0x4: // Cache info
switch (R_ECX) {
case 0: // L1 data cache
R_EAX = (1 | (1<<5) | (1<<8)); //type
R_EBX = (63 | (7<<22)); // size
R_ECX = 63;
R_EDX = 1;
break;
case 1: // L1 inst cache
R_EAX = (2 | (1<<5) | (1<<8)); //type
R_EBX = (63 | (7<<22)); // size
R_ECX = 63;
R_EDX = 1;
break;
case 2: // L2 cache
R_EAX = (3 | (2<<5) | (1<<8)); //type
R_EBX = (63 | (15<<22)); // size
R_ECX = 4095;
R_EDX = 1;
break;
default:
R_EAX = 0x00000000;
R_EBX = 0x00000000;
R_ECX = 0x00000000;
R_EDX = 0x00000000;
break;
}
break;
case 0x5: //mwait info
R_EAX = 0;
R_EBX = 0;
R_ECX = 1 | 2;
R_EDX = 0;
break;
case 0x6: // thermal
case 0x9: // direct cache access
case 0xA: // Architecture performance monitor
R_EAX = 0;
R_EBX = 0;
R_ECX = 0;
R_EDX = 0;
break;
case 0x7: // extended bits...
/*if(R_ECX==0) R_EAX = 0;
else*/ R_EAX = R_ECX = R_EBX = R_EDX = 0;
break;
case 0x80000000: // max extended
break; // no extended, so return same value as beeing the max value!
default:
printf_log(LOG_INFO, "Warning, CPUID command %X unsupported (ECX=%08x)\n", tmp32u, R_ECX);
R_EAX = 0;
}
kill(getpid(), SIGILL);
}
void arm_fxsave(x86emu_t* emu, uint8_t* ed)
{
// should save flags & all
// copy MMX regs...
for(int i=0; i<8; ++i)
memcpy(ed+32+i*16, &emu->mmx[0], sizeof(emu->mmx[0]));
// copy SSE regs
memcpy(ed+160, &emu->xmm[0], sizeof(emu->xmm));
// put also FPU regs in a reserved area...
for(int i=0; i<8; ++i)
memcpy(ed+416+i*8, &emu->fpu[0], sizeof(emu->fpu[0]));
}
void arm_fxrstor(x86emu_t* emu, uint8_t* ed)
{
// should restore flags & all
// copy back MMX regs...
for(int i=0; i<8; ++i)
memcpy(&emu->mmx[i], ed+32+i*16, sizeof(emu->mmx[0]));
// copy SSE regs
memcpy(&emu->xmm[0], ed+160/4, sizeof(emu->xmm));
for(int i=0; i<8; ++i)
memcpy(&emu->fpu[0], ed+416+i*8, sizeof(emu->fpu[0]));
}
void arm_fsave(x86emu_t* emu, uint8_t* ed)
{
fpu_savenv(emu, (char*)ed, 0);
uint8_t* p = ed;
p += 28;
for (int i=0; i<8; ++i) {
#ifdef USE_FLOAT
d = ST(i).f;
LD2D(p, &d);
#else
LD2D(p, &ST(i).d);
#endif
p+=10;
}
}
void arm_frstor(x86emu_t* emu, uint8_t* ed)
{
fpu_loadenv(emu, (char*)ed, 0);
uint8_t* p = ed;
p += 28;
for (int i=0; i<8; ++i) {
#ifdef USE_FLOAT
D2LD(&d, p);
ST(i).f = d;
#else
D2LD(&ST(i).d, p);
#endif
p+=10;
}
}
// Get a FPU single scratch reg
int fpu_get_scratch_single(dynarec_arm_t* dyn)
{
@@ -246,7 +223,7 @@ int fpu_get_scratch_quad(dynarec_arm_t* dyn)
return i/2; // Return a Dx, not a Qx
}
// Reset scratch regs counter
int fpu_reset_scratch(dynarec_arm_t* dyn)
void fpu_reset_scratch(dynarec_arm_t* dyn)
{
dyn->fpu_scratch = 0;
}
@@ -282,9 +259,50 @@ void fpu_free_reg_quad(dynarec_arm_t* dyn, int reg)
dyn->fpuused[i] = dyn->fpuused[i+1] = 0;
}
// Reset fpu regs counter
int fpu_reset_reg(dynarec_arm_t* dyn)
void fpu_reset_reg(dynarec_arm_t* dyn)
{
dyn->fpu_reg = 0;
for (int i=0; i<24; ++i)
dyn->fpuused[i]=0;
}
// 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)
return 0; // direct register, no parity...
if(!(nextop&0xC0)) {
if((nextop&7)==4) {
uint8_t sib = F8;
int sib_reg = (sib>>3)&7;
if((sib&0x7)==5) {
uint32_t tmp = F32;
if (sib_reg!=4) {
// if XXXXXX+reg<<N then check parity of XXXXX and N should be enough
return ((tmp&tested)==0 && (sib>>6)>=parity)?1:0;
} else {
// just a constant...
return (tmp&tested)?0:1;
}
} else {
if(sib_reg==4)
return 0; // simple [reg]
// don't try [reg1 + reg2<<N], unless reg1 is ESP
return ((sib&0x7)==4 && (sib>>6)>=parity)?1:0;
}
} else if((nextop&7)==5) {
uint32_t tmp = F32;
return (tmp&tested)?0:1;
} else {
return 0;
}
} else {
return 0; //Form [reg1 + reg2<<N + XXXXXX]
}
#undef F8
#undef F32
}
+10 -3
View File
@@ -25,8 +25,12 @@ 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_fld(x86emu_t* emu, uint8_t* ed);
void arm_fxsave(x86emu_t* emu, uint8_t* ed);
void arm_fxrstor(x86emu_t* emu, uint8_t* ed);
void arm_fsave(x86emu_t* emu, uint8_t* ed);
void arm_frstor(x86emu_t* emu, uint8_t* ed);
void arm_cpuid(x86emu_t* emu, uint32_t tmp32u);
void arm_ud(x86emu_t* emu);
// Get an FPU single scratch reg
int fpu_get_scratch_single(dynarec_arm_t* dyn);
@@ -35,7 +39,7 @@ int fpu_get_scratch_double(dynarec_arm_t* dyn);
// Get an FPU quad scratch reg
int fpu_get_scratch_quad(dynarec_arm_t* dyn);
// Reset scratch regs counter
int fpu_reset_scratch(dynarec_arm_t* dyn);
void fpu_reset_scratch(dynarec_arm_t* dyn);
// Get an FPU double reg
int fpu_get_reg_double(dynarec_arm_t* dyn);
// Free a FPU double reg
@@ -45,6 +49,9 @@ int fpu_get_reg_quad(dynarec_arm_t* dyn);
// Free a FPU quad reg
void fpu_free_reg_quad(dynarec_arm_t* dyn, int reg);
// Reset fpu regs counter
int fpu_reset_reg(dynarec_arm_t* dyn);
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);
#endif //__DYNAREC_ARM_FUNCTIONS_H__
File diff suppressed because it is too large. Load diff
+216 -34
View File
@@ -171,8 +171,10 @@
RSB_COND_IMM8(cEQ, r, r, 0)
// CALL will use x12 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)
// 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 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))
@@ -182,6 +184,8 @@
#define GETMARK3 ((dyn->insts)?dyn->insts[ninst].mark3:(dyn->arm_size+4))
#define MARKF if(dyn->insts) {dyn->insts[ninst].markf = (uintptr_t)dyn->arm_size;}
#define GETMARKF ((dyn->insts)?dyn->insts[ninst].markf:(dyn->arm_size+4))
#define MARKSEG if(dyn->insts) {dyn->insts[ninst].markseg = (uintptr_t)dyn->arm_size;}
#define GETMARKSEG ((dyn->insts)?dyn->insts[ninst].markseg:(dyn->arm_size+4))
// Branch to MARK if cond (use i32)
#define B_MARK(cond) \
@@ -199,69 +203,104 @@
#define B_NEXT(cond) \
i32 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->arm_size+8)):0; \
Bcond(cond, i32)
// Branch to MARKSEG if cond (use i32)
#define B_MARKSEG(cond) \
i32 = GETMARKSEG-(dyn->arm_size+8); \
Bcond(cond, i32)
#define IFX(A) if(dyn->insts && (dyn->insts[ninst].x86.need_flags&(A)))
#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))))
// 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_IMM8(s2, s2, s1, 0); \
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_IMM8(s2, s2, s1, 0); \
ORR_REG_LSL_IMM5(s2, s2, s1, 0); \
STRH_IMM8(s2, 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_IMM8(s2, s2, s2, 0); \
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 */ \
UBFX(s2, s1, 0, 1); \
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_CF])); \
UBFX(s2, s1, 1, 1); \
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_PF])); \
UBFX(s2, s1, 2, 1); \
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_ZF])); \
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));
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]));\
} \
#ifndef UFLAGS
#define UFLAGS(A) dyn->cleanflags=A
#endif
#ifndef USEFLAG
// USEFLAG will check status of defered flags the call update flags if needed. x3 will be used
#define USEFLAG(A) \
if(!dyn->cleanflags) { \
if(A) { \
#ifndef READFLAGS
#define READFLAGS(A) \
if(dyn->state_flags!=SF_SET) { \
if(dyn->state_flags!=SF_PENDING) { \
LDR_IMM9(x3, xEmu, offsetof(x86emu_t, df)); \
TSTS_REG_LSL_IMM8(x3, x3, 0); \
TSTS_REG_LSL_IMM5(x3, x3, 0); \
i32 = (GETMARKF)-(dyn->arm_size+8); \
Bcond(cEQ, i32); \
CALL_(UpdateFlags, -1, 0); \
MARKF; \
dyn->cleanflags=1; \
} \
} \
CALL_(UpdateFlags, -1, 0); \
MARKF; \
dyn->state_flags = SF_SET; \
}
#endif
#ifndef SETFLAGS
#define SETFLAGS(A, B) \
if(dyn->state_flags!=SF_SET && B==SF_SUBSET && (dyn->insts[ninst].x86.need_flags&(~((A)|X_PEND)))) \
READFLAGS(dyn->insts[ninst].x86.need_flags&(~(A))); \
dyn->state_flags = (B==SF_SUBSET)?SF_SET:B
#endif
#ifndef JUMP
#define JUMP(A)
#endif
#define BARRIER(A) if (dyn->insts && !dyn->insts[ninst].x86.barrier) dyn->insts[ninst].x86.barrier = A
#define UFLAG_OP1(A) if(dyn->insts && dyn->insts[ninst].x86.flags) {STR_IMM9(A, 0, offsetof(x86emu_t, op1));}
#define UFLAG_OP2(A) if(dyn->insts && dyn->insts[ninst].x86.flags) {STR_IMM9(A, 0, offsetof(x86emu_t, op2));}
#define UFLAG_OP12(A1, A2) if(dyn->insts && dyn->insts[ninst].x86.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.flags) {STR_IMM9(A, 0, offsetof(x86emu_t, res));}
#define UFLAG_DF(r, A) if(dyn->insts && dyn->insts[ninst].x86.flags) {MOVW(r, A); STR_IMM9(r, 0, offsetof(x86emu_t, df));}
#define UFLAG_IF if(dyn->insts && dyn->insts[ninst].x86.flags)
#ifndef DEFAULT
#define DEFAULT BARRIER(2)
#ifndef BARRIER
#define BARRIER(A)
#endif
#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_IF if(dyn->insts && dyn->insts[ninst].x86.need_flags)
#ifndef DEFAULT
#define DEFAULT *ok = -1; BARRIER(2)
#endif
#ifndef NEW_BARRIER_INST
#define NEW_BARRIER_INST
#endif
// Emit the LOCK mutex (x1, x2 and x3 are lost)
#define LOCK emit_lock(dyn, addr, ninst)
// Emit the UNLOCK mutex (x1, x2 and x3 are lost)
@@ -281,6 +320,7 @@ void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
#define dynarec00 STEPNAME(dynarec00)
#define dynarec0F STEPNAME(dynarec0F)
#define dynarecFS STEPNAME(dynarecFS)
#define dynarecGS STEPNAME(dynarecGS)
#define dynarec66 STEPNAME(dynarec66)
#define dynarec67 STEPNAME(dynarec67)
@@ -303,7 +343,9 @@ void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
#define jump_to_linker STEPNAME(jump_to_linker_)
#define ret_to_epilog STEPNAME(ret_to_epilog_)
#define retn_to_epilog STEPNAME(retn_to_epilog_)
#define iret_to_epilog STEPNAME(iret_to_epilog_)
#define call_c STEPNAME(call_c_)
#define grab_fsdata STEPNAME(grab_fsdata_)
#define grab_tlsdata STEPNAME(grab_tlsdata_)
#define isNativeCall STEPNAME(isNativeCall_)
#define emit_lock STEPNAME(emit_lock)
@@ -314,9 +356,65 @@ void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
#define emit_cmp8_0 STEPNAME(emit_cmp8_0)
#define emit_cmp16_0 STEPNAME(emit_cmp16_0)
#define emit_cmp32_0 STEPNAME(emit_cmp32_0)
#define emit_test8 STEPNAME(emit_test8)
#define emit_test8 STEPNAME(emit_test8)
#define emit_test16 STEPNAME(emit_test16)
#define emit_test32 STEPNAME(emit_test32)
#define emit_add32 STEPNAME(emit_add32)
#define emit_add32c STEPNAME(emit_add32c)
#define emit_add8 STEPNAME(emit_add8)
#define emit_add8c STEPNAME(emit_add8c)
#define emit_sub32 STEPNAME(emit_sub32)
#define emit_sub32c STEPNAME(emit_sub32c)
#define emit_sub8 STEPNAME(emit_sub8)
#define emit_sub8c STEPNAME(emit_sub8c)
#define emit_or32 STEPNAME(emit_or32)
#define emit_or32c STEPNAME(emit_or32c)
#define emit_xor32 STEPNAME(emit_xor32)
#define emit_xor32c STEPNAME(emit_xor32c)
#define emit_and32 STEPNAME(emit_and32)
#define emit_and32c STEPNAME(emit_and32c)
#define emit_or8 STEPNAME(emit_or8)
#define emit_or8c STEPNAME(emit_or8c)
#define emit_xor8 STEPNAME(emit_xor8)
#define emit_xor8c STEPNAME(emit_xor8c)
#define emit_and8 STEPNAME(emit_and8)
#define emit_and8c STEPNAME(emit_and8c)
#define emit_add16 STEPNAME(emit_add16)
#define emit_add16c STEPNAME(emit_add16c)
#define emit_sub16 STEPNAME(emit_sub16)
#define emit_sub16c STEPNAME(emit_sub16c)
#define emit_or16 STEPNAME(emit_or16)
#define emit_or16c STEPNAME(emit_or16c)
#define emit_xor16 STEPNAME(emit_xor16)
#define emit_xor16c STEPNAME(emit_xor16c)
#define emit_and16 STEPNAME(emit_and16)
#define emit_and16c STEPNAME(emit_and16c)
#define emit_inc32 STEPNAME(emit_inc32)
#define emit_inc16 STEPNAME(emit_inc16)
#define emit_inc8 STEPNAME(emit_inc8)
#define emit_dec32 STEPNAME(emit_dec32)
#define emit_dec16 STEPNAME(emit_dec16)
#define emit_dec8 STEPNAME(emit_dec8)
#define emit_adc32 STEPNAME(emit_adc32)
#define emit_adc32c STEPNAME(emit_adc32c)
#define emit_adc8 STEPNAME(emit_adc8)
#define emit_adc8c STEPNAME(emit_adc8c)
#define emit_adc16 STEPNAME(emit_adc16)
#define emit_adc16c STEPNAME(emit_adc16c)
#define emit_sbb32 STEPNAME(emit_sbb32)
#define emit_sbb32c STEPNAME(emit_sbb32c)
#define emit_sbb8 STEPNAME(emit_sbb8)
#define emit_sbb8c STEPNAME(emit_sbb8c)
#define emit_sbb16 STEPNAME(emit_sbb16)
#define emit_sbb16c STEPNAME(emit_sbb16c)
#define emit_neg32 STEPNAME(emit_neg32)
#define emit_neg16 STEPNAME(emit_neg16)
#define emit_neg8 STEPNAME(emit_neg8)
#define emit_shl32c STEPNAME(emit_shl32c)
#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 x87_do_push STEPNAME(x87_do_push)
#define x87_do_push_empty STEPNAME(x87_do_push_empty)
@@ -341,6 +439,9 @@ void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
#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)
@@ -358,7 +459,9 @@ 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 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 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);
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn);
void emit_lock(dynarec_arm_t* dyn, uintptr_t addr, int ninst);
@@ -372,6 +475,62 @@ void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_test32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_add32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_add32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_add8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
void emit_add8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_sub32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_sub32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_sub8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
void emit_sub8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_or32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_or32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
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_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_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_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_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_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_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);
void emit_inc8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
void emit_dec32(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
void emit_dec16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
void emit_dec8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
void emit_adc32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_adc32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_adc8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
void emit_adc8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_adc16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
void emit_adc16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_sbb32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_sbb32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_sbb8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
void emit_sbb8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_sbb16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
void emit_sbb16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_neg32(dynarec_arm_t* dyn, int ninst, 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_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, 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);
// x87 helper
// cache of the local stack counter, to avoid upadte at every call
@@ -425,9 +584,9 @@ int fpu_get_single_reg(dynarec_arm_t* dyn, int ninst, int reg, int idx);
// put back (if needed) the single reg in place
void fpu_putback_single_reg(dynarec_arm_t* dyn, int ninst, int reg, int idx, int s);
uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
@@ -444,4 +603,27 @@ 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
#define PASS2(A) A
#endif
#if STEP < 3
#define PASS3(A)
#else
#define PASS3(A) A
#endif
#if STEP < 3
#define MAYUSE(A) (void)A
#else
#define MAYUSE(A)
#endif
#endif //__DYNAREC_ARM_HELPER_H__
+24 -18
View File
@@ -24,39 +24,31 @@
#error No STEP defined
#endif
#include "dynarec_arm_helper.h"
void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
{
uint8_t nextop, opcode;
int ok = 1;
int ninst = 0;
uintptr_t ip = addr;
uintptr_t natcall;
int retn;
uint8_t gd, ed;
int8_t i8;
int32_t i32, tmp;
uint8_t u8;
uint8_t gb1, gb2, eb1, eb2;
uint32_t u32;
int need_epilog = 1;
uint8_t wback, wb1, wb2;
int fixedaddress;
dyn->tablei = 0;
dyn->sons_size = 0;
// Clean up (because there are multiple passes)
dyn->cleanflags = 0;
dyn->state_flags = 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;
}
NEW_INST;
fpu_reset_scratch(dyn);
#ifdef HAVE_TRACE
if(dyn->emu->dec && box86_dynarec_trace) {
if((dyn->emu->trace_end == 0)
|| ((ip >= dyn->emu->trace_start) && (ip <= dyn->emu->trace_end))) {
if(my_context->dec && box86_dynarec_trace) {
if((trace_end == 0)
|| ((ip >= trace_start) && (ip <= trace_end))) {
MESSAGE(LOG_DUMP, "TRACE ----\n");
fpu_reflectcache(dyn, ninst, x1, x2, x3);
MOV32(1, ip);
@@ -76,8 +68,21 @@ 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)
dyn->cleanflags = 0;
dyn->state_flags = 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<0) {ok = 0; need_epilog=1;}
++ninst;
}
if(need_epilog) {
@@ -85,4 +90,5 @@ void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
jump_to_epilog(dyn, ip, 0, ninst); // no linker here, it's an unknow instruction
}
FINI;
MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d, %d sons)\n", dyn->size, dyn->sons_size);
}
+14 -8
View File
@@ -2,15 +2,21 @@
#define INIT uintptr_t sav_addr=addr
#define FINI dyn->isize = addr-sav_addr
#define MESSAGE(A, ...)
#define SETFLAGS(A, B)
#define READFLAGS(A)
#define EMIT(A)
#define UFLAGS(A) {}
#define USEFLAGS(A) {}
#define JUMP(A) add_next(dyn, (uintptr_t)A)
#define NEW_INST ++dyn->size
#define INST_EPILOG
#define INST_NAME(name)
#define DEFAULT \
--dyn->size; \
dynarec_log(LOG_INFO, "%p: Dynarec stopped because of Opcode %02X %02X %02X %02X %02X %02X %02X\n", \
ip, PKip(0), \
PKip(1), PKip(2), PKip(3), \
PKip(4), PKip(5), PKip(6))
#define DEFAULT \
--dyn->size; \
*ok = -1; \
dynarec_log(LOG_INFO, "%p: Dynarec stopped because of Opcode %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X (%s)\n", \
(void*)ip, PKip(0), \
PKip(1), PKip(2), PKip(3), \
PKip(4), PKip(5), PKip(6), \
PKip(7), PKip(8), PKip(9), \
PKip(10),PKip(11),PKip(12), \
PKip(13),PKip(14), \
GetNativeName((void*)addr))
+7 -5
View File
@@ -1,15 +1,17 @@
#define INIT
#define FINI \
dyn->insts[ninst].x86.addr = addr; \
dyn->insts[ninst].x86.flags = X86_FLAGS_USE; \
if(ninst) dyn->insts[ninst-1].x86.size = dyn->insts[ninst].x86.addr - dyn->insts[ninst-1].x86.addr;
#define MESSAGE(A, ...)
#define EMIT(A)
#define UFLAGS(A) dyn->insts[ninst+(A?1:0)].x86.flags = X86_FLAGS_CHANGE
#define USEFLAG(A) dyn->insts[ninst].x86.flags = X86_FLAGS_USE
#define JUMP(A) dyn->insts[ninst].x86.jmp = A
#define READFLAGS(A) dyn->insts[ninst].x86.use_flags = A
#define SETFLAGS(A,B) {dyn->insts[ninst].x86.set_flags = A; dyn->insts[ninst].x86.state_flags = B;}
#define JUMP(A) dyn->insts[ninst].x86.jmp = A
#define BARRIER(A) dyn->insts[ninst].x86.barrier = A
#define BARRIER_NEXT(A) if(ninst+1<dyn->size) dyn->insts[ninst+1].x86.barrier = A
#define NEW_INST \
dyn->insts[ninst].x86.addr = ip; \
if(ninst) dyn->insts[ninst-1].x86.size = dyn->insts[ninst].x86.addr - dyn->insts[ninst-1].x86.addr;
#define INST_EPILOG
#define INST_NAME(name)
#define INST_NAME(name)
+1
View File
@@ -6,3 +6,4 @@
#define NEW_INST if(ninst) {dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size);}
#define INST_EPILOG dyn->insts[ninst].epilog = dyn->arm_size;
#define INST_NAME(name)
#define NEW_BARRIER_INST if(ninst) ++dyn->sons_size
+24 -3
View File
@@ -1,12 +1,33 @@
#define INIT
#define FINI
#define EMIT(A) \
if(box86_dynarec_log>=LOG_DUMP) {dynarec_log(LOG_NONE, "\t%08x\t%s\n", (A), arm_print(A));} \
if(box86_dynarec_dump) {dynarec_log(LOG_NONE, "\t%08x\t%s\n", (A), arm_print(A));} \
*(uint32_t*)(dyn->block) = A; \
dyn->block += 4; dyn->arm_size += 4
#define MESSAGE(A, ...) dynarec_log(A, __VA_ARGS__);
#define MESSAGE(A, ...) if(box86_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__)
#define NEW_INST
#define INST_EPILOG
#define INST_NAME(name) if(box86_dynarec_log>=LOG_DUMP) printf_x86_instruction(dyn->emu->dec, &dyn->insts[ninst].x86, name)
#define INST_NAME(name) \
if(box86_dynarec_dump) {\
printf_x86_instruction(my_context->dec, &dyn->insts[ninst].x86, name); \
dynarec_log(LOG_NONE, "%s%p: %d emited opcodes, state=%d/%d, set=%X, use=%X, need=%X%s\n", \
(box86_dynarec_dump>1)?"\e[32m":"", \
(void*)(dyn->arm_start+dyn->insts[ninst].address), \
dyn->insts[ninst].size/4, \
dyn->insts[ninst].x86.state_flags, \
dyn->state_flags, \
dyn->insts[ninst].x86.set_flags, \
dyn->insts[ninst].x86.use_flags, \
dyn->insts[ninst].x86.need_flags, \
(box86_dynarec_dump>1)?"\e[m":""); \
}
#define NEW_BARRIER_INST \
if(ninst) { \
dyn->sons_x86[dyn->sons_size] = (uintptr_t)ip; \
dyn->sons_arm[dyn->sons_size] = dyn->block; \
MESSAGE(LOG_DUMP, "----> potential Son here\n");\
++dyn->sons_size; \
}
+13 -2
View File
@@ -12,6 +12,7 @@ typedef struct instruction_arm_s {
int size; // size of the arm emited instruction
uintptr_t mark, mark2, mark3;
uintptr_t markf;
uintptr_t markseg;
} instruction_arm_t;
typedef struct dynarec_arm_s {
@@ -21,12 +22,12 @@ typedef struct dynarec_arm_s {
uintptr_t start; // start of the block
uint32_t isize; // size in byte of x86 instructions included
void* block; // memory pointer where next instruction is emited
uintptr_t arm_start; // start of the arm code
int arm_size; // size of emitted arm code
x86emu_t* emu;
uintptr_t* table; // jump table
int tablesz; // size of the jump table
int tablei; // index
int cleanflags; // flags are clean (CMP or TST have been just executed)
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
int mmxcache[8];// cache status for the 8 MMX registers
@@ -35,7 +36,17 @@ typedef struct dynarec_arm_s {
int x87stack; // cache stack counter
int fpu_scratch;// scratch counter
int fpu_reg; // x87/sse/mmx reg counter
int nolinker; // disable use of (smart) linker in the block
uintptr_t* next; // variable array of "next" jump address
int next_sz;
int next_cap;
uintptr_t* sons_x86; // the x86 address of potential dynablock sons
void** sons_arm; // the arm address of potential dynablock sons
int sons_size; // number of potential dynablock sons
} dynarec_arm_t;
void add_next(dynarec_arm_t *dyn, uintptr_t addr);
uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr);
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n);
#endif //__DYNAREC_ARM_PRIVATE_H_
+23 -5
View File
@@ -1,19 +1,37 @@
#ifndef __DYNAREC_PRIVATE_H_
#define __DYNAREC_PRIVATE_H_
#define X86_FLAGS_NONE 0
#define X86_FLAGS_CHANGE 1
#define X86_FLAGS_USE 2
// all flags for the use_flags field
#define X_CF (1<<0)
#define X_PF (1<<1)
#define X_AF (1<<2)
#define X_ZF (1<<3)
#define X_SF (1<<4)
#define X_OF (1<<5)
#define X_ALL ((1<<6)-1)
#define X_PEND (0x1000)
// all state flags
#define SF_UNKNOWN 0
#define SF_SET 1
#define SF_PENDING 2
#define SF_MAYSET 3
#define SF_SUBSET 4
typedef struct instruction_x86_s {
uintptr_t addr; //address of the instruction
int32_t size; // size of the instruction
int flags; // flags for this instruction (see X86_FLAGS_XXXX)
int barrier; // next instruction is a jump point, so no optim allowed
uintptr_t jmp; // offset to jump to, even if conditionnal (0 if not), no relative offset here
int jmp_insts; // instuction to jump to (-1 if out of the block)
uint32_t use_flags; // 0 or combination of X_?F
uint32_t set_flags; // 0 or combination of X_?F
uint32_t need_flags; // calculated
int state_flags; // One of SF_XXX state
} instruction_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_
#endif //__DYNAREC_PRIVATE_H_
+475
View File
@@ -0,0 +1,475 @@
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 op 0 N Q M 0 Vm VH\(op ? "SUB" : "ADD")\<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 0 0 N Q M 1 Vm VQADD<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 0 1 N Q M 0 Vm VRHADD<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D 0 0 Vn Vd 0 0 0 1 N Q M 1 Vm VAND<c> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D 0 1 Vn Vd 0 0 0 1 N Q M 1 Vm VBIC<c> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D 1 0 Vn Vd 0 0 0 1 N Q M 1 Vm @ m=n const char* op op,"MOV","ORR"@ m=n char lastop[6] !@ %@ lastop[0] = '\0'@ sprintf(lastop, ", %s", vecname[(q << 5) + 0x20 + n])@ @ V\op\<c> <Qd>, <Qm>\lastop\
NEON 1 1 1 1 0 0 1 0 0 D 1 1 Vn Vd 0 0 0 1 N Q M 1 Vm VORN<c> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 1 0 D @<2> Vn Vd 0 0 0 1 N Q M 1 Vm @ param=0b00=0b01=0b10 const char* op op,"EOR","BSL","BIT","BIF"@ @ V\op\<c> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 1 0 N Q M 1 Vm VQSUB<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 1 1 N Q M op Vm @ op=0 const char* strict strict,"T","E"@ @ VCG\strict\<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 0 N Q M 0 Vm VSHL<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 0 N Q M 1 Vm VQSHL<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 1 N Q M 0 Vm VRSHL<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 1 N Q M 1 Vm VQRSHL<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 1 0 N Q M op Vm @ op=0 const char* opname opname,"MAX","MIN"@ @ V\opname\<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 1 1 N Q M 0 Vm VABD<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 1 1 N Q M 1 Vm VABA<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 op 0 D size Vn Vd 1 0 0 0 N Q M 0 Vm @ op=0 const char* opname opname,"ADD","SUB"@ @ V\opname\<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D size Vn Vd 1 0 0 0 N Q M 1 Vm VTST<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 1 0 D size Vn Vd 1 0 0 0 N Q M 1 Vm VCEQ<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 1 0 0 1 N Q M 0 Vm @ set size = 8 << size@ @ VML\(u ? "S" : "A")\<c>.I\%dsize\ <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 1 0 0 1 N Q M 1 Vm VMUL<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 1 0 1 0 N Q M op Vm @ op=0 const char* opname opname,"MAX","MIN"@ @ VP\opname\<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D size Vn Vd 1 0 1 1 N Q M 0 Vm VQDMULH<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 1 0 D size Vn Vd 1 0 1 1 N Q M 0 Vm VQRDMULH<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D size Vn Vd 1 0 1 1 N Q/=0 M 1 Vm VPADD<c>.<dt> <Dd>, <Dn>, <Dm>
NEON 1 1 1 1 0 0 1 0 0 D U sz/=0 Vn Vd 1 1 0 0 N Q M 1 Vm @ u=0 const char* y y,"A","S"@ @ VFM\y\<c>.F32 <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D U sz/=0 Vn Vd 1 1 0 1 N Q M 0 Vm @ u=0 const char* op op,"ADD","SUB"@ @ V\op\<c>.F32 <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 1 0 D 0 sz/=0 Vn Vd 1 1 0 1 N Q/=0 M 0 Vm VPADD.F32 <Dd>, <Dn>, <Dm>
NEON 1 1 1 1 0 0 1 1 0 D 1 sz/=0 Vn Vd 1 1 0 1 N Q M 0 Vm VABD.F32 <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D op sz/=0 Vn Vd 1 1 0 1 N Q M 1 Vm VML\(op ? "S" : "A")\<c>.F32 <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 1 0 D 0 sz/=0 Vn Vd 1 1 0 1 N Q M 1 Vm VMUL.F32 <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D 0 sz/=0 Vn Vd 1 1 1 0 N Q M 0 Vm VCEQ.F32 <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 1 0 D op sz/=0 Vn Vd 1 1 1 0 N Q M 0 Vm @ op=1 const char* strict strict,"T","E"@ @ VCG\strict\.F32 <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 1 0 D op sz/=0 Vn Vd 1 1 1 0 N Q M 1 Vm @ op=1 const char* strict strict,"T","E"@ @ VACG\strict\.F32 <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D op sz/=0 Vn Vd 1 1 1 1 N Q M 0 Vm @ op=0 const char* opname opname,"MAX","MIN"@ @ V\opname\.F32 <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 1 0 D op sz/=0 Vn Vd 1 1 1 1 N Q M 0 Vm @ op=0 const char* opname opname,"MAX","MIN"@ @ VP\opname\.F32 <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D 0 sz/=0 Vn Vd 1 1 1 1 N Q M 1 Vm VRECPS.F32 <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 0 0 D 1 sz/=0 Vn Vd 1 1 1 1 N Q M 1 Vm VRSQRTS.F32 <Qd>, <Qn>, <Qm>
INVALIDATE 1 1 1 1 0 0 1 <1> 0 <23>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=0xx0 0 Q op/=0 1 imm4 VMOV<c>.<dt> <Qd>, #<imm>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=0xx1 0 Q op/=0 1 imm4 VORR<c>.<dt> <Qd>, #<imm>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=10x0 0 Q op/=0 1 imm4 VMOV<c>.<dt> <Qd>, #<imm>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=10x1 0 Q op/=0 1 imm4 VORR<c>.<dt> <Qd>, #<imm>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=11xx 0 Q op/=0 1 imm4 VMOV<c>.<dt> <Qd>, #<imm>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=0xx0 0 Q op/=1 1 imm4 VMVN<c>.<dt> <Qd>, #<imm>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=0xx1 0 Q op/=1 1 imm4 VBIC<c>.<dt> <Qd>, #<imm>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=10x0 0 Q op/=1 1 imm4 VMVN<c>.<dt> <Qd>, #<imm>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=10x1 0 Q op/=1 1 imm4 BIC<c>.<dt> <Qd>, #<imm>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=110x 0 Q op/=1 1 imm4 VMVN<c>.<dt> <Qd>, #<imm>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=1110 0 Q op/=1 1 imm4 VMOV<c>.<dt> <Qd>, #<imm>
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <1> 0 0 0 <11> 0 <2> 1 <4>
NEON 1 1 1 1 0 0 1 0 1 D 0 0 1 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S8 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 0 1 D 0 1 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S16 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 0 1 D 1 0 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S32 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 0 0 1 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U8 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 0 1 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U16 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 0 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U32 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 0 0 0 0 L Q M 1 Vm VSHR<c>.<dt> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 0 0 0 1 L Q M 1 Vm VSRA<c>.<dt> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 0 0 1 0 L Q M 1 Vm VRSHR<c>.<dt> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 0 0 1 1 L Q M 1 Vm VRSRA<c>.<dt> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 1 1 D imm6 Vd 0 1 0 0 L Q M 1 Vm VSRI<c>.<size> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 0 1 D Imm6 Vd 0 1 0 1 L Q M 1 Vm VSHL<c>.I<size> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 1 1 D Imm6 Vd 0 1 0 1 L Q M 1 Vm VSLI<c>.<size> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 U 1 D Imm6 Vd 0 1 1 op L Q M 1 Vm VQSHL\((u & op) ? "U" : "")\<c>.<dt> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 0 1 D imm6 Vd 1 0 0 0 0 0 M 1 Vm VSHRN<c>.I<size> <Dd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 0 1 D imm6 Vd 1 0 0 0 0 1 M 1 Vm VRSHRN<c>.I<size> <Dd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 1 0 0 op 0 0 M 1 Vm VQSHR\((u & op) ? "U" : "")\N<c>.<dt> <Dd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 1 0 0 op 0 1 M 1 Vm VQRSHR\((u & op) ? "U" : "")\N<c>.<dt> <Dd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 1 0 0 M 1 Vm VSHLL<c>.<dt> <Qd>, <Dm>, #\%d8 &l&l size\
NEON 1 1 1 1 0 0 1 U 1 D Imm6 Vd 1 0 1 0 0 0 M 1 Vm VSHLL<c>.<dt> <Qd>, <Dm>, #<imm>
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <1> 0 <9> 1 1 1 <1> 0 <2> 1 <4>
NEON 1 1 1 1 0 0 1 0 1 D IMM6 Vd 1 1 1 0 0 Q M 1 Vm VCVT<c>.F32.S32 <Qd>, <Qm>, #<fbits>
NEON 1 1 1 1 0 0 1 0 1 D IMM6 Vd 1 1 1 1 0 Q M 1 Vm VCVT<c>.S32.F32 <Qd>, <Qm>, #<fbits>
NEON 1 1 1 1 0 0 1 1 1 D IMM6 Vd 1 1 1 0 0 Q M 1 Vm VCVT<c>.F32.U32 <Qd>, <Qm>, #<fbits>
NEON 1 1 1 1 0 0 1 1 1 D IMM6 Vd 1 1 1 1 0 Q M 1 Vm VCVT<c>.U32.F32 <Qd>, <Qm>, #<fbits>
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <18> 1 <4>
NEON 1 1 1 1 0 0 1 0 1 D 1 1 Vn Vd IMM4 N Q M 0 Vm VEXT<c>.8 <Qd>, <Qn>, <Qm>, #<imm>
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=11 0 0 <4> 0 0 0 <2> <2> 0 <4>
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=10 0 0 <4> 0 0 0 <2>/11 <2> 0 <4>
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=10 0 0 <4> 0 0 0 <2>/01 <2> 0 <4>
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=01 0 0 <4> 0 0 0 <2>/11 <2> 0 <4>
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=00 0 0 <4> 0 0 0 <2>/=11 <2> 0 <4>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 0 0 @<2> Q M 0 Vm VREV\%d16 &l&l param\<c>.\%d8 &l&l size\ <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 0 1 0 U Q M 0 Vm VPADDL<c>.<dt> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 0 0 0 Q M 0 Vm VCLS<c>.<dt> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 0 0 1 Q M 0 Vm VCLZ<c>.<dt> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=00 0 0 Vd 0 1 0 1 0 Q M 0 Vm VCNT<c>.8 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=00 0 0 Vd 0 1 0 1 1 Q M 0 Vm VMVN<c> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 1 0 U Q M 0 Vm VPADAL<c>.<dt> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 1 1 0 Q M 0 Vm VQABS<c>.<dt> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 1 1 1 Q M 0 Vm VQNEG<c>.<dt> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 0 0 0 Q M 0 Vm VCGT<c>.<dt> <Qd>, <Qm>, #0
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 0 0 1 Q M 0 Vm VCGE<c>.<dt> <Qd>, <Qm>, #0
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 0 1 0 Q M 0 Vm VCEQ<c>.<dt> <Qd>, <Qm>, #0
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 0 1 1 Q M 0 Vm VCLE<c>.<dt> <Qd>, <Qm>, #0
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 1 0 0 Q M 0 Vm VCLT<c>.<dt> <Qd>, <Qm>, #0
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 1 1 0 Q M 0 Vm VABS<c>.<dt> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 1 1 1 Q M 0 Vm VNEG<c>.<dt> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=00 1 0 Vd 0 0 0 0 0 Q M 0 Vm VSWP<c> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 0 0 1 Q M 0 Vm VTRN<c>.\%d8 &l&l size\ <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 0 1 0 Q M 0 Vm VUZP<c>.\%d8 &l&l size\ <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 0 1 1 Q M 0 Vm VZIP<c>.\%d8 &l&l size\ <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 0 0 0 M 0 Vm VMOVN<c>.<dt> <Dd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 0 0 1 M 0 Vm VQMOVUN<c>.S\%d16 &l&l size\ <Dd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 0 1 U M 0 Vm @ set u = 1 - u@ set ++size@ @ VQMOVN<c>.<dt> <Dd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 1 0 0 M 0 Vm VSHLL<c>.I\%d8 &l&l size\ <Qd>, <Dm>, #\%d8 &l&l size\
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=01 1 0 Vd 0 1 1 0 0 0 M 0 Vm VCVT<c>.F16.F32 <Dd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=01 1 0 Vd 0 1 1 1 0 0 M 0 Vm VCVT<c>.F32.F16 <Qd>, <Dm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 1 Vd 0 1 0 F 0 Q M 0 Vm VRECPE<c>.<dt> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 1 Vd 0 1 0 F 1 Q M 0 Vm VRSQRTE<c>.<dt> <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=10 1 1 Vd 0 1 1 0 0 Q M 0 Vm VCVT<c>.F32.S32 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=10 1 1 Vd 0 1 1 0 1 Q M 0 Vm VCVT<c>.S32.F32 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=10 1 1 Vd 0 1 1 1 0 Q M 0 Vm VCVT<c>.F32.U32 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=10 1 1 Vd 0 1 1 1 1 Q M 0 Vm VCVT<c>.U32.F32 <Qd>, <Qm>
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <8> 0 <6> 0 <4>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 Vn Vd 1 0 @<2> N op M 0 Vm @ param=0b00 char list[10] !@ sprintf(list, %)@ "{%s}", vecname[0x20 + n]@ "{%s-%s}", vecname[0x20 + n], vecname[0x20 + n + param]@ @ VTB\(op ? "X" : "L")\<c>.8 <Dd>, \list\, <Dm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 imm4 Vd 1 1 0 0 0 Q M 0 Vm VDUP<c>.\%dsize\ <Qd>, <Dm[x]>
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <1> 1 1 <13> 0 <1> 0 <4>
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 0 0 0 Q N 0 M 0 Vm VADD\(q ? "W" : "L")\<c>.<dt> <qd>, <Qn>, <Dm>
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 0 0 1 Q N 0 M 0 Vm VSUB\(q ? "W" : "L")\<c>.<dt> <qd>, <Qn>, <Dm>
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 0 1 0 0 N 0 M 0 Vm @ set size = 16 << size@ @ VADDHN<c>.I\%dsize\ <Dd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D size Vn Vd 0 1 0 0 N 0 M 0 Vm VRADDHN<c>.<dt> <Dd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 0 1 0 1 N 0 M 0 Vm VABAL<c>.<dt> <Qd>, <Dn>, <Dm>
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 0 1 1 0 N 0 M 0 Vm VSUBHN<c>.<dt> <Dd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D size Vn Vd 0 1 1 0 N 0 M 0 Vm VRSUBHN<c>.<dt> <Dd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 0 1 1 1 N 0 M 0 Vm VABDL<c>.<dt> <Qd>, <Dn>, <Dm>
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 1 0 op 0 N 0 M 0 Vm VML\(op ? "S" : "A")\L<c>.<dt> <Qd>, <Dn>, <Dm>
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 1 0 op 1 N 0 M 0 Vm VQDML\(op ? "S" : "A")\L<c>.<dt> <Qd>, <Dn>, <Dm>
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 1 1 0 0 N 0 M 0 Vm VMULL<c>.<dt> <Qd>, <Dn>, <Dm>
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 1 1 0 1 N 0 M 0 Vm VQDMULL<c>.<dt> <Qd>, <Dn>, <Dm>
NEON 1 1 1 1 0 0 1 U/=0 1 D size/=00 Vn Vd 1 1 1 0 N 0 M 0 Vm @ set uint8_t size = 0@ @ VMULL<c>.<dt> <Qd>, <Dn>, <Dm>
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <16> 0 <1> 0 <4>
NEON 1 1 1 1 0 0 1 Q 1 D size Vn Vd 0 op 0 F N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VML\(op ? "S" : "A")\<c>.<dt> <Qd>, <Qn>, <Dm[x]>
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 0 op 1 0 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VML\(op ? "S" : "A")\L<c>.<dt> <Qd>, <Dn>, <Dm[x]>
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 0 op 1 1 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VQDML\(op ? "S" : "A")\L<c>.<dt> <Qd>, <Dn>, <Dm[x]>
NEON 1 1 1 1 0 0 1 Q 1 D size Vn Vd 1 0 0 F N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VMUL<c>.<dt> <Qd>, <Qn>, <Dm[x]>
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 1 0 1 0 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VMULL<c>.<dt> <Qd>, <Qn>, <Dm[x]>
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 1 0 1 1 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VQDMULL<c>.<dt> <Qd>, <Qn>, <Dm[x]>
NEON 1 1 1 1 0 0 1 Q 1 D size Vn Vd 1 1 0 0 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VQDMULH<c>.<dt> <Qd>, <Qn>, <Dm[x]>
NEON 1 1 1 1 0 0 1 Q 1 D size Vn Vd 1 1 0 1 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VQRDMULH<c>.<dt> <Qd>, <Qn>, <Dm[x]>
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <16> 0 <1> 0 <4>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 0 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 1 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 0 0 <8> 1 1 <10>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 0 @<4> 1 1 1 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 0 @<4> 1 1 0 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 0 @<4> Rm @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> Rm @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 0 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 1 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 1 0 <8> 1 1 <10>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> 1 1 1 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> 1 1 0 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> Rm @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> Rm @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
INVALIDATE 1 1 1 1 0 1 0 0 <3> 0 <20>
INVALIDATE 1 1 1 1 <28>
ARMS cond 0 0 0 0 0 0 0 S Rn Rd imm5 type 0 Rm AND{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 0 0 0 0 S Rd (0) (0) (0) (0) Rm 1 0 0 1 Rn MUL{S}<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 0 0 0 U 0 0 0 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm STRH<c> <Rt>, [<Rn>], +/-<Rm>
ARM_ cond 0 0 0 0 U 0 0 0 Rn Rt (0) (0) (0) (0) 1 1 0 1 Rm LDRD<c> <Rt>, <Rt2>, [<Rn>], +/-<Rm>
ARM_ cond 0 0 0 0 U 0 0 0 Rn Rt (0) (0) (0) (0) 1 1 1 1 Rm STRD<c> <Rt>, <Rt2>, [<Rn>], +/-<Rm>
ARM_ cond 0 0 0 0 U 0 0 1 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm LDRH<c> <Rt>, [<Rn>], +/-<Rm>
ARM_ cond 0 0 0 0 U 0 0 1 Rn Rt (0) (0) (0) (0) 1 1 0 1 Rm LDRSB<c> <Rt>, [<Rn>], +/-<Rm>
ARM_ cond 0 0 0 0 U 0 0 1 Rn Rt (0) (0) (0) (0) 1 1 1 1 Rm LDRSH<c> <Rt>, [<Rn>], +/-<Rm>
ARMS cond 0 0 0 0 0 0 1 S Rn Rd imm5 type 0 Rm EOR{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 0 0 0 1 S Rd Ra Rm 1 0 0 1 Rn MLA{S}<c> <Rd>, <Rn>, <Rm>, <Ra>
ARM_ cond 0 0 0 0 U 0 1 0 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm STRHT<c> <Rt>, [<Rn>], +/-<Rm>
ARM_ cond 0 0 0 0 U 0 1 1 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm LDRHT<c> <Rt>, [<Rn>], +/-<Rm>
ARM_ cond 0 0 0 0 U 0 1 1 Rn Rt (0) (0) (0) (0) 1 1 0 1 Rm LDRSBT<c> <Rt>, [<Rn>], +/-<Rm>
ARM_ cond 0 0 0 0 U 0 1 1 Rn Rt (0) (0) (0) (0) 1 1 1 1 Rm LDRSHT<c> <Rt>, [<Rn>], +/-<Rm>
ARMS cond 0 0 0 0 0 1 0 S Rn Rd imm5 type 0 Rm SUB{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 0 0 1 0 0 RdHi RdLo Rm 1 0 0 1 Rn UMAAL<c> <RdLo>, <RdHi>, <Rn>, <Rm>
ARM_ cond 0 0 0 0 U 1 0 0 Rn Rt imm4H 1 0 1 1 imm4L STRH<c> <Rt>, [<Rn>], #+/-<imm8>
ARM_ cond 0 0 0 0 U 1 0 0 Rn Rt imm4H 1 1 0 1 imm4L LDRD<c> <Rt>, <Rt2>, [<Rn>], #+/-<imm8>
ARM_ cond 0 0 0 0 U 1 0 0 Rn Rt imm4H 1 1 1 1 imm4L STRD<c> <Rt>, <Rt2>, [<Rn>], #+/-<imm8>
ARM_ cond 0 0 0 0 U 1 0 1 Rn Rt imm4H 1 0 1 1 imm4L LDRH<c> <Rt>, [<Rn>], #+/-<imm8>
ARM_ cond 0 0 0 0 U 1 0 1 Rn Rt imm4H 1 1 0 1 imm4L LDRSB<c> <Rt>, [<Rn>], #+/-<imm8>
ARM_ cond 0 0 0 0 U 1 0 1 Rn Rt imm4H 1 1 1 1 imm4L LDRSH<c> <Rt>, [<Rn>], #+/-<imm8>
ARMS cond 0 0 0 0 0 1 1 S Rn Rd imm5 type 0 Rm RSB{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 0 0 1 1 0 Rd Ra Rm 1 0 0 1 Rn MLS<c> <Rd>, <Rn>, <Rm>, <Ra>
ARM_ cond 0 0 0 0 U 1 1 0 Rn Rt imm4H 1 0 1 1 imm4L STRHT<c> <Rt>, [<Rn>], #+/-<imm8>
ARM_ cond 0 0 0 0 U 1 1 1 Rn Rt imm4H 1 0 1 1 imm4L LDRHT<c> <Rt>, [<Rn>], #+/-<imm8>
ARM_ cond 0 0 0 0 U 1 1 1 Rn Rt imm4H 1 1 0 1 imm4L LDRSBT<c> <Rt>, [<Rn>], #+/-<imm8>
ARM_ cond 0 0 0 0 U 1 1 1 Rn Rt imm4H 1 1 1 1 imm4L LDRSHT<c> <Rt>, [<Rn>], #+/-<imm8>
ARMS cond 0 0 0 0 1 0 0 S Rn Rd imm5 type 0 Rm ADD{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 0 1 0 0 S RdHi RdLo Rm 1 0 0 1 Rn UMULL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
ARMS cond 0 0 0 0 1 0 1 S Rn Rd imm5 type 0 Rm ADC{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 0 1 0 1 S RdHi RdLo Rm 1 0 0 1 Rn UMLAL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
ARMS cond 0 0 0 0 1 1 0 S Rn Rd imm5 type 0 Rm SBC{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 0 1 1 0 S RdHi RdLo Rm 1 0 0 1 Rn SMULL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
ARMS cond 0 0 0 0 1 1 1 S Rn Rd imm5 type 0 Rm RSC{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 0 1 1 1 S RdHi RdLo Rm 1 0 0 1 Rn SMLAL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
ARM_ cond 0 0 0 1 0 0 0 0 Rd Ra Rm 1 0 0 0 Rn SMLABB<c> <Rd>, <Rn>, <Rm>, <Ra>
ARM_ cond 0 0 0 1 0 0 0 0 Rd Ra Rm 1 0 1 0 Rn SMLATB<c> <Rd>, <Rn>, <Rm>, <Ra>
ARM_ cond 0 0 0 1 0 0 0 0 Rd Ra Rm 1 1 0 0 Rn SMLABT<c> <Rd>, <Rn>, <Rm>, <Ra>
ARM_ cond 0 0 0 1 0 0 0 0 Rd Ra Rm 1 1 1 0 Rn SMLATT<c> <Rd>, <Rn>, <Rm>, <Ra>
ARM_ cond 0 0 0 1 0 0 0 0 Rn Rt (0) (0) (0) (0) 1 0 0 1 Rm SWP<c> <Rt>, <Rm>, [<Rn>]
ARM_ cond 0 0 0 1 U 0 W 0 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm STRH<c> <Rt>, [<Rn>, +/-<Rm>]{!}
ARM_ cond 0 0 0 1 U 0 W 0 Rn Rt (0) (0) (0) (0) 1 1 0 1 Rm LDRD<c> <Rt>, <Rt2>, [<Rn>, +/-<Rm>]{!}
ARM_ cond 0 0 0 1 U 0 W 0 Rn Rt (0) (0) (0) (0) 1 1 1 1 Rm STRD<c> <Rt>, <Rt2>, [<Rn>, +/-<Rm>]{!}
ARMS cond 0 0 0 1 0 0 0 1 Rn (0) (0) (0) (0) imm5 type 0 Rm TST<c> <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 1 U 0 W 1 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm LDRH<c> <Rt>, [<Rn>, +/-<Rm>]{!}
ARM_ cond 0 0 0 1 U 0 W 1 Rn Rt (0) (0) (0) (0) 1 1 0 1 Rm LDRSB<c> <Rt>, [<Rn>, +/-<Rm>]{!}
ARM_ cond 0 0 0 1 U 0 W 1 Rn Rt (0) (0) (0) (0) 1 1 1 1 Rm LDRSH<c> <Rt>, [<Rn>, +/-<Rm>]{!}
ARM_ cond 0 0 0 1 0 0 1 0 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) 0 0 0 1 Rm BX<c> <Rm>
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 0 Rm BXJ<c> <Rm>
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 1 Rm BLX<c> <Rm>
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 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>]{!}
ARMS cond 0 0 0 1 0 1 0 1 Rn (0) (0) (0) (0) imm5 type 0 Rm CMP<c> <Rn>, <Rm>{, <shift>}
ARMS cond 0 0 0 1 0 1 1 1 Rn (0) (0) (0) (0) imm5 type 0 Rm CMN<c> <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 1 U 1 W 1 Rn Rt imm4H 1 0 1 1 imm4L LDRH<c> <Rt>, [<Rn>, #+/-<imm8>]{!}
ARM_ cond 0 0 0 1 U 1 W 1 Rn Rt imm4H 1 1 0 1 imm4L LDRSB<c> <Rt>, [<Rn>, #+/-<imm8>]{!}
ARM_ cond 0 0 0 1 U 1 W 1 Rn Rt imm4H 1 1 1 1 imm4L LDRSH<c> <Rt>, [<Rn>, #+/-<imm8>]{!}
ARMS cond 0 0 0 1 1 0 0 S Rn Rd imm5 type 0 Rm ORR{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 1 1 0 0 0 Rn Rd (1) (1) (1) (1) 1 0 0 1 Rt STREX<c> <Rd>, <Rt>, [<Rn>]
ARM_ cond 0 0 0 1 1 0 0 1 Rn Rt (1) (1) (1) (1) 1 0 0 1 (1) (1) (1) (1) LDREX<c> <Rt>, [<Rn>]
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd 0 0 0 0 0 0 0 0 Rm MOV{S}<c> <Rd>, <Rm>
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd imm5 0 0 0 Rm LSL{S}<c> <Rd>, <Rm>, #<imm>
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd Rm 0 0 0 1 Rn LSL{S}<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd imm5 0 1 0 Rm LSR{S}<c> <Rd>, <Rm>, #<imm>
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd Rm 0 0 1 1 Rn LSR{S}<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd imm5 1 0 0 Rm ASR{S}<c> <Rd>, <Rm>, #<imm>
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd Rm 0 1 0 1 Rn ASR{S}<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd 0 0 0 0 0 1 1 0 Rm RRX{S}<c> <Rd>, <Rm>
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd imm5 1 1 0 Rm ROR{S}<c> <Rd>, <Rm>, #<imm>
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd Rm 0 1 1 1 Rn ROR{S}<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 0 0 1 1 0 1 0 Rn Rd (1) (1) (1) (1) 1 0 0 1 Rt STREXD<c> <Rd>, <Rt>, <Rt2>, [<Rn>]
ARM_ cond 0 0 0 1 1 0 1 1 Rn Rt (1) (1) (1) (1) 1 0 0 1 (1) (1) (1) (1) LDREXD<c> <Rt>, <Rt2>, [<Rn>]
ARMS cond 0 0 0 1 1 1 0 S Rn Rd imm5 type 0 Rm BIC{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 1 1 1 0 0 Rn Rd (1) (1) (1) (1) 1 0 0 1 Rt STREXB<c> <Rd>, <Rt>, [<Rn>]
ARM_ cond 0 0 0 1 1 1 0 1 Rn Rt (1) (1) (1) (1) 1 0 0 1 (1) (1) (1) (1) LDREXB<c> <Rt>, [<Rn>]
ARMS cond 0 0 0 1 1 1 1 S (0) (0) (0) (0) Rd imm5 type 0 Rm MVN{S}<c> <Rd>, <Rm>{, <shift>}
ARM_ cond 0 0 0 1 1 1 1 0 Rn Rd (1) (1) (1) (1) 1 0 0 1 Rt STREXH<c> <Rd>, <Rt>, [<Rn>]
ARM_ cond 0 0 0 1 1 1 1 1 Rn Rt (1) (1) (1) (1) 1 0 0 1 (1) (1) (1) (1) LDREXH<c> <Rt>, [<Rn>]
ARM_ cond 0 0 1 0 0 0 0 S Rn Rd imm12 AND{S}<c> <Rd>, <Rn>, #<const>
ARM_ cond 0 0 1 0 0 0 1 S Rn Rd imm12 EOR{S}<c> <Rd>, <Rn>, #<const>
ARM_ cond 0 0 1 0 0 1 0 S Rn Rd imm12 SUB{S}<c> <Rd>, <Rn>, #<const>
ARM_ cond 0 0 1 0 0 1 1 S Rn Rd imm12 RSB{S}<c> <Rd>, <Rn>, #<const>
ARM_ cond 0 0 1 0 1 0 0 S Rn Rd imm12 ADD{S}<c> <Rd>, <Rn>, #<const>
ARM_ cond 0 0 1 0 1 0 1 S Rn Rd imm12 ADC{S}<c> <Rd>, <Rn>, #<const>
ARM_ cond 0 0 1 0 1 1 0 S Rn Rd imm12 SBC{S}<c> <Rd>, <Rn>, #<const>
ARM_ cond 0 0 1 0 1 1 1 S Rn Rd imm12 RSC{S}<c> <Rd>, <Rn>, #<const>
ARM_ cond 0 0 1 1 0 0 0 0 imm4 Rd imm12 MOVW<c> <Rd>, #<imm16>
ARM_ cond 0 0 1 1 0 0 0 1 Rn (0) (0) (0) (0) imm12 TST<c> <Rn>, #<const>
ARM_ cond 0 0 1 1 0 0 1 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 0 0 0 0 0 NOP<c>
ARM_ cond 0 0 1 1 0 0 1 1 Rn (0) (0) (0) (0) imm12 TEQ<c> <Rn>, #<const>
ARM_ cond 0 0 1 1 0 1 0 0 imm4 Rd imm12 MOVT<c> <Rd>, #<imm16>
ARM_ cond 0 0 1 1 0 1 0 1 Rn (0) (0) (0) (0) imm12 CMP<c> <Rn>, #<const>
ARM_ cond 0 0 1 1 0 1 1 1 Rn (0) (0) (0) (0) imm12 CMN<c> <Rn>, #<const>
ARM_ cond 0 0 1 1 1 0 0 S Rn Rd imm12 ORR{S}<c> <Rd>, <Rn>, #<const>
ARM_ cond 0 0 1 1 1 0 1 S (0) (0) (0) (0) Rd imm12 MOV{S}<c> <Rd>, #<const>
ARM_ cond 0 0 1 1 1 1 0 S Rn Rd imm12 BIC{S}<c> <Rd>, <Rn>, #<const>
ARM_ cond 0 0 1 1 1 1 1 S (0) (0) (0) (0) Rd imm12 MVN{S}<c> <Rd>, #<const>
ARM_ cond 0 1 0 0 1 0 0 1 1 1 0 1 Rt 0 0 0 0 0 0 0 0 0 1 0 0 POP<c> {<Rt>}
ARM_ cond 0 1 0 0 U 0 0 0 Rn Rt imm12 STR<c> <Rt>, [<Rn>], #+/-<imm12>
ARM_ cond 0 1 0 0 U 0 0 1 Rn Rt imm12 LDR<c> <Rt>, [<Rn>], #+/-<imm12>
ARM_ cond 0 1 0 0 U 0 1 0 Rn Rt imm12 STRT<c> <Rt>, [<Rn>], #+/-<imm12>
ARM_ cond 0 1 0 0 U 0 1 1 Rn Rt imm12 LDRT<c> <Rt>, [<Rn>], #+/-<imm12>
ARM_ cond 0 1 0 0 U 1 0 0 Rn Rt imm12 STRB<c> <Rt>, [<Rn>], #+/-<imm12>
ARM_ cond 0 1 0 0 U 1 0 1 Rn Rt imm12 LDRB<c> <Rt>, [<Rn>], #+/-<imm12>
ARM_ cond 0 1 0 0 U 1 1 0 Rn Rt imm12 STRBT<c> <Rt>, [<Rn>], #+/-<imm12>
ARM_ cond 0 1 0 0 U 1 1 1 Rn Rt imm12 LDRBT<c> <Rt>, [<Rn>], #+/-<imm12>
ARM_ cond 0 1 0 1 0 0 1 0 1 1 0 1 Rt 0 0 0 0 0 0 0 0 0 1 0 0 PUSH<c> {<Rt>}
ARM_ cond 0 1 0 1 U 0 W 0 Rn Rt imm12 STR<c> <Rt>, [<Rn>, #+/-<imm12>]{!}
ARM_ cond 0 1 0 1 U 0 W 1 Rn Rt imm12 LDR<c> <Rt>, [<Rn>, #+/-<imm12>]{!}
ARM_ cond 0 1 0 1 U 1 W 0 Rn Rt imm12 STRB<c> <Rt>, [<Rn>, #+/-<imm12>]{!}
ARM_ cond 0 1 0 1 U 1 W 1 Rn Rt imm12 LDRB<c> <Rt>, [<Rn>, #+/-<imm12>]{!}
ARM_ cond 0 1 1 0 0 0 0 1 Rn Rd (1) (1) (1) (1) 0 1 0 1 Rm SSAX<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 1 1 0 0 0 0 1 Rn Rd (1) (1) (1) (1) 0 1 1 1 Rm SSUB16<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 1 1 0 0 0 0 1 Rn Rd (1) (1) (1) (1) 1 1 1 1 Rm SSUB8<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 1 1 0 0 1 0 1 Rn Rd (1) (1) (1) (1) 0 1 0 1 Rm USAX<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 1 1 0 0 1 0 1 Rn Rd (1) (1) (1) (1) 0 1 1 1 Rm USUB16<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 1 1 0 0 1 0 1 Rn Rd (1) (1) (1) (1) 1 1 1 1 Rm USUB8<c> <Rd>, <Rn>, <Rm>
ARMs cond 0 1 1 0 1 0 0 0 Rn Rd imm5 0 0 1 Rm PKHBT<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARMs cond 0 1 1 0 1 0 0 0 Rn Rd imm5 1 0 1 Rm PKHTB<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 1 1 0 1 0 0 0 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm SXTB16<c> <Rd>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 0 0 0 Rn Rd rotate (0) (0) 0 1 1 1 Rm SXTAB16<c> <Rd>, <Rn>, <Rm>{, <rotation>}
ARMs cond 0 1 1 0 1 0 1 sat_imm Rd imm5 sh 0 1 Rn SSAT<c> <Rd>, #<imm>, <Rn>{, <shift>}
ARM_ cond 0 1 1 0 1 0 1 0 sat_imm Rd (1) (1) (1) (1) 0 0 1 1 Rn SSAT16<c> <Rd>, #<imm>, <Rn>
ARM_ cond 0 1 1 0 1 0 1 0 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm SXTB<c> <Rd>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 0 1 0 Rn Rd rotate (0) (0) 0 1 1 1 Rm SXTAB<c> <Rd>, <Rn>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 0 1 1 (1) (1) (1) (1) Rd (1) (1) (1) (1) 0 0 1 1 Rm REV<c> <Rd>, <Rm>
ARM_ cond 0 1 1 0 1 0 1 1 (1) (1) (1) (1) Rd (1) (1) (1) (1) 1 0 1 1 Rm REV16<c> <Rd>, <Rm>
ARM_ cond 0 1 1 0 1 0 1 1 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm SXTH<c> <Rd>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 0 1 1 Rn Rd rotate (0) (0) 0 1 1 1 Rm SXTAH<c> <Rd>, <Rn>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 1 0 0 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm UXTB16<c> <Rd>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 1 0 0 Rn Rd rotate (0) (0) 0 1 1 1 Rm UXTAB16<c> <Rd>, <Rn>, <Rm>{, <rotation>}
ARMs cond 0 1 1 0 1 1 1 sat_imm Rd imm5 sh 0 1 Rn USAT<c> <Rd>, #<imm>, <Rn>{, <shift>}
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 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>}
ARMs cond 0 1 1 0 U 0 0 0 Rn Rt imm5 type 0 Rm STR<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
ARMs cond 0 1 1 0 U 0 0 1 Rn Rt imm5 type 0 Rm LDR<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
ARMs cond 0 1 1 0 U 0 1 0 Rn Rt imm5 type 0 Rm STRT<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
ARMs cond 0 1 1 0 U 0 1 1 Rn Rt imm5 type 0 Rm LDRT<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
ARMs cond 0 1 1 0 U 1 0 0 Rn Rt imm5 type 0 Rm STRB<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
ARMs cond 0 1 1 0 U 1 0 1 Rn Rt imm5 type 0 Rm LDRB<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
ARMs cond 0 1 1 0 U 1 1 0 Rn Rt imm5 type 0 Rm STRBT<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
ARMs cond 0 1 1 0 U 1 1 1 Rn Rt imm5 type 0 Rm LDRBT<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
ARMs cond 0 1 1 1 U 0 W 0 Rn Rt imm5 type 0 Rm STR<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
ARMs cond 0 1 1 1 U 0 W 1 Rn Rt imm5 type 0 Rm LDR<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
ARMs cond 0 1 1 1 U 1 W 0 Rn Rt imm5 type 0 Rm STRB<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
ARMs cond 0 1 1 1 U 1 W 1 Rn Rt imm5 type 0 Rm LDRB<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
ARM_ cond 0 1 1 1 1 0 0 0 Rd 1 1 1 1 Rm 0 0 0 1 Rn USAD8<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 1 1 1 1 0 0 0 Rd Ra Rm 0 0 0 1 Rn USADA8<c> <Rd>, <Rn>, <Rm>, <Ra>
ARM_ cond 0 1 1 1 1 1 0 msb Rd lsb 0 0 1 1 1 1 1 BFC<c> <Rd>, #<lsb>, #<width>
ARM_ cond 0 1 1 1 1 1 0 msb Rd lsb 0 0 1 Rn BFI<c> <Rd>, <Rn>, #<lsb>, #<width>
ARM_ cond 0 1 1 1 1 1 1 widthm1 Rd lsb 1 0 1 Rn UBFX<c> <Rd>, <Rn>, #<lsb>, #<width>
ARM_ cond 1 0 0 0 0 0 W 0 Rn/=1101 register_list STMED<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 0 0 0 W 0 Rn register_list STMDA<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 0 0 0 W 1 Rn/=1101 register_list LDMED<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 0 0 0 W 1 Rn register_list LDMDA<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 0 1 0 W 0 Rn/=1101 register_list STMEA<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 0 1 0 W 0 Rn register_list STM<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 0 1 0 0 1 Rn/=1101 register_list LDMEA<c> <Rn>, <registers>
ARM_ cond 1 0 0 0 1 0 1 1 1 1 0 1 register_list @ = const char* op @@ (reglist != 0) && ((reglist & (reglist - 1)) == 0)@ op,"POP","LDMEA"@ @ \op\<c> <registers>
ARM_ cond 1 0 0 0 1 0 W 1 Rn register_list LDM<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 1 0 0 0 0 Rn/=1101 register_list STMFD<c> <Rn>, <registers>
ARM_ cond 1 0 0 1 0 0 1 0 1 1 0 1 register_list @ = const char* op @@ (reglist != 0) && ((reglist & (reglist - 1)) == 0)@ op,"PUSH","STMFD"@ @ \op\<c> <registers>
ARM_ cond 1 0 0 1 0 0 W 0 Rn register_list STMDB<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 1 0 0 W 1 Rn/=1101 register_list LDMFD<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 1 0 0 W 1 Rn register_list LDMDB<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 1 1 0 W 0 Rn/=1101 register_list STMFA<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 1 1 0 W 0 Rn register_list STMIB<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 1 1 0 W 1 Rn/=1101 register_list LDMFA<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 1 1 0 W 1 Rn register_list LDMIB<c> <Rn>{!}, <registers>
ARM_ cond 1 0 1 0 imm24 B<c> <label>
ARM_ cond 1 0 1 1 imm24 BL<c> <label>
VFPU cond 1 1 0 0 0 1 0 0 Rn Rt 1 0 1 0 0 0 M 1 Vm VMOV<c> <Sm>, <Sm1>, <Rt>, <Rn>
VFPU cond 1 1 0 0 0 1 0 1 Rn Rt 1 0 1 0 0 0 M 1 Vm VMOV<c> <Rt>, <Rn>, <Sm>, <Sm1>
VFPU cond 1 1 0 0 0 1 0 0 Rn Rt 1 0 1 1 0 0 M 1 Vm VMOV<c> <Dm>, <Rt>, <Rn>
VFPU cond 1 1 0 0 0 1 0 1 Rn Rt 1 0 1 1 0 0 M 1 Vm VMOV<c> <Rt>, <Rn>, <Dm>
INVALIDATE <4> 1 1 0 0 0 <11> 1 0 1 <9>
INVALIDATE <4> 1 1 0 0 0 <11> 1 0 1 <9>
INVALIDATE <4> 1 1 0 1 1 <1> 1 <9> 1 0 1 <9>
INVALIDATE <4> 1 1 0 1 1 <1> 1 <9> 1 0 1 <9>
VFPU cond 1 1 0 1 0 D 1 0 1 1 0 1 Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FSTMX<c> <LIst>
VFPU cond 1 1 0 1 0 D 1 0 1 1 0 1 Vd 1 0 1 sz imm8 VPUSH<c> <list>
VFPU cond 1 1 0 1 U D 0 0 Rn Vd 1 0 1 sz imm8 VSTR<c> <Dd>, [<Rn>{, #+/-<imm>}]
VFPU cond 1 1 0 @<2> D W 0 Rn Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FSTM\(param == 0b01 ? "IA" : "DB")\X<c> <Rn>{!}, <LIst>
VFPU cond 1 1 0 @<2> D W 0 Rn Vd 1 0 1 sz imm8 VSTM\(param == 0b01 ? "IA" : "DB")\<c> <Rn>{!}, <list>
VFPU cond 1 1 0 0 1 D 1 1 1 1 0 1 Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FLDMX<c> <LIst>
VFPU cond 1 1 0 0 1 D 1 1 1 1 0 1 Vd 1 0 1 sz imm8 VPOP<c> <list>
VFPU cond 1 1 0 1 0 D 0 1 1 1 1 1 Vd 1 0 1 sz 0 0 0 0 0 0 0 0 VLDR<c> <Dd>, [PC, #-0]
VFPU cond 1 1 0 1 U D 0 1 1 1 1 1 Vd 1 0 1 sz imm8 VLDR<c> <Dd>, <label>
VFPU cond 1 1 0 1 U D 0 1 Rn Vd 1 0 1 sz imm8 VLDR<c> <Dd>, [<Rn>{, #+/-<imm>}]
VFPU cond 1 1 0 @<2> D W 1 Rn Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FLDM\(param == 0b01 ? "IA" : "DB")\X<c> <Rn>{!}, <LIst>
VFPU cond 1 1 0 @<2> D W 1 Rn Vd 1 0 1 sz imm8 VLDM\(param == 0b01 ? "IA" : "DB")\<c> <Rn>{!}, <list>
INVALIDATE <4> 1 1 0 <25>
INVALIDATE <4> 1 1 1 0 0 0 <1> 0 <8> 1 0 1 1 <1> 1 0 1 (0) (0) (0) (0)
VFPU cond 1 1 1 0 0 0 0 0 Vn Rt 1 0 1 0 N (0) (0) 1 (0) (0) (0) (0) VMOV<c> <Sn>, <Rt>
VFPU cond 1 1 1 0 1 1 1 0 0 0 0 1 Rt 1 0 1 0 (0) (0) (0) 1 (0) (0) (0) (0) VMSR<c> FPSCR, <Rt>
VFPU cond 1 1 1 0 0 @<2> 0 Vd Rt 1 0 1 1 D @<2> 1 (0) (0) (0) (0) @ set uint8_t opc = (param1_2 << 2) + param2_2@ = uint8_t shift @@ (opc & 0b1000) == 0b1000@ @@ (opc & 0b1001) == 0b0001@ @@ (opc & 0b1011) == 0b0000@ shift,0,1,2,0xFF@ set uint8_t decodedImm = (opc & 0x7) >> shift@ @ VMOV<c>.\%d8 &l&l shift\ <Dd[x]>, <Rt>
VFPU cond 1 1 1 0 1 0 Q 0 Vd Rt 1 0 1 1 D 0 0 1 (0) (0) (0) (0) VDUP<c>.32 <Qd>, <Rt>
VFPU cond 1 1 1 0 1 0 Q 0 Vd Rt 1 0 1 1 D 0 1 1 (0) (0) (0) (0) VDUP<c>.16 <Qd>, <Rt>
VFPU cond 1 1 1 0 1 1 Q 0 Vd Rt 1 0 1 1 D 0 0 1 (0) (0) (0) (0) VDUP<c>.8 <Qd>, <Rt>
VFPU cond 1 1 1 0 0 0 0 1 Vn Rt 1 0 1 0 N (0) (0) 1 (0) (0) (0) (0) VMOV<c> <Rt>, <Sn>
VFPU cond 1 1 1 0 1 1 1 1 0 0 0 1 Rt 1 0 1 0 (0) (0) (0) 1 (0) (0) (0) (0) VMRS<c> <Rt>, FPSCR
VFPU cond 1 1 1 0 U @<2> 1 Vn Rt 1 0 1 1 N @<2> 1 (0) (0) (0) (0) @ set uint8_t opc = (u << 3) + (param1_2 << 2) + param2_2@ = uint8_t shift, size @@ (opc & 0b01000) == 0b01000@ @@ (opc & 0b01001) == 0b00001@ @@ (opc & 0b11011) == 0b00000@ shift,0,1,2,0xFF;size,0,1,2,4@ set uint8_t decodedImm = (opc & 0x7) >> shift@ @ VMOV<c>.<dt> <Rt>, <Dn[x]>
INVALIDATE <4> 1 1 1 0 <12> 1 0 1 <4> 1 <4>
VFPU cond 1 1 1 0 0 D 0 0 Vn Vd 1 0 1 sz N op M 0 Vm VML\(op ? "S" : "A")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
VFPU cond 1 1 1 0 0 D 0 1 Vn Vd 1 0 1 sz N op M 0 Vm VNML\(op ? "S" : "A")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
VFPU cond 1 1 1 0 0 D 1 0 Vn Vd 1 0 1 sz N 0 M 0 Vm VMUL<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
VFPU cond 1 1 1 0 0 D 1 0 Vn Vd 1 0 1 sz N 1 M 0 Vm VNMUL<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
VFPU cond 1 1 1 0 0 D 1 1 Vn Vd 1 0 1 sz N 0 M 0 Vm VADD<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
VFPU cond 1 1 1 0 0 D 1 1 Vn Vd 1 0 1 sz N 1 M 0 Vm VSUB<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
VFPU cond 1 1 1 0 1 D 0 0 Vn Vd 1 0 1 sz N 0 M 0 Vm VDIV<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
VFPU cond 1 1 1 0 1 D 0 1 Vn Vd 1 0 1 sz N op M 0 Vm VFNM\(op ? "A" : "S")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
VFPU cond 1 1 1 0 1 D 1 0 Vn Vd 1 0 1 sz N op M 0 Vm VFM\(op ? "S" : "A")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
VFPU cond 1 1 1 0 1 D 1 1 @<4> Vd 1 0 1 0 (0) 0 (0) 0 @<4> @ set int8_t sign = (param1_4 >> 3) ? -1 : 1@ set uint8_t exp = ((param1_4 & 0b111) ^ 0b100)@ set float mantissa = 16 + param2_4@ set float imm = sign * (1 << exp) * mantissa / 128.@ @ VMOV<c>.F32 <Sd>, #\%fimm\
VFPU cond 1 1 1 0 1 D 1 1 @<4> Vd 1 0 1 1 (0) 0 (0) 0 @<4> @ set int8_t sign = (param1_4 >> 3) ? -1 : 1@ set uint8_t exp = ((param1_4 & 0b111) ^ 0b100)@ set double mantissa = 16 + param2_4@ set double imm = sign * (1 << exp) * mantissa / 128.@ @ VMOV<c>.F64 <Dd>, #\%fimm\
VFPU cond 1 1 1 0 1 D 1 1 0 0 0 0 Vd 1 0 1 sz 0 1 M 0 Vm VMOV<c>.F\(size ? "64" : "32")\ <Dd>, <Dm>
VFPU cond 1 1 1 0 1 D 1 1 0 0 0 0 Vd 1 0 1 sz 1 1 M 0 Vm VABS<c>.F\(size ? "64" : "32")\ <Dd>, <Dm>
VFPU cond 1 1 1 0 1 D 1 1 0 0 0 1 Vd 1 0 1 sz 0 1 M 0 Vm VNEG<c>.F\(size ? "64" : "32")\ <Dd>, <Dm>
VFPU cond 1 1 1 0 1 D 1 1 0 0 0 1 Vd 1 0 1 sz 1 1 M 0 Vm VSQRT<c>.F\(size ? "64" : "32")\ <Dd>, <Dm>
VFPU cond 1 1 1 0 1 D 1 1 0 0 1 0 Vd 1 0 1 (0) @<1> 1 M 0 Vm VCVT\(param ? "T" : "B")\<c>.F32.F16 <Sd>, <Sm>
VFPU cond 1 1 1 0 1 D 1 1 0 0 1 1 Vd 1 0 1 (0) @<1> 1 M 0 Vm VCVT\(param ? "T" : "B")\<c>.F16.F32 <Sd>, <Sm>
VFPU cond 1 1 1 0 1 D 1 1 0 1 0 0 Vd 1 0 1 sz op 1 M 0 Vm VCMP\(op ? "E" : "")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dm>
VFPU cond 1 1 1 0 1 D 1 1 0 1 0 1 Vd 1 0 1 sz op 1 (0) 0 (0) (0) (0) (0) VCMP\(op ? "E" : "")\<c>.F\(size ? "64" : "32")\ <Dd>, #0.0
VFPU cond 1 1 1 0 1 D 1 1 0 1 1 1 Vd 1 0 1 0 1 1 M 0 Vm VCVT<c>.F64.F32 <Dd>, <Sm>
VFPU cond 1 1 1 0 1 D 1 1 0 1 1 1 Vd 1 0 1 1 1 1 M 0 Vm VCVT<c>.F32.F64 <Sd>, <Dm>
VFPU cond 1 1 1 0 1 D 1 1 1 0 0 0 Vd 1 0 1 sz op 1 M 0 Vm VCVT<c>.F\(size ? "64" : "32")\.\(op ? "S" : "U")\32 <Dd>, <Sm>
VFPU cond 1 1 1 0 1 D 1 1 1 0 1 U Vd 1 0 1 sz op 1 i 0 imm4 @ set uint8_t td = (u << 2) + op + 1@ td=0b001=0b010=0b101 const char* Td Td,"S16","U16","S32","U32"@ set imm5 = (16 << op) - (imm5 >> 4) - ((imm5 & 0xF) << 1)@ @ VCVT<c>.F\(size ? "64" : "32")\.\Td\ <Dd>, <Dd>, #<imm>
VFPU cond 1 1 1 0 1 D 1 1 1 1 0 U Vd 1 0 1 sz op 1 M 0 Vm VCVT\(op ? "" : "R")\<c>.\(u ? "U" : "S")\32.F\(size ? "64" : "32")\ <Sd>, <Dm>
VFPU cond 1 1 1 0 1 D 1 1 1 1 1 U Vd 1 0 1 sz op 1 i 0 imm4 @ set uint8_t td = (u << 2) + op + 1@ td=0b001=0b010=0b101 const char* Td Td,"S16","U16","S32","U32"@ set imm5 = (16 << op) - (imm5 >> 4) - ((imm5 & 0xF) << 1)@ @ VCVT<c>.\Td\.F\(size ? "64" : "32")\ <Dd>, <Dd>, #<imm>
INVALIDATE <32>
+16
View File
@@ -284,6 +284,22 @@ void DumpDynamicNeeded(elfheader_t *h)
}
}
void DumpDynamicRPath(elfheader_t *h)
{
if(box86_log>=LOG_DUMP && h->DynStrTab) {
printf_log(LOG_DUMP, "ELF Dump DT_RPATH/DT_RUNPATH=====\n");
for (int i=0; i<h->numDynamic; ++i) {
if(h->Dynamic[i].d_tag==DT_RPATH) {
printf_log(LOG_DUMP, " RPATH : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
}
if(h->Dynamic[i].d_tag==DT_RUNPATH) {
printf_log(LOG_DUMP, " RUNPATH : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
}
}
printf_log(LOG_DUMP, "=====ELF Dump DT_RPATH/DT_RUNPATH\n");
}
}
void DumpRelTable(elfheader_t *h, int cnt, Elf32_Rel *rel, const char* name)
{
if(box86_log>=LOG_DUMP) {
+413 -214
View File
@@ -4,7 +4,12 @@
#include <string.h>
#include <elf.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <link.h>
#include <unistd.h>
#include <errno.h>
#include "box86version.h"
#include "elfloader.h"
@@ -21,10 +26,12 @@
#include "box86stack.h"
#include "callback.h"
#include "dynarec.h"
#include "box86stack.h"
#ifdef DYNAREC
#include "dynablock.h"
#endif
#include "../emu/x86emu_private.h"
#include "x86tls.h"
void* my__IO_2_1_stderr_ = NULL;
void* my__IO_2_1_stdin_ = NULL;
@@ -44,6 +51,10 @@ elfheader_t* LoadAndCheckElfHeader(FILE* f, const char* name, int exec)
if(!h)
return NULL;
if ((h->path = realpath(name, NULL)) == NULL) {
h->path = (char*)malloc(1);
h->path[0] = '\0';
}
return h;
}
@@ -53,10 +64,11 @@ void FreeElfHeader(elfheader_t** head)
return;
elfheader_t *h = *head;
#ifdef DYNAREC
dynarec_log(LOG_INFO, "Free Dynarec block for %s\n", h->name);
dynarec_log(LOG_INFO, "Free Dynarec block for %s\n", h->path);
FreeDynablockList(&h->blocks);
#endif
free(h->name);
free(h->path);
free(h->PHEntries);
free(h->SHEntries);
free(h->SHStrTab);
@@ -124,6 +136,8 @@ int CalcLoadAddr(elfheader_t* head)
const char* ElfName(elfheader_t* head)
{
if(!head)
return "(noelf)";
return head->name;
}
@@ -138,23 +152,91 @@ int AllocElfMemory(box86context_t* context, elfheader_t* head, int mainbin)
}
if(!offs)
offs = head->vaddr;
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)
, -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(head->vaddr) {
head->multiblock_n = 0; // count PHEntrie with LOAD
for (int i=0; i<head->numPHEntries; ++i)
if(head->PHEntries[i].p_type == PT_LOAD)
++head->multiblock_n;
head->multiblock_size = (uint32_t*)calloc(head->multiblock_n, sizeof(uint32_t));
head->multiblock_offs = (uintptr_t*)calloc(head->multiblock_n, sizeof(uintptr_t));
head->multiblock = (void**)calloc(head->multiblock_n, sizeof(void*));
// and now, create all individual blocks
head->memory = (char*)0xffffffff;
int n = 0;
for (int i=0; i<head->numPHEntries; ++i)
if(head->PHEntries[i].p_type == PT_LOAD) {
Elf32_Phdr * e = &head->PHEntries[i];
uintptr_t bstart = e->p_vaddr;
uint32_t bsize = e->p_memsz;
uintptr_t balign = e->p_align;
if (balign) balign = balign-1; else balign = 1;
if(balign<4095) balign = 4095;
uintptr_t bend = (bstart + bsize + balign)&(~balign);
bstart &= ~balign;
int ok = 0;
for (int j=0; !ok && j<n; ++j) {
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))) {
// merge
ok = 1;
if(bstart<start)
head->multiblock_offs[j] = bstart;
head->multiblock_size[j] = ((bend>end)?bend:end) - head->multiblock_offs[j];
--head->multiblock_n;
}
}
if(!ok) {
head->multiblock_offs[n] = bstart;
head->multiblock_size[n] = bend - head->multiblock_offs[n];
++n;
}
}
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
, -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;
}
head->multiblock[i] = p;
if(p<(void*)head->memory)
head->memory = (char*)p;
}
} else {
// vaddr is 0, load everything has a One block
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))
, -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;
}
head->memory = p;
memset(p, 0, head->memsz);
head->delta = (intptr_t)p - (intptr_t)head->vaddr;
printf_log(LOG_DEBUG, "Got %p (delta=%p)\n", p, (void*)head->delta);
head->multiblock_n = 1;
head->multiblock_size = (uint32_t*)calloc(head->multiblock_n, sizeof(uint32_t));
head->multiblock_offs = (uintptr_t*)calloc(head->multiblock_n, sizeof(uintptr_t));
head->multiblock = (void**)calloc(head->multiblock_n, sizeof(void*));
head->multiblock_size[0] = head->memsz;
head->multiblock_offs[0] = (uintptr_t)p;
head->multiblock[0] = p;
}
head->memory = p;
memset(p, 0, head->memsz);
head->delta = (intptr_t)p - (intptr_t)head->vaddr;
printf_log(LOG_DEBUG, "Got %p (delta=%p)\n", p, (void*)head->delta);
head->tlsbase = AddTLSPartition(context, head->tlssize);
#ifdef DYNAREC
head->blocks = NewDynablockList((uintptr_t)GetBaseAddress(head), head->text + head->delta, head->textsz);
head->blocks = NewDynablockList((uintptr_t)GetBaseAddress(head), head->text + head->delta, head->textsz, 0, mainbin);
#endif
return 0;
@@ -162,8 +244,13 @@ int AllocElfMemory(box86context_t* context, elfheader_t* head, int mainbin)
void FreeElfMemory(elfheader_t* head)
{
if(head->memory)
munmap((void*)head->memory, head->memsz);
if(head->multiblock_n) {
for(int i=0; i<head->multiblock_n; ++i)
munmap(head->multiblock[i], head->multiblock_size[i]);
free(head->multiblock);
free(head->multiblock_size);
free(head->multiblock_offs);
}
}
int LoadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
@@ -173,10 +260,10 @@ int LoadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
Elf32_Phdr * e = &head->PHEntries[i];
char* dest = (char*)e->p_paddr + head->delta;
printf_log(LOG_DEBUG, "Loading block #%i @%p (0x%x/0x%x)\n", i, dest, e->p_filesz, e->p_memsz);
fseek(f, e->p_offset, SEEK_SET);
fseeko64(f, e->p_offset, SEEK_SET);
if(e->p_filesz) {
if(fread(dest, e->p_filesz, 1, f)!=1) {
printf_log(LOG_NONE, "Fail to read PT_LOAD part #%d\n", i);
printf_log(LOG_NONE, "Fail to read PT_LOAD part #%d (size=%d)\n", i, e->p_filesz);
return 1;
}
}
@@ -186,12 +273,12 @@ int LoadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
}
if(head->PHEntries[i].p_type == PT_TLS) {
Elf32_Phdr * e = &head->PHEntries[i];
char* dest = (char*)context->tlsdata;
char* dest = (char*)(context->tlsdata+context->tlssize+head->tlsbase);
printf_log(LOG_DEBUG, "Loading TLS block #%i @%p (0x%x/0x%x)\n", i, dest, e->p_filesz, e->p_memsz);
fseek(f, e->p_offset, SEEK_SET);
if(e->p_filesz) {
fseeko64(f, e->p_offset, SEEK_SET);
if(fread(dest, e->p_filesz, 1, f)!=1) {
printf_log(LOG_NONE, "Fail to read PT_TLS part #%d\n", i);
printf_log(LOG_NONE, "Fail to read PT_TLS part #%d (size=%d)\n", i, e->p_filesz);
return 1;
}
}
@@ -210,10 +297,15 @@ int ReloadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
Elf32_Phdr * e = &head->PHEntries[i];
char* dest = (char*)e->p_paddr + head->delta;
printf_log(LOG_DEBUG, "Re-loading block #%i @%p (0x%x/0x%x)\n", i, dest, e->p_filesz, e->p_memsz);
fseek(f, e->p_offset, SEEK_SET);
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;}
if(e->p_filesz) {
if(fread(dest, e->p_filesz, 1, f)!=1) {
printf_log(LOG_NONE, "Fail to read PT_LOAD part #%d\n", i);
ssize_t r = -1;
#ifdef DYNAREC
unprotectDB((uintptr_t)dest, e->p_filesz);
#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;
}
}
@@ -226,24 +318,39 @@ int ReloadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
return 0;
}
int RelocateElfREL(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rel *rel)
int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cnt, Elf32_Rel *rel)
{
for (int i=0; i<cnt; ++i) {
int t = ELF32_R_TYPE(rel[i].r_info);
Elf32_Sym *sym = &head->DynSym[ELF32_R_SYM(rel[i].r_info)];
int type = ELF32_ST_TYPE(sym->st_info);
int bind = ELF32_ST_BIND(sym->st_info);
const char* symname = SymName(head, sym);
uint32_t ndx = sym->st_shndx;
uint32_t *p = (uint32_t*)(rel[i].r_offset + head->delta);
uintptr_t offs = 0;
uint32_t sz = 0;
uintptr_t end = 0;
if(bind==STB_LOCAL)
GetLocalSymbolStartEnd(maplib, symname, &offs, &end, head);
else
GetGlobalSymbolStartEnd(maplib, symname, &offs, &end);
elfheader_t* h_tls = head;
if(bind==STB_LOCAL) {
offs = sym->st_value + head->delta;
end = offs + sym->st_size;
} else {
// this is probably very very wrong. A proprer way to get reloc need to be writen, but this hack seems ok for now
// at least it work for half-life, unreal, ut99, zsnes, Undertale, ColinMcRae Remake, FTL, ShovelKnight...
if(bind==STB_GLOBAL && (ndx==10 || ndx==19) && t!=R_386_GLOB_DAT) {
offs = sym->st_value + head->delta;
end = offs + sym->st_size;
}
// so weak symbol are the one left
if(!offs && !end) {
h_tls = NULL;
if(local_maplib)
GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end);
if(!offs && !end)
GetGlobalSymbolStartEnd(maplib, symname, &offs, &end);
}
}
uintptr_t globoffs, globend;
int delta;
int t = ELF32_R_TYPE(rel[i].r_info);
switch(t) {
case R_386_NONE:
// can be ignored
@@ -252,31 +359,41 @@ int RelocateElfREL(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rel *rel)
case R_386_TLS_TPOFF:
// Negated offset in static TLS block
{
elfheader_t *h = GetGlobalSymbolElf(maplib, symname);
if(h) {
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_DEBUG, "Applying %s %s on %s @%p (%d -> %d)\n", (bind==STB_LOCAL)?"Local":"Global", DumpRelType(t), symname, p, delta, (int32_t)offs + h->tlsbase);
*p = (uint32_t)((int32_t)offs + h->tlsbase);
printf_log(LOG_DEBUG, "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)\n", symname, p, *(void**)p);
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);
}
offs = (offs - (uintptr_t)p);
if(!offs)
printf_log(LOG_DEBUG, "Apply %s R_386_PC32 @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)(*(uintptr_t*)p+offs));
printf_log(LOG_DEBUG, "Apply %s R_386_PC32 @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)(*(uintptr_t*)p+offs));
*p += offs;
break;
case R_386_GLOB_DAT:
// Look for same symbol already loaded but not in self
// 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) {
printf_log(LOG_NONE, "Error: Global Symbol %s not found, cannot apply R_386_GLOB_DAT @%p (%p)\n", symname, p, *(void**)p);
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;
} else {
printf_log(LOG_DEBUG, "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);
@@ -289,7 +406,7 @@ int RelocateElfREL(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rel *rel)
break;
case R_386_32:
if (!offs) {
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_32 @%p (%p)\n", symname, p, *(void**)p);
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_32 @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
// return -1;
} else {
printf_log(LOG_DEBUG, "Apply %s R_386_32 @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)(offs+*(uint32_t*)p));
@@ -299,10 +416,15 @@ int RelocateElfREL(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rel *rel)
case R_386_TLS_DTPMOD32:
// ID of module containing symbol
if(!symname || symname[0]=='\0' || bind==STB_LOCAL)
offs = getElfIndex(GetLibrarianContext(maplib), head);
offs = getElfIndex(my_context, head);
else {
elfheader_t *h = GetGlobalSymbolElf(maplib, symname);
offs = getElfIndex(GetLibrarianContext(maplib), h);
if(!h_tls) {
if(local_maplib)
h_tls = GetGlobalSymbolElf(local_maplib, symname);
if(!h_tls)
h_tls = GetGlobalSymbolElf(maplib, symname);
}
offs = getElfIndex(my_context, h_tls);
}
if(p) {
printf_log(LOG_DEBUG, "Apply %s %s @%p with sym=%s (%p -> %p)\n", "R_386_TLS_DTPMOD32", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)offs);
@@ -313,14 +435,16 @@ int RelocateElfREL(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rel *rel)
break;
case R_386_TLS_DTPOFF32:
// Offset in TLS block
if (!offs) {
if (!offs && !end) {
if(bind==STB_WEAK) {
printf_log(LOG_INFO, "Warning: Weak Symbol %s not found, cannot apply R_386_TLS_DTPOFF32 @%p (%p)\n", symname, p, *(void**)p);
} else {
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_TLS_DTPOFF32 @%p (%p)\n", symname, p, *(void**)p);
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_TLS_DTPOFF32 @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
}
// return -1;
} else {
if(h_tls)
offs = sym->st_value;
if(p) {
int tlsoffset = offs; // it's not an offset in elf memory
printf_log(LOG_DEBUG, "Apply %s R_386_TLS_DTPOFF32 @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, (void*)tlsoffset, (void*)offs);
@@ -331,25 +455,34 @@ int RelocateElfREL(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rel *rel)
}
break;
case R_386_JMP_SLOT:
if (!offs) {
if(bind==STB_WEAK) {
printf_log(LOG_INFO, "Warning: Weak Symbol %s not found, cannot apply R_386_JMP_SLOT @%p (%p)\n", symname, p, *(void**)p);
if(bind==STB_LOCAL) {
if (!offs) {
if(bind==STB_WEAK) {
printf_log(LOG_INFO, "Warning: Weak Symbol %s not found, cannot apply R_386_JMP_SLOT @%p (%p)\n", symname, p, *(void**)p);
} else {
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_JMP_SLOT @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
}
// return -1;
} else {
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_JMP_SLOT @%p (%p)\n", symname, p, *(void**)p);
if(p) {
printf_log(LOG_DEBUG, "Apply %s R_386_JMP_SLOT @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)offs);
*p = offs;
} else {
printf_log(LOG_NONE, "Warning, Symbol %s found, but Jump Slot Offset is NULL \n", symname);
}
}
// return -1;
} else {
if(p) {
printf_log(LOG_DEBUG, "Apply %s R_386_JMP_SLOT @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)offs);
*p = offs;
} else {
printf_log(LOG_NONE, "Warning, Symbol %s found, but Jump Slot Offset is NULL \n", symname);
}
printf_log(LOG_DEBUG, "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);
*p += head->delta;
}
break;
case R_386_COPY:
if(offs) {
GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head); // get original copy if any
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_DEBUG, "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_DEBUG<=box86_log) {
@@ -359,7 +492,7 @@ int RelocateElfREL(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rel *rel)
printf_log(LOG_DEBUG, "%s)\n", (sym->st_size>128)?" ...":"");
}
} else {
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_COPY @%p (%p)\n", symname, p, *(void**)p);
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:
@@ -369,14 +502,13 @@ int RelocateElfREL(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rel *rel)
return 0;
}
int RelocateElfRELA(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rela *rela)
int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cnt, Elf32_Rela *rela)
{
for (int i=0; i<cnt; ++i) {
Elf32_Sym *sym = &head->DynSym[ELF32_R_SYM(rela[i].r_info)];
const char* symname = SymName(head, sym);
uint32_t *p = (uint32_t*)(rela[i].r_offset + head->delta);
uintptr_t offs = 0;
uint32_t sz = 0;
uintptr_t end = 0;
switch(ELF32_R_TYPE(rela[i].r_info)) {
case R_386_NONE:
@@ -384,13 +516,16 @@ int RelocateElfRELA(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rela *rela)
// can be ignored
break;
case R_386_COPY:
GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head);
if(local_maplib)
GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head);
if(!offs)
GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head);
if(offs) {
// add r_addend to p?
printf_log(LOG_DEBUG, "Apply R_386_COPY @%p with sym=%s, @%p size=%d\n", p, symname, (void*)offs, sym->st_size);
memcpy(p, (void*)(offs+rela[i].r_addend), sym->st_size);
} else {
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_COPY @%p (%p)\n", symname, p, *(void**)p);
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply RELA R_386_COPY @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
}
break;
default:
@@ -399,48 +534,53 @@ int RelocateElfRELA(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rela *rela)
}
return 0;
}
int RelocateElf(lib_t *maplib, elfheader_t* head)
int RelocateElf(lib_t *maplib, lib_t *local_maplib, elfheader_t* head)
{
if(head->rel) {
int cnt = head->relsz / head->relent;
DumpRelTable(head, cnt, (Elf32_Rel *)(head->rel + head->delta), "Rel");
printf_log(LOG_DEBUG, "Applying %d Relocation(s) for %s\n", cnt, head->name);
if(RelocateElfREL(maplib, head, cnt, (Elf32_Rel *)(head->rel + head->delta)))
if(RelocateElfREL(maplib, local_maplib, head, cnt, (Elf32_Rel *)(head->rel + head->delta)))
return -1;
}
if(head->rela) {
int cnt = head->relasz / head->relaent;
DumpRelATable(head, cnt, (Elf32_Rela *)(head->rela + head->delta), "RelA");
printf_log(LOG_DEBUG, "Applying %d Relocation(s) with Addend for %s\n", cnt, head->name);
if(RelocateElfRELA(maplib, head, cnt, (Elf32_Rela *)(head->rela + head->delta)))
if(RelocateElfRELA(maplib, local_maplib, head, cnt, (Elf32_Rela *)(head->rela + head->delta)))
return -1;
}
return 0;
}
int RelocateElfPlt(box86context_t* context, lib_t *maplib, elfheader_t* head)
int RelocateElfPlt(lib_t *maplib, lib_t *local_maplib, elfheader_t* head)
{
if(pltResolver==~0) {
pltResolver = AddBridge(my_context->system, vFE, PltResolver, 0);
}
if(head->pltgot) {
*(uintptr_t*)(head->pltgot+head->delta+8) = pltResolver;
*(uintptr_t*)(head->pltgot+head->delta+4) = (uintptr_t)head;
printf_log(LOG_DEBUG, "PLT Resolver injected in plt.got at %p\n", (void*)(head->pltgot+head->delta+8));
} else if(head->got) {
*(uintptr_t*)(head->got+head->delta+8) = pltResolver;
*(uintptr_t*)(head->got+head->delta+4) = (uintptr_t)head;
printf_log(LOG_DEBUG, "PLT Resolver injected in got at %p\n", (void*)(head->got+head->delta+8));
}
if(head->pltrel) {
int cnt = head->pltsz / head->pltent;
if(head->pltrel==DT_REL) {
DumpRelTable(head, cnt, (Elf32_Rel *)(head->jmprel + head->delta), "PLT");
printf_log(LOG_DEBUG, "Applying %d PLT Relocation(s) for %s\n", cnt, head->name);
if(RelocateElfREL(maplib, head, cnt, (Elf32_Rel *)(head->jmprel + head->delta)))
if(RelocateElfREL(maplib, local_maplib, head, cnt, (Elf32_Rel *)(head->jmprel + head->delta)))
return -1;
} else if(head->pltrel==DT_RELA) {
DumpRelATable(head, cnt, (Elf32_Rela *)(head->jmprel + head->delta), "PLT");
printf_log(LOG_DEBUG, "Applying %d PLT Relocation(s) with Addend for %s\n", cnt, head->name);
if(RelocateElfRELA(maplib, head, cnt, (Elf32_Rela *)(head->jmprel + head->delta)))
if(RelocateElfRELA(maplib, local_maplib, head, cnt, (Elf32_Rela *)(head->jmprel + head->delta)))
return -1;
}
if(head->gotplt) {
if(pltResolver==~0) {
pltResolver = AddBridge(context->system, vFEpp, PltResolver, 0); // should be vFEuu
}
*(uintptr_t*)(head->gotplt+head->delta+8) = pltResolver;
printf_log(LOG_DEBUG, "PLT Resolver injected at %p\n", (void*)(head->gotplt+head->delta+8));
}
}
return 0;
@@ -555,8 +695,9 @@ void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* wea
const char * symname = h->DynStr+h->DynSym[i].st_name;
int bind = ELF32_ST_BIND(h->DynSym[i].st_info);
int type = ELF32_ST_TYPE(h->DynSym[i].st_info);
//st_shndx==65521 means ABS value
if((type==STT_OBJECT || type==STT_FUNC || type==STT_COMMON || type==STT_TLS || type==STT_NOTYPE)
&& (h->DynSym[i].st_other==0) && (h->DynSym[i].st_shndx!=0 && h->DynSym[i].st_shndx<62521)) {
&& (h->DynSym[i].st_other==0) && (h->DynSym[i].st_shndx!=0 && h->DynSym[i].st_shndx<=65521)) {
if(bind==10/*STB_GNU_UNIQUE*/ && FindGlobalSymbol(maplib, symname))
continue;
uintptr_t offs = (type==STT_TLS)?h->DynSym[i].st_value:(h->DynSym[i].st_value + h->delta);
@@ -589,14 +730,46 @@ $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, library_t* parent, box86context_t *box86, x86emu_t* emu)
int LoadNeededLibs(elfheader_t* h, lib_t *maplib, needed_libs_t* neededlibs, int local, box86context_t *box86, x86emu_t* emu)
{
DumpDynamicNeeded(h);
for (int i=0; i<h->numDynamic; ++i)
DumpDynamicRPath(h);
// update RPATH first
for (int i=0; i<h->numDynamic; ++i)
if(h->Dynamic[i].d_tag==DT_RPATH || h->Dynamic[i].d_tag==DT_RUNPATH) {
char *rpathref = h->DynStrTab+h->delta+h->Dynamic[i].d_un.d_val;
char* rpath = rpathref;
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;
}
if(strchr(rpath, '$')) {
printf_log(LOG_INFO, "BOX86: Warning, RPATH with $ variable not supported yet (%s)\n", rpath);
} else {
printf_log(LOG_DEBUG, "Prepending path \"%s\" to BOX86_LD_LIBRARY_PATH\n", rpath);
PrependPath(rpath, &box86->box86_ld_lib, 1);
}
if(rpath!=rpathref)
free(rpath);
}
if(!h->neededlibs && neededlibs)
h->neededlibs = neededlibs;
DumpDynamicNeeded(h);
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, parent, needed, box86, emu)) {
if(AddNeededLib(maplib, neededlibs, local, needed, box86, emu)) {
printf_log(LOG_INFO, "Error loading needed lib: \"%s\"\n", needed);
if(!allow_missing_libs)
return 1; //error...
@@ -604,25 +777,13 @@ int LoadNeededLibs(elfheader_t* h, lib_t *maplib, library_t* parent, box86contex
}
return 0;
}
int FinalizeNeededLibs(elfheader_t* h, lib_t *maplib, box86context_t *box86, x86emu_t* emu)
{
DumpDynamicNeeded(h);
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(FinalizeLibrary(GetLib(maplib, needed), emu)) {
printf_log(LOG_INFO, "Error finalizing needed lib: \"%s\"\n", needed);
return 1; //error...
}
}
return 0;
}
void RunElfInit(elfheader_t* h, x86emu_t *emu)
{
if(h->init_done || !h->initentry)
if(!h || h->init_done)
return;
// reset Segs Cache
memset(emu->segs_clean, 0, sizeof(emu->segs_clean));
uintptr_t p = h->initentry + h->delta;
box86context_t* context = GetEmuContext(emu);
if(context->deferedInit) {
@@ -634,25 +795,23 @@ void RunElfInit(elfheader_t* h, x86emu_t *emu)
return;
}
printf_log(LOG_DEBUG, "Calling Init for %s @%p\n", ElfName(h), (void*)p);
Push32(emu, (uintptr_t)context->envv);
Push32(emu, (uintptr_t)context->argv);
Push32(emu, context->argc);
DynaCall(emu, p);
if(h->initentry)
RunFunctionWithEmu(emu, 0, p, 3, context->argc, context->argv, context->envv);
printf_log(LOG_DEBUG, "Done Init for %s\n", ElfName(h));
// and check init array now
Elf32_Addr *addr = (Elf32_Addr*)(h->initarray + h->delta);
for (int i=0; i<h->initarray_sz; ++i) {
printf_log(LOG_DEBUG, "Calling Init[%d] for %s @%p\n", i, ElfName(h), (void*)addr[i]);
DynaCall(emu, (uintptr_t)addr[i]);
RunFunctionWithEmu(emu, 0, (uintptr_t)addr[i], 3, context->argc, context->argv, context->envv);
}
Pop32(emu);
Pop32(emu);
Pop32(emu);
h->init_done = 1;
h->fini_done = 0; // can be fini'd now (in case it was re-inited)
printf_log(LOG_DEBUG, "All Init Done for %s\n", ElfName(h));
return;
}
EXPORTDYN
void RunDeferedElfInit(x86emu_t *emu)
{
box86context_t* context = GetEmuContext(emu);
@@ -667,25 +826,24 @@ void RunDeferedElfInit(x86emu_t *emu)
context->deferedInitList = NULL;
context->deferedInitCap = context->deferedInitSz = 0;
}
void RunElfFini(elfheader_t* h, x86emu_t *emu)
{
if(h->fini_done || !h->finientry)
if(!h || h->fini_done)
return;
uintptr_t p = h->finientry + h->delta;
printf_log(LOG_DEBUG, "Calling Fini for %s @%p\n", ElfName(h), (void*)p);
uint32_t sESP = GetESP(emu);
Push32(emu, (uintptr_t)GetEmuContext(emu)->envv);
Push32(emu, (uintptr_t)GetEmuContext(emu)->argv);
Push32(emu, GetEmuContext(emu)->argc);
DynaCall(emu, p);
// and check fini array now
h->fini_done = 1;
// first check fini array
Elf32_Addr *addr = (Elf32_Addr*)(h->finiarray + h->delta);
for (int i=0; i<h->finiarray_sz; ++i) {
printf_log(LOG_DEBUG, "Calling Fini[%d] for %s @%p\n", i, ElfName(h), (void*)addr[i]);
DynaCall(emu, (uintptr_t)addr[i]);
RunFunctionWithEmu(emu, 0, (uintptr_t)addr[i], 0);
}
// then the "old-style" fini
if(h->finientry) {
uintptr_t p = h->finientry + h->delta;
printf_log(LOG_DEBUG, "Calling Fini for %s @%p\n", ElfName(h), (void*)p);
RunFunctionWithEmu(emu, 0, p, 0);
}
SetESP(emu, sESP);
h->fini_done = 1;
h->init_done = 0; // can be re-inited again...
return;
}
@@ -704,6 +862,11 @@ void* GetBaseAddress(elfheader_t* h)
return h->memory;
}
void* GetElfDelta(elfheader_t* h)
{
return (void*)h->delta;
}
uint32_t GetBaseSize(elfheader_t* h)
{
return h->memsz;
@@ -713,10 +876,13 @@ int IsAddressInElfSpace(elfheader_t* h, uintptr_t addr)
{
if(!h)
return 0;
uintptr_t base = (uintptr_t)GetBaseAddress(h);
uintptr_t end = GetLastByte(h);
if(addr>=base && addr<=end)
return 1;
for(int i=0; i<h->multiblock_n; ++i) {
uintptr_t base = h->multiblock_offs[i];
uintptr_t end = h->multiblock_offs[i] + h->multiblock_size[i] - 1;
if(addr>=base && addr<=end)
return 1;
}
return 0;
}
elfheader_t* FindElfAddress(box86context_t *context, uintptr_t addr)
@@ -743,7 +909,7 @@ const char* FindNearestSymbolName(elfheader_t* h, void* p, uintptr_t* start, uin
const char * symname = h->StrTab+h->SymTab[i].st_name;
uintptr_t offs = h->SymTab[i].st_value + h->delta;
if(offs<addr) {
if(offs<=addr) {
if(distance>addr-offs) {
distance = addr-offs;
ret = symname;
@@ -756,7 +922,7 @@ const char* FindNearestSymbolName(elfheader_t* h, void* p, uintptr_t* start, uin
const char * symname = h->DynStr+h->DynSym[i].st_name;
uintptr_t offs = h->DynSym[i].st_value + h->delta;
if(offs<addr) {
if(offs<=addr) {
if(distance>addr-offs) {
distance = addr-offs;
ret = symname;
@@ -774,87 +940,6 @@ const char* FindNearestSymbolName(elfheader_t* h, void* p, uintptr_t* start, uin
return ret;
}
static void* fillTLSData(box86context_t *context)
{
void* ptr = NULL;
pthread_mutex_lock(&context->mutex_lock);
// Setup the GS segment:
int dtsize = context->elfsize*8;
ptr = (char*)malloc(context->tlssize+0x50+dtsize+24); // plan a 8*4 dtp table
memcpy(ptr, context->tlsdata, context->tlssize);
tlsdatasize_t *data = (tlsdatasize_t*)calloc(1, sizeof(tlsdatasize_t));
data->tlsdata = ptr;
data->tlssize = context->tlssize;
pthread_setspecific(context->tlskey, data);
// copy canary...
memset((void*)((uintptr_t)ptr+context->tlssize), 0, 0x50+dtsize+24); // set to 0 remining bytes
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x14), context->canary, 4); // put canary in place
uintptr_t unknown = (uintptr_t)ptr+context->tlssize;
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x0), &unknown, 4);
uintptr_t dtp = (uintptr_t)ptr+context->tlssize+0x50;
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x4), &dtp, 4);
if(dtsize) {
for (int i=0; i<context->elfsize; ++i) {
// set pointer
dtp = (uintptr_t)ptr + (context->tlssize + GetTLSBase(context->elfs[i]));
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x50+i*8), &dtp, 4);
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x50+i*8+4), &i, 4); // index
}
}
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x10), &context->vsyscall, 4); // address of vsyscall
pthread_mutex_unlock(&context->mutex_lock);
return data;
}
static void* resizeTLSData(box86context_t *context, void* oldptr)
{
void* ptr = NULL;
pthread_mutex_lock(&context->mutex_lock);
tlsdatasize_t* oldata = (tlsdatasize_t*)oldptr;
tlsdatasize_t *data = (tlsdatasize_t*)calloc(1, sizeof(tlsdatasize_t));
// Setup the GS segment:
int dtsize = context->elfsize*8;
ptr = (char*)malloc(context->tlssize+0x50+dtsize+24); // plan a 8*4 dtp table
data->tlsdata = ptr;
data->tlssize = context->tlssize;
memcpy(ptr, context->tlsdata, context->tlssize);
pthread_setspecific(context->tlskey, data);
// copy canary...
memset((void*)((uintptr_t)ptr+context->tlssize), 0, 0x50+dtsize+24); // set to 0 remining bytes
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x14), context->canary, 4); // put canary in place
uintptr_t unknown = (uintptr_t)ptr+context->tlssize;
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x0), &unknown, 4);
uintptr_t dtp = (uintptr_t)ptr+context->tlssize+0x50;
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x4), &dtp, 4);
if(dtsize) {
for (int i=0; i<context->elfsize; ++i) {
// set pointer
dtp = (uintptr_t)ptr + (context->tlssize + GetTLSBase(context->elfs[i]));
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x50+i*8), &dtp, 4);
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x50+i*8+4), &i, 4); // index
}
}
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x10), &context->vsyscall, 4); // address of vsyscall
// copy the relevent old part, in case something changed
memcpy((void*)((uintptr_t)ptr+(context->tlssize-oldata->tlssize)), oldata->tlsdata, oldata->tlssize);
// all done, update new size, free old pointer and exit
pthread_mutex_unlock(&context->mutex_lock);
free_tlsdatasize(oldptr);
return data;
}
void* GetGSBase(box86context_t *context)
{
tlsdatasize_t* ptr;
if ((ptr = (tlsdatasize_t*)pthread_getspecific(context->tlskey)) == NULL) {
ptr = (tlsdatasize_t*)fillTLSData(context);
}
if(ptr->tlssize != context->tlssize)
ptr = (tlsdatasize_t*)resizeTLSData(context, ptr);
return ptr->tlsdata+ptr->tlssize;
}
void* GetDTatOffset(box86context_t* context, int index, int offset)
{
return (void*)((char*)GetTLSPointer(context, context->elfs[index])+offset);
@@ -886,17 +971,31 @@ void* GetTLSPointer(box86context_t* context, elfheader_t* h)
#ifdef DYNAREC
dynablocklist_t* GetDynablocksFromAddress(box86context_t *context, uintptr_t addr)
{
// this is one is fast, so start with that
dynablocklist_t* ret = getDBFromAddress(addr);
if(ret) {
return ret;
}
// nope, then find in elfs
elfheader_t* elf = FindElfAddress(context, addr);
if(!elf) {
if((*(uint8_t*)addr)==0xCC)
return context->dynablocks;
// still nope
if(addr>0x100)
if((*(uint8_t*)addr)==0xCC || (((*(uint8_t*)addr)==0xC3 || (*(uint8_t*)addr)==0xC2) && (*(uint8_t*)(addr-11))==0xCC) )
return context->dynablocks;
if(box86_dynarec_forced)
return context->dynablocks;
dynarec_log(LOG_INFO, "Address %p not found in Elf memory and is not a native call wrapper\n", addr);
dynarec_log(LOG_INFO, "Address %p not found in Elf memory and is not a native call wrapper\n", (void*)addr);
return NULL;
}
return elf->blocks;
}
dynablocklist_t* GetDynablocksFromElf(elfheader_t* h)
{
if(!h)
return NULL;
return h->blocks;
}
#endif
typedef struct my_dl_phdr_info_s {
@@ -908,8 +1007,20 @@ typedef struct my_dl_phdr_info_s {
static int dl_iterate_phdr_callback(x86emu_t *emu, my_dl_phdr_info_t *info, size_t size, void* data)
{
SetCallbackArg(emu, 0, info);
SetCallbackArg(emu, 1, (void*)size);
SetCallbackArgs(emu, 2, info, size);
int ret = RunCallback(emu);
return ret;
}
static int dl_iterate_phdr_native(struct dl_phdr_info* info, size_t size, void* data)
{
if(!info->dlpi_name)
return 0;
if(!info->dlpi_name[0]) // don't send informations about box86 itself
return 0;
x86emu_t* emu = (x86emu_t*)data;
SetCallbackArgs(emu, 2, info, size);
int ret = RunCallback(emu);
return ret;
}
@@ -919,17 +1030,23 @@ EXPORT int my_dl_iterate_phdr(x86emu_t *emu, void* F, void *data) {
x86emu_t* cbemu = AddSharedCallback(emu, (uintptr_t)F, 3, NULL, NULL, data, NULL);
box86context_t *context = GetEmuContext(emu);
const char* empty = "";
int ret = 0;
for (int idx=0; idx<context->elfsize; ++idx) {
my_dl_phdr_info_t info;
info.dlpi_addr = GetBaseAddress(context->elfs[idx]);
info.dlpi_addr = GetElfDelta(context->elfs[idx]);
info.dlpi_name = idx?context->elfs[idx]->name:empty; //1st elf is program, and this one doesn't get a name
info.dlpi_phdr = context->elfs[idx]->PHEntries;
info.dlpi_phnum = context->elfs[idx]->numPHEntries;
if(dl_iterate_phdr_callback(cbemu, &info, sizeof(info), data))
break;
if((ret = dl_iterate_phdr_callback(cbemu, &info, sizeof(info), data))) {
FreeCallback(cbemu);
return ret;
}
}
// and now, go on native version
ret = dl_iterate_phdr(dl_iterate_phdr_native, cbemu);
// all done
FreeCallback(cbemu);
return 0;
return ret;
}
void ResetSpecialCaseMainElf(elfheader_t* h)
@@ -939,18 +1056,100 @@ void ResetSpecialCaseMainElf(elfheader_t* h)
if(h->DynSym[i].st_info == 17) {
sym = h->DynSym+i;
const char * symname = h->DynStr+sym->st_name;
if(strcmp(symname, "_IO_2_1_stderr_")==0) {
if(strcmp(symname, "_IO_2_1_stderr_")==0 && ((void*)sym->st_value+h->delta)) {
memcpy((void*)sym->st_value+h->delta, stderr, sym->st_size);
my__IO_2_1_stderr_ = (void*)sym->st_value+h->delta;
printf_log(LOG_DEBUG, "BOX86: Set @_IO_2_1_stderr_ to %p\n", my__IO_2_1_stderr_);
} else
if(strcmp(symname, "_IO_2_1_stdin_")==0) {
if(strcmp(symname, "_IO_2_1_stdin_")==0 && ((void*)sym->st_value+h->delta)) {
memcpy((void*)sym->st_value+h->delta, stdin, sym->st_size);
my__IO_2_1_stdin_ = (void*)sym->st_value+h->delta;
printf_log(LOG_DEBUG, "BOX86: Set @_IO_2_1_stdin_ to %p\n", my__IO_2_1_stdin_);
} else
if(strcmp(symname, "_IO_2_1_stdout_")==0) {
if(strcmp(symname, "_IO_2_1_stdout_")==0 && ((void*)sym->st_value+h->delta)) {
memcpy((void*)sym->st_value+h->delta, stdout, sym->st_size);
my__IO_2_1_stdout_ = (void*)sym->st_value+h->delta;
printf_log(LOG_DEBUG, "BOX86: Set @_IO_2_1_stdout_ to %p\n", my__IO_2_1_stdout_);
}
}
}
}
void CreateMemorymapFile(box86context_t* context, int fd)
{
char buff[1024];
struct stat st;
int dummy;
(void)dummy;
elfheader_t *h = context->elfs[0];
if (stat(h->path, &st)) {
printf_log(LOG_INFO, "Failed to stat file %s (creating memory maps \"file\")!", h->path);
// Some constants, to have "valid" values
st.st_dev = makedev(0x03, 0x00);
st.st_ino = 0;
}
for (int i=0; i<h->numPHEntries; ++i) {
if (h->PHEntries[i].p_memsz == 0) continue;
sprintf(buff, "%08x-%08x %c%c%c%c %08x %02x:%02x %ld %s\n", (uintptr_t)h->PHEntries[i].p_vaddr + h->delta,
(uintptr_t)h->PHEntries[i].p_vaddr + h->PHEntries[i].p_memsz + h->delta,
(h->PHEntries[i].p_type & (PF_R|PF_X) ? 'r':'-'), (h->PHEntries[i].p_type & PF_W ? 'w':'-'),
(h->PHEntries[i].p_type & PF_X ? 'x':'-'), 'p', // p for private or s for shared
(uintptr_t)h->PHEntries[i].p_offset,
major(st.st_dev), minor(st.st_dev), st.st_ino, h->path);
dummy = write(fd, buff, strlen(buff));
}
}
void ElfAttachLib(elfheader_t* head, library_t* lib)
{
if(!head)
return;
head->lib = lib;
}
uintptr_t pltResolver = ~0;
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);
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);
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 (!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);
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)));
*p = offs;
} else {
printf_log(LOG_NONE, "PltReolver: Warning, Symbol %s found, but Jump Slot Offset is NULL \n", symname);
}
}
// jmp to function
R_EIP = offs;
}
+11
View File
@@ -5,10 +5,14 @@
typedef struct dynablocklist_s dynablocklist_t;
#endif
typedef struct library_s library_t;
typedef struct needed_libs_s needed_libs_t;
#include <pthread.h>
struct elfheader_s {
char* name;
char* path; // Resolved path to file
int numPHEntries;
Elf32_Phdr *PHEntries;
int numSHEntries;
@@ -48,6 +52,7 @@ struct elfheader_s {
int pltent;
uint32_t pltrel;
uintptr_t gotplt;
uintptr_t pltgot;
uintptr_t got;
uintptr_t text;
int textsz;
@@ -67,9 +72,15 @@ struct elfheader_s {
int fini_done;
char* memory; // char* and not void* to allow math on memory pointer
void** multiblock;
uintptr_t* multiblock_offs;
uint32_t* multiblock_size;
int multiblock_n;
#ifdef DYNAREC
dynablocklist_t *blocks;
#endif
library_t *lib;
needed_libs_t *neededlibs;
};
#define R_386_NONE 0
+13 -6
View File
@@ -1,3 +1,4 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -23,7 +24,7 @@ int LoadSH(FILE *f, Elf32_Shdr *s, void** SH, const char* name, uint32_t type)
printf_log(LOG_INFO, "Section Header \"%s\" (off=%d, size=%d) has size (not multiple of %d)\n", name, s->sh_offset, s->sh_size, sizeof(Elf32_Sym));
}
*SH = calloc(1, s->sh_size);
fseek(f, s->sh_offset ,SEEK_SET);
fseeko64(f, s->sh_offset ,SEEK_SET);
if(fread(*SH, s->sh_size, 1, f)!=1) {
printf_log(LOG_INFO, "Cannot read Section Header \"%s\" (off=%d, size=%d)\n", name, s->sh_offset, s->sh_size);
return -1;
@@ -69,11 +70,15 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
return NULL;
}
if(header.e_ident[EI_CLASS]!=ELFCLASS32) {
printf_log(LOG_INFO, "Not an 32bits ELF (%d)\n", header.e_ident[EI_CLASS]);
if(header.e_ident[EI_CLASS]==ELFCLASS64) {
printf_log(LOG_INFO, "This is a 64bits ELF! box86 can only run 32bits ELF!\n");
} else {
printf_log(LOG_INFO, "Not a 32bits ELF (%d)\n", header.e_ident[EI_CLASS]);
}
return NULL;
}
if(header.e_ident[EI_DATA]!=ELFDATA2LSB) {
printf_log(LOG_INFO, "Not an LittleEndian ELF (%d)\n", header.e_ident[EI_DATA]);
printf_log(LOG_INFO, "Not a LittleEndian ELF (%d)\n", header.e_ident[EI_DATA]);
return NULL;
}
if(header.e_ident[EI_VERSION]!=EV_CURRENT) {
@@ -119,7 +124,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
if(h->numSHEntries == 0) {
printf_log(LOG_DEBUG, "Read number of Sections in 1st Section\n");
// read 1st section header and grab actual number from here
fseek(f, header.e_shoff, SEEK_SET);
fseeko64(f, header.e_shoff, SEEK_SET);
Elf32_Shdr section;
if(fread(&section, sizeof(Elf32_Shdr), 1, f)!=1) {
free(h);
@@ -131,7 +136,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
// now read all section headers
printf_log(LOG_DEBUG, "Read %d Section header\n", h->numSHEntries);
h->SHEntries = (Elf32_Shdr*)calloc(h->numSHEntries, sizeof(Elf32_Shdr));
fseek(f, header.e_shoff ,SEEK_SET);
fseeko64(f, header.e_shoff ,SEEK_SET);
if(fread(h->SHEntries, sizeof(Elf32_Shdr), h->numSHEntries, f)!=h->numSHEntries) {
FreeElfHeader(&h);
printf_log(LOG_INFO, "Cannot read all Section Header\n");
@@ -147,7 +152,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
printf_log(LOG_DEBUG, "Read %d Program header\n", h->numPHEntries);
h->PHEntries = (Elf32_Phdr*)calloc(h->numPHEntries, sizeof(Elf32_Phdr));
fseek(f, header.e_phoff ,SEEK_SET);
fseeko64(f, header.e_phoff ,SEEK_SET);
if(fread(h->PHEntries, sizeof(Elf32_Phdr), h->numPHEntries, f)!=h->numPHEntries) {
FreeElfHeader(&h);
printf_log(LOG_INFO, "Cannot read all Program Header\n");
@@ -194,6 +199,8 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
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)
+5
View File
@@ -51,6 +51,10 @@
if((nextop&0xC0)==0xC0) { \
A = (reg32_t*)&emu->regs[(nextop&3)].byte[((nextop&0x4)>>2)]; \
} else getecommon(A, reg32_t)
#define getebo(A, O) \
if((nextop&0xC0)==0xC0) { \
A = (reg32_t*)&emu->regs[(nextop&3)].byte[((nextop&0x4)>>2)]; \
} else getecommono(A, reg32_t, O)
#define geted(A) \
if((nextop&0xC0)==0xC0) { \
A = &emu->regs[(nextop&7)]; \
@@ -71,6 +75,7 @@
#define GET_EB geteb(oped)
#define GET_ED geted(oped)
#define GET_ED_OFFS(o) getedo(oped, o)
#define GET_EB_OFFS(o) getebo(oped, o)
#define GET_EM getem(opem)
#define GET_EX getex(opex)
#define EB oped
+138 -95
View File
@@ -1,5 +1,21 @@
opcode = F8;
goto *opcodes0f[opcode];
_0f_0x00: /* VERx Ed */
nextop = F8;
switch((nextop>>3)&7) {
case 4: //VERR
case 5: //VERW
GET_EW;
if(!EW->word[0])
CLEAR_FLAG(F_ZF);
else
SET_FLAG(F_ZF); // should test if selector is ok
break;
default:
goto _default;
}
NEXT;
_0f_0x0B: /* UD2 */
kill(getpid(), SIGILL); // this is undefined instruction
NEXT;
@@ -54,7 +70,18 @@
_0f_0x18: /* PREFETCHh Ed */
nextop = F8;
GET_ED;
__builtin_prefetch((void*)ED->dword[0], 0, 0); // inoring wich level of cache (roughly (nextop>>3)&7)
if((nextop&0xC0)==0xC0) {
} else
switch((nextop>>3)&7) {
case 0: //PREFETCHnta
case 1: //PREFETCH1
case 2: //PREFETCH2
case 3: //PREFETCH3
__builtin_prefetch((void*)ED, 0, 0); // ignoring wich level of cache
break;
default: //NOP
break;
}
NEXT;
_0f_0x1F: /* NOP (multi-byte) */
@@ -139,6 +166,22 @@
R_EAX = tmp64u&0xFFFFFFFF;
NEXT;
_0f_0x38: // these are some SSE3 opcodes
opcode = F8;
switch(opcode) {
case 0x04: /* PMADDUBSW Gm,Em */
nextop = F8;
GET_EM;
for (int i=0; i<4; ++i) {
tmp32s = (int32_t)(GM.ub[i*2+0])*EM->ub[i*2+0] + (int32_t)(GM.ub[i*2+1])*EM->ub[i*2+1];
GM.sw[i] = (tmp32s>32767)?32767:tmp32s; // no negative value to test
}
break;
default:
goto _default;
}
NEXT;
#define GOCOND(BASE, PREFIX, CONDITIONAL) \
_0f_##BASE##_0: \
PREFIX \
@@ -571,95 +614,16 @@
EM->q = GM.q;
NEXT;
_0f_0xA0: /* PUSH FS */
Push(emu, emu->segs[_FS]); // even if a segment is a 16bits, a 32bits push/pop is done
NEXT;
_0f_0xA1: /* POP FS */
emu->segs[_FS] = Pop(emu); // no check, no use....
emu->segs_clean[_FS] = 0;
NEXT;
_0f_0xA2: /* CPUID */
tmp32u = R_EAX;
switch(tmp32u) {
case 0x0:
// emulate a P4
R_EAX = 0x80000004;
// return GenuineIntel
R_EBX = 0x756E6547;
R_EDX = 0x49656E69;
R_ECX = 0x6C65746E;
break;
case 0x1:
R_EAX = 0x00000101; // familly and all
R_EBX = 0; // Brand indexe, CLFlush, Max APIC ID, Local APIC ID
R_EDX = 1 // fpu
| 1<<8 // cmpxchg8
| 1<<11 // sep (sysenter & sysexit)
| 1<<15 // cmov
| 1<<19 // clflush (seems to be with SSE2)
| 1<<23 // mmx
//| 1<<24 // fxsr (fxsave, fxrestore)
| 1<<25 // SSE
| 1<<26 // SSE2
;
R_ECX = 1<<12 // fma
| 1<<13 // cx16 (cmpxchg16)
; // also 1<<0 is SSE3 and 1<<9 is SSSE3
break;
case 0x2: // TLB and Cache info. Sending 1st gen P4 info...
R_EAX = 0x665B5001;
R_EBX = 0x00000000;
R_ECX = 0x00000000;
R_EDX = 0x007A7000;
break;
case 0x4: // Cache info
switch (R_ECX) {
case 0: // L1 data cache
R_EAX = (1 | (1<<5) | (1<<8)); //type
R_EBX = (63 | (7<<22)); // size
R_ECX = 63;
R_EDX = 1;
break;
case 1: // L1 inst cache
R_EAX = (2 | (1<<5) | (1<<8)); //type
R_EBX = (63 | (7<<22)); // size
R_ECX = 63;
R_EDX = 1;
break;
case 2: // L2 cache
R_EAX = (3 | (2<<5) | (1<<8)); //type
R_EBX = (63 | (15<<22)); // size
R_ECX = 4095;
R_EDX = 1;
break;
default:
R_EAX = 0x00000000;
R_EBX = 0x00000000;
R_ECX = 0x00000000;
R_EDX = 0x00000000;
break;
}
break;
case 0x5: //mwait info
R_EAX = 0;
R_EBX = 0;
R_ECX = 1 | 2;
R_EDX = 0;
break;
case 0x6: // thermal
case 0x9: // direct cache access
case 0xA: // Architecture performance monitor
R_EAX = 0;
R_EBX = 0;
R_ECX = 0;
R_EDX = 0;
break;
case 0x7: // extended bits...
/*if(R_ECX==0) R_EAX = 0;
else*/ R_EAX = R_ECX = R_EBX = R_EDX = 0;
break;
case 0x80000000: // max extended
break; // no extended, so return same value as beeing the max value!
default:
printf_log(LOG_INFO, "Warning, CPUID command %X unsupported (ECX=%08x)\n", tmp32u, R_ECX);
R_EAX = 0;
}
my_cpuid(emu, tmp32u);
NEXT;
_0f_0xA3: /* BT Ed,Gd */
CHECK_FLAGS(emu);
@@ -684,6 +648,15 @@
ED->dword[0] = shld32(emu, ED->dword[0], GD.dword[0], tmp8u);
NEXT;
_0f_0xA8: /* PUSH GS */
Push(emu, emu->segs[_GS]); // even if a segment is a 16bits, a 32bits push/pop is done
NEXT;
_0f_0xA9: /* POP GS */
emu->segs[_GS] = Pop(emu);
emu->segs_clean[_GS] = 0;
NEXT;
_0f_0xAB: /* BTS Ed,Gd */
CHECK_FLAGS(emu);
nextop = F8;
@@ -725,16 +698,23 @@
case 0: /* FXSAVE m512byte */
// should save flags & all
// copy MMX regs...
memcpy(ED->dword+32/4, &emu->mmx[0], sizeof(emu->mmx));
for(int i=0; i<8; ++i)
memcpy(ED->dword+32+i*16, &emu->mmx[0], sizeof(emu->mmx[0]));
// copy SSE regs
memcpy(ED->dword+160/4, &emu->xmm[0], sizeof(emu->xmm));
memcpy(ED->dword+160, &emu->xmm[0], sizeof(emu->xmm));
// put also FPU regs in a reserved area...
for(int i=0; i<8; ++i)
memcpy(ED->dword+416+i*8, &emu->fpu[0], sizeof(emu->fpu[0]));
break;
case 1: /* FXRSTOR m512byte */
// should restore flags & all
// copy MMX regs...
memcpy(&emu->mmx[0], ED->dword+32/4, sizeof(emu->mmx));
// copy back MMX regs...
for(int i=0; i<8; ++i)
memcpy(&emu->mmx[i], ED->dword+32+i*16, sizeof(emu->mmx[0]));
// copy SSE regs
memcpy(&emu->xmm[0], ED->dword+160/4, sizeof(emu->xmm));
for(int i=0; i<8; ++i)
memcpy(&emu->fpu[0], ED->dword+416+i*8, sizeof(emu->fpu[0]));
break;
case 2: /* LDMXCSR Md */
emu->mxcsr = ED->dword[0];
@@ -818,6 +798,21 @@
else
CLEAR_FLAG(F_CF);
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;
if(ED->dword[0] & (1<<tmp8u)) {
SET_FLAG(F_CF);
} else
ED->dword[0] ^= (1<<tmp8u);
CLEAR_FLAG(F_CF);
break;
case 6: /* BTR Ed, Ib */
CHECK_FLAGS(emu);
GET_ED;
@@ -833,6 +828,21 @@
} else
CLEAR_FLAG(F_CF);
break;
case 7: /* BTC Ed, Ib */
CHECK_FLAGS(emu);
GET_ED;
tmp8u = F8;
if((nextop&0xC0)!=0xC0)
{
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
}
tmp8u&=31;
if(ED->dword[0] & (1<<tmp8u))
SET_FLAG(F_CF);
else
CLEAR_FLAG(F_CF);
ED->dword[0] ^= (1<<tmp8u);
break;
default:
goto _default;
@@ -1021,6 +1031,14 @@
}
NEXT;
_0f_0xD7: /* PMOVMSKB Gd,Em */
nextop = F8;
GET_EM;
GD.dword[0] = 0;
for (int i=0; i<8; ++i)
if(EM->ub[i]&0x80)
GD.dword[0] |= (1<<i);
NEXT;
_0f_0xD8: /* PSUBUSB Gm,Em */
nextop = F8;
GET_EM;
@@ -1119,6 +1137,13 @@
}
NEXT;
_0f_0xE7: /* MOVNTQ Em,Gm */
nextop = F8;
if((nextop&0xC0)==0xC0)
goto _default;
GET_EM;
EM->q = GM.q;
NEXT;
_0f_0xE8: /* PSUBSB Gm,Em */
nextop = F8;
GET_EM;
@@ -1135,7 +1160,12 @@
GM.sw[i] = (tmp32s>32767)?32767:((tmp32s<-32768)?-32768:tmp32s);
}
NEXT;
_0f_0xEA: /* PMINSW Gm,Em */
nextop = F8;
GET_EM;
for (int i=0; i<4; ++i)
GM.sw[i] = (GM.sw[i]<EM->sw[i])?GM.sw[i]:EM->sw[i];
NEXT;
_0f_0xEB: /* POR Gm, Em */
nextop = F8;
GET_EM;
@@ -1157,7 +1187,12 @@
GM.sw[i] = (tmp32s>32767)?32767:((tmp32s<-32768)?-32768:tmp32s);
}
NEXT;
_0f_0xEE: /* PMAXSW Gm,Em */
nextop = F8;
GET_EM;
for (int i=0; i<4; ++i)
GM.sw[i] = (GM.sw[i]>EM->sw[i])?GM.sw[i]:EM->sw[i];
NEXT;
_0f_0xEF: /* PXOR Gm, Em */
nextop = F8;
GET_EM;
@@ -1215,7 +1250,15 @@
tmp32u += (GM.ub[i]>EM->ub[i])?(GM.ub[i] - EM->ub[i]):(EM->ub[i] - GM.ub[i]);
GM.q = tmp32u;
NEXT;
_0f_0xF7: /* MASKMOVQ Gm, Em */
nextop = F8;
if((nextop&0xC0)==0xC0) {
GET_EM;
for (int i=0; i<8; ++i)
if(EM->ub[i]&0x80) ((uint8_t*)(R_EDI))[i] = GM.ub[i];
} else
goto _default;
NEXT;
_0f_0xF8: /* PSUBB Gm,Em */
nextop = F8;
GET_EM;
+70 -8
View File
@@ -30,6 +30,7 @@
NEXT;
_66_0x07: /* POP ES */
emu->segs[_ES] = Pop16(emu); // no check, no use....
emu->segs_clean[_ES] = 0;
NEXT;
_66_0x0F: /* 66 0f prefix */
@@ -37,10 +38,17 @@
_66_0x26: /* ES: */
// ignored
NEXT;
opcode = F8;
goto *opcodes66[opcode];
_66_0x2E: /* CS: */
// ignored
NEXT;
opcode = F8;
goto *opcodes66[opcode];
_66_0x36: /* SS: */
// ignored
opcode = F8;
goto *opcodes66[opcode];
_66_0x39:
nextop = F8;
GET_EW;
@@ -99,6 +107,27 @@
tmp8u = opcode&7;
emu->regs[tmp8u].word[0] = Pop16(emu);
NEXT;
_66_0x60: /* PUSHA */
tmp16u = R_SP;
Push16(emu, R_AX);
Push16(emu, R_CX);
Push16(emu, R_DX);
Push16(emu, R_BX);
Push16(emu, tmp16u);
Push16(emu, R_BP);
Push16(emu, R_SI);
Push16(emu, R_DI);
NEXT;
_66_0x61: /* POPA */
R_DI = Pop16(emu);
R_SI = Pop16(emu);
R_BP = Pop16(emu);
R_ESP+=2; // POP ESP
R_BX = Pop16(emu);
R_DX = Pop16(emu);
R_CX = Pop16(emu);
R_AX = Pop16(emu);
NEXT;
_66_0x66:
goto _0x66; // 0x66 0x66 => can remove one 0x66
@@ -181,6 +210,7 @@
nextop = F8;
GET_EW;
emu->segs[((nextop&0x38)>>3)] = EW->word[0];
emu->segs_clean[((nextop&0x38)>>3)] = 0;
NEXT;
_66_0x8F: /* POP Ew */
nextop = F8;
@@ -190,10 +220,16 @@
_66_0x90: /* NOP */
NEXT;
_66_0x92: /* XCHG DX,AX */
_66_0x91:
_66_0x92:
_66_0x93:
_66_0x94:
_66_0x95:
_66_0x96:
_66_0x97: /* XCHG reg,EAX */
tmp16u = R_AX;
R_AX = R_DX;
R_DX = tmp16u;
R_AX = emu->regs[opcode&7].word[0];
emu->regs[opcode&7].word[0] = tmp16u;
NEXT;
_66_0x98: /* CBW */
@@ -208,6 +244,13 @@
PackFlags(emu);
Push16(emu, (uint16_t)emu->packed_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);
NEXT;
_66_0xA1: /* MOV AX,Ow */
R_AX = *(uint16_t*)F32;
@@ -302,7 +345,7 @@
NEXT;
_66_0xD9:
emu->old_ip = old_ip;
emu->old_ip = R_EIP;
R_EIP = ip;
Run66D9(emu);
ip = R_EIP;
@@ -310,7 +353,7 @@
NEXT;
_66_0xDD:
emu->old_ip = old_ip;
emu->old_ip = R_EIP;
R_EIP = ip;
Run66DD(emu);
ip = R_EIP;
@@ -324,6 +367,14 @@
tmp8s = ACCESS_FLAG(F_DF)?-2:+2;
tmp32u = R_ECX;
switch(nextop) {
case 0xA4: /* REP MOVSB */
while(tmp32u) {
--tmp32u;
*(uint8_t*)R_EDI = *(uint8_t*)R_ESI;
R_EDI += tmp8s;
R_ESI += tmp8s;
}
break;
case 0xA5: /* REP MOVSW */
while(tmp32u) {
--tmp32u;
@@ -405,6 +456,14 @@
break;
}
NEXT;
_66_0xF8: /* CLC */
CHECK_FLAGS(emu);
CLEAR_FLAG(F_CF);
NEXT;
_66_0xF9: /* STC */
CHECK_FLAGS(emu);
SET_FLAG(F_CF);
NEXT;
_66_0xFF: /* GRP 5 Ew */
nextop = F8;
@@ -416,8 +475,11 @@
case 1: /* DEC Ed */
EW->word[0] = dec16(emu, EW->word[0]);
break;
case 6:
Push16(emu, EW->word[0]);
break;
default:
emu->old_ip = old_ip;
emu->old_ip = R_EIP;
R_EIP = ip;
printf_log(LOG_NONE, "Illegal Opcode 66 %02X %02X\n", opcode, nextop);
emu->quit=1;
+65 -5
View File
@@ -207,7 +207,7 @@
_6f_0x38: // these are some SSE3 opcodes
opcode = F8;
switch(opcode) {
case 0x00: // PSHUFB
case 0x00: /* PSHUFB */
nextop = F8;
GET_EX;
eax1 = GX;
@@ -218,6 +218,14 @@
GX.ub[i] = eax1.ub[EX->ub[i]&15];
}
break;
case 0x04: /* PMADDUBSW Gx,Ex */
nextop = F8;
GET_EX;
for (int i=0; i<8; ++i) {
tmp32s = (int32_t)(GX.ub[i*2+0])*EX->ub[i*2+0] + (int32_t)(GX.ub[i*2+1])*EX->ub[i*2+1];
GX.sw[i] = (tmp32s>32767)?32767:tmp32s; // no negative value to test
}
break;
default:
goto _default;
}
@@ -247,8 +255,9 @@
GX.q[0] = (GX.q[0] >> tmp8u) | (GX.q[1] << (64 - tmp8u));
GX.q[1] = (GX.q[1] >> tmp8u) | (EX->q[0] << (64-tmp8u));
} else {
GX.q[0] = GX.q[1] >> (tmp8u - 64) | (EX->q[0] << (tmp8u));
GX.q[1] = (EX->q[0] << (64-tmp8u)) | (EX->q[1] >> (tmp8u - 64));
tmp8u -= 64;
GX.q[0] = (GX.q[1] >> tmp8u) | (EX->q[0] << (64 - tmp8u));
GX.q[1] = (EX->q[0] >> tmp8u) | (EX->q[1] >> (64 - tmp8u));
}
}
break;
@@ -680,6 +689,43 @@
GW.word[0] = EB->byte[0];
NEXT;
_6f_0xBA:
nextop = F8;
switch((nextop>>3)&7) {
case 4: /* BT Ew,Ib */
CHECK_FLAGS(emu);
GET_EW;
tmp8u = F8;
if((nextop&0xC0)!=0xC0)
{
EW=(reg32_t*)(((uint16_t*)(EW))+(tmp8u>>4));
}
tmp8u&=15;
if(EW->word[0] & (1<<tmp8u))
SET_FLAG(F_CF);
else
CLEAR_FLAG(F_CF);
break;
case 6: /* BTR Ew, Ib */
CHECK_FLAGS(emu);
GET_EW;
tmp8u = F8;
if((nextop&0xC0)!=0xC0)
{
EW=(reg32_t*)(((uint16_t*)(ED))+(tmp8u>>4));
}
tmp8u&=15;
if(EW->word[0] & (1<<tmp8u)) {
SET_FLAG(F_CF);
EW->word[0] ^= (1<<tmp8u);
} else
CLEAR_FLAG(F_CF);
break;
default:
goto _default;
}
NEXT;
_6f_0xBB: /* BTC Ew,Gw */
CHECK_FLAGS(emu);
nextop = F8;
@@ -870,7 +916,11 @@
GX.q[0] = (~GX.q[0]) & EX->q[0];
GX.q[1] = (~GX.q[1]) & EX->q[1];
NEXT;
_6f_0xE0: /* PAVGB Gx, Ex */
nextop = F8;
GET_EX;
for (int i=0; i<16; ++i) GX.ub[i] = ((uint16_t)GX.ub[i] + EX->ub[i] + 1)>>1;
NEXT;
_6f_0xE1: /* PSRAW Gx, Ex */
nextop = F8;
GET_EX;
@@ -883,6 +933,11 @@
tmp8u=(EX->q[0]>31)?32:EX->ub[0];
for (int i=0; i<4; ++i) GX.sd[i] >>= tmp8u;
NEXT;
_6f_0xE3: /* PAVGW Gx, Ex */
nextop = F8;
GET_EX;
for (int i=0; i<8; ++i) GX.uw[i] = ((uint16_t)GX.uw[i] + EX->uw[i] + 1)>>1;
NEXT;
_6f_0xE5: /* PMULHW Gx, Ex */
nextop = F8;
@@ -1023,7 +1078,12 @@
opx2->ub[i] = GX.ub[i];
}
NEXT;
_6f_0xF8: /* PSUBB Gx,Ex */
nextop = F8;
GET_EX;
for(int i=0; i<16; ++i)
GX.ub[i] -= EX->ub[i];
NEXT;
_6f_0xF9: /* PSUBW Gx,Ex */
nextop = F8;
GET_EX;
+49 -11
View File
@@ -124,7 +124,7 @@
#endif
fpu_do_pop(emu);
break;
case 0xF2: /* FTAN */
case 0xF2: /* FPTAN */
#ifdef USE_FLOAT
ST0.f = tanf(ST0.f);
fpu_do_push(emu);
@@ -134,6 +134,7 @@
fpu_do_push(emu);
ST0.d = 1.0;
#endif
emu->sw.f.F87_C2 = 0;
break;
case 0xF3: /* FPATAN */
#ifdef USE_FLOAT
@@ -161,16 +162,53 @@
case 0xF8: /* FPREM */
#ifdef USE_FLOAT
tmp32s = ST0.f / ST1.f;
ST0.f -= ST1.f * tmp32s;
ll = ST0.f / ST1.f;
ST0.f -= ST1.f * ll;
#else
tmp32s = ST0.d / ST1.d;
ST0.d -= ST1.d * tmp32s;
ll = ST0.d / ST1.d;
ST0.d -= ST1.d * ll;
#endif
emu->sw.f.F87_C2 = 0;
emu->sw.f.F87_C0 = (tmp32s&1);
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
emu->sw.f.F87_C1 = ((tmp32s>>2)&1);
emu->sw.f.F87_C0 = (ll&1);
emu->sw.f.F87_C3 = ((ll>>1)&1);
emu->sw.f.F87_C1 = ((ll>>2)&1);
break;
case 0xF5: /* FPREM1 */
// get exponant(ST(0))-exponant(ST(1)) in temp32s
#ifdef USE_FLOAT
tmp32s = ((ST0.ll&0x7f700000)>>23) - ((ST1.ll&0x7f700000)>>23);
#else
tmp32s = ((ST0.ll&0x7ff0000000000000LL)>>52) - ((ST1.ll&0x7ff0000000000000LL)>>52);
#endif
if(tmp32s<64)
{
#ifdef USE_FLOAT
ll = (int64_t)round(ST0.f/ST1.f);
ST0.f = ST0.f - (ST1.f*ll);
#else
ll = (int64_t)round(ST0.d/ST1.d);
ST0.d = ST0.d - (ST1.d*ll);
#endif
emu->sw.f.F87_C2 = 0;
emu->sw.f.F87_C1 = (ll&1)?1:0;
emu->sw.f.F87_C3 = (ll&2)?1:0;
emu->sw.f.F87_C0 = (ll&4)?1:0;
} else {
#ifdef USE_FLOAT
ll = (int64_t)(floor((ST0.f/ST1.f))/powf(2, tmp32s - 32));
ST0.f = ST0.f - ST1.f*ll*powf(2, 32);
#else
ll = (int64_t)(floor((ST0.d/ST1.d))/pow(2, tmp32s - 32));
ST0.d = ST0.d - ST1.d*ll*pow(2, tmp32s - 32);
#endif
emu->sw.f.F87_C2 = 1;
}
break;
case 0xF6: /* FDECSTP */
emu->top=(emu->top-1)&7; // this will probably break a few things
break;
case 0xF7: /* FINCSTP */
emu->top=(emu->top+1)&7; // this will probably break a few things
break;
case 0xF9: /* FYL2XP1 */
#ifdef USE_FLOAT
@@ -244,9 +282,6 @@
case 0xE6:
case 0xE7:
case 0xEF:
case 0xF5:
case 0xF6:
case 0xF7:
goto _default;
default:
switch((nextop>>3)&7) {
@@ -309,6 +344,9 @@
ED->dword[0] = emu->cw;
ED->dword[1] = emu->sw.x16;
// tagword: 2bits*8
ED->word[4] = 0;
for (int i=0; i<8; ++i)
ED->word[4] |= (emu->p_regs[i].tag)<<(i*2);
// intruction pointer: 48bits
// data (operand) pointer: 48bits
// last opcode: 11bits save: 16bits restaured (1st and 2nd opcode only)
+2 -1
View File
@@ -9,7 +9,8 @@
case 0xC5:
case 0xC6:
case 0xC7:
break; // not handling Tag...
fpu_do_free(emu, nextop-0xC0);
break;
case 0xD0: /* FST ST0, STx */
case 0xD1:
+14
View File
@@ -111,6 +111,20 @@
}
break;
case 0x7C: /* HADDPS Gx, Ex */
nextop = F8;
GET_EX;
GX.f[0] += GX.f[1];
GX.f[1] = GX.f[2] + GX.f[3];
if(EX==&GX) {
GX.f[2] = GX.f[0];
GX.f[3] = GX.f[1];
} else {
GX.f[2] = EX->f[0] + EX->f[1];
GX.f[3] = EX->f[2] + EX->f[3];
}
break;
case 0xC2: /* CMPSD Gx, Ex, Ib */
nextop = F8;
GET_EX;
+11 -2
View File
@@ -15,6 +15,15 @@
GET_EX;
EX->ud[0] = GX.ud[0];
break;
case 0x1E: /* NOP / ENDBR32 / ENDBR64 */
nextop = F8;
GET_ED;
break;
case 0x1F: /* REP NOP */
nextop = F8;
GET_ED;
break;
case 0x2A: /* CVTSI2SS Gx, Ed */
nextop = F8;
@@ -141,7 +150,7 @@
memcpy(EX, &GX, 16); // unaligned...
break;
case 0xBC: /* TZCNT Ew,Gw */
case 0xBC: /* TZCNT Ed,Gd */
CHECK_FLAGS(emu);
nextop = F8;
GET_ED;
@@ -151,7 +160,7 @@
tmp8u = 0;
while(!(tmp32u&(1<<tmp8u))) ++tmp8u;
GD.dword[0] = tmp8u;
CONDITIONAL_SET_FLAG(tmp8u, F_ZF);
CONDITIONAL_SET_FLAG(tmp8u==0, F_ZF);
CLEAR_FLAG(F_CF);
} else {
CLEAR_FLAG(F_ZF);
+49 -65
View File
@@ -12,9 +12,9 @@
#include "x86emu_private.h"
#include "x87emu_private.h"
#include "box86context.h"
#include "x86trace.h"
#include "x86run.h"
#include "x86run_private.h"
#include "callback.h"
typedef struct cleanup_s {
void* f;
@@ -56,8 +56,7 @@ static void internalX86Setup(x86emu_t* emu, box86context_t *context, uintptr_t s
emu->packed_eflags.x32 = 0x202; // default flags?
UnpackFlags(emu);
// own stack?
if(ownstack)
emu->stack = (void*)stack;
emu->stack2free = (ownstack)?(void*)stack:NULL;
emu->init_stack = (void*)stack;
emu->size_stack = stacksize;
// set default value
@@ -66,18 +65,13 @@ static void internalX86Setup(x86emu_t* emu, box86context_t *context, uintptr_t s
// fake init of segments...
emu->segs[_CS] = 0x73;
emu->segs[_DS] = emu->segs[_ES] = emu->segs[_SS] = 0x7b;
emu->segs[_FS] = 0;
emu->segs[_FS] = default_fs;
emu->segs[_GS] = 0x33;
// setup fpu regs
reset_fpu(emu);
// if trace is activated
if(context->x86trace) {
emu->dec = InitX86TraceDecoder(context);
if(!emu->dec)
printf_log(LOG_INFO, "Failed to initialize Zydis decoder and formater, no trace activated\n");
}
}
EXPORTDYN
x86emu_t *NewX86Emu(box86context_t *context, uintptr_t start, uintptr_t stack, int stacksize, int ownstack)
{
printf_log(LOG_DEBUG, "Allocate a new X86 Emu, with EIP=%p and Stack=%p/0x%X\n", (void*)start, (void*)stack, stacksize);
@@ -98,96 +92,80 @@ x86emu_t *NewX86EmuFromStack(x86emu_t* emu, box86context_t *context, uintptr_t s
return emu;
}
EXPORTDYN
void SetupX86Emu(x86emu_t *emu)
{
printf_log(LOG_DEBUG, "Setup X86 Emu\n");
}
void SetTraceEmu(x86emu_t *emu, uintptr_t trace_start, uintptr_t trace_end)
void SetTraceEmu(uintptr_t start, uintptr_t end)
{
if(emu->dec) {
if (trace_end == 0) {
if(my_context->zydis) {
if (end == 0) {
printf_log(LOG_INFO, "Setting trace\n");
} else {
if(trace_end!=1) { // 0-1 is basically no trace, so don't printf it...
printf_log(LOG_INFO, "Setting trace only between %p and %p\n", (void*)trace_start, (void*)trace_end);
if(end!=1) { // 0-1 is basically no trace, so don't printf it...
printf_log(LOG_INFO, "Setting trace only between %p and %p\n", (void*)start, (void*)end);
}
}
}
emu->trace_start = trace_start;
emu->trace_end = trace_end;
trace_start = start;
trace_end = end;
}
void AddCleanup(x86emu_t *emu, void *p)
{
if(emu->clean_sz == emu->clean_cap) {
emu->clean_cap += 4;
emu->cleanups = (cleanup_t*)realloc(emu->cleanups, sizeof(cleanup_t)*emu->clean_cap);
if(my_context->clean_sz == my_context->clean_cap) {
my_context->clean_cap += 4;
my_context->cleanups = (cleanup_t*)realloc(my_context->cleanups, sizeof(cleanup_t)*my_context->clean_cap);
}
emu->cleanups[emu->clean_sz].arg = 0;
emu->cleanups[emu->clean_sz++].f = p;
my_context->cleanups[my_context->clean_sz].arg = 0;
my_context->cleanups[my_context->clean_sz].a = NULL;
my_context->cleanups[my_context->clean_sz++].f = p;
}
void AddCleanup1Arg(x86emu_t *emu, void *p, void* a)
{
if(emu->clean_sz == emu->clean_cap) {
emu->clean_cap += 4;
emu->cleanups = (cleanup_t*)realloc(emu->cleanups, sizeof(cleanup_t)*emu->clean_cap);
if(my_context->clean_sz == my_context->clean_cap) {
my_context->clean_cap += 4;
my_context->cleanups = (cleanup_t*)realloc(my_context->cleanups, sizeof(cleanup_t)*my_context->clean_cap);
}
emu->cleanups[emu->clean_sz].arg = 1;
emu->cleanups[emu->clean_sz].a = a;
emu->cleanups[emu->clean_sz++].f = p;
my_context->cleanups[my_context->clean_sz].arg = 1;
my_context->cleanups[my_context->clean_sz].a = a;
my_context->cleanups[my_context->clean_sz++].f = p;
}
void CallCleanup(x86emu_t *emu, void* p)
{
for(int i=emu->clean_sz-1; i>=0; --i) {
if(p==emu->cleanups[i].f) {
printf_log(LOG_DEBUG, "Calling atexit registered functions for %p mask\n", p);
for(int i=my_context->clean_sz-1; i>=0; --i) {
if(p==my_context->cleanups[i].f) {
printf_log(LOG_DEBUG, "Call cleanup #%d\n", i);
if(emu->cleanups[i].arg)
Push(emu, (uintptr_t)emu->cleanups[i].a);
PushExit(emu);
emu->ip.dword[0] = (uintptr_t)(emu->cleanups[i].f);
Run(emu, 0);
emu->quit = 0;
RunFunctionWithEmu(emu, 0, (uintptr_t)(my_context->cleanups[i].f), my_context->cleanups[i].arg, my_context->cleanups[i].a );
// now remove the cleanup
if(i!=emu->clean_sz-1)
memmove(emu->cleanups+i, emu->cleanups+i+1, (emu->clean_sz-i-1)*sizeof(cleanup_t));
--emu->clean_sz;
return;
if(i!=my_context->clean_sz-1)
memmove(my_context->cleanups+i, my_context->cleanups+i+1, (my_context->clean_sz-i-1)*sizeof(cleanup_t));
--my_context->clean_sz;
}
}
}
void CallAllCleanup(x86emu_t *emu)
{
/* disabling for now...
for(int i=emu->clean_sz-1; i>=0; --i) {
printf_log(LOG_DEBUG, "Calling atexit registered functions\n");
for(int i=my_context->clean_sz-1; i>=0; --i) {
printf_log(LOG_DEBUG, "Call cleanup #%d\n", i);
if(emu->cleanups[i].arg)
Push(emu, (uintptr_t)emu->cleanups[i].a);
PushExit(emu);
emu->ip.dword[0] = (uintptr_t)(emu->cleanups[i].f);
Run(emu);
emu->quit = 0;
RunFunctionWithEmu(emu, 0, (uintptr_t)(my_context->cleanups[i].f), my_context->cleanups[i].arg, my_context->cleanups[i].a );
}
*/
emu->clean_sz = 0;
my_context->clean_sz = 0;
}
static void internalFreeX86(x86emu_t* emu)
{
// stop trace now
if(emu->dec)
DeleteX86TraceDecoder(&emu->dec);
emu->dec = NULL;
// call atexit and fini first!
CallAllCleanup(emu);
free(emu->cleanups);
free(emu->stack);
free(emu->stack2free);
}
EXPORTDYN
void FreeX86Emu(x86emu_t **emu)
{
if(!emu)
@@ -207,8 +185,6 @@ void FreeX86EmuFromStack(x86emu_t **emu)
printf_log(LOG_DEBUG, "Free a X86 Emu from stack (%p)\n", *emu);
internalFreeX86(*emu);
*emu = NULL;
}
void CloneEmu(x86emu_t *newemu, const x86emu_t* emu)
@@ -219,6 +195,7 @@ void CloneEmu(x86emu_t *newemu, const x86emu_t* emu)
memcpy(&newemu->flags, &emu->flags, sizeof(emu->flags));
newemu->old_ip = emu->old_ip;
memcpy(newemu->segs, emu->segs, sizeof(emu->segs));
memset(newemu->segs_clean, 0, sizeof(newemu->segs_clean));
memcpy(newemu->fpu, emu->fpu, sizeof(emu->fpu));
memcpy(newemu->fpu_ld, emu->fpu_ld, sizeof(emu->fpu_ld));
memcpy(newemu->fpu_ll, emu->fpu_ll, sizeof(emu->fpu_ll));
@@ -234,10 +211,9 @@ void CloneEmu(x86emu_t *newemu, const x86emu_t* emu)
newemu->mxcsr = emu->mxcsr;
newemu->quit = emu->quit;
newemu->error = emu->error;
SetTraceEmu(newemu, emu->trace_start, emu->trace_end);
// addapt R_ESP to new stack frame
uintptr_t oldst = (uintptr_t)((emu->stack)?emu->stack:emu->context->stack);
uintptr_t newst = (uintptr_t)((newemu->stack)?newemu->stack:newemu->context->stack);
// adapt R_ESP to new stack frame
uintptr_t oldst = (uintptr_t)((emu->init_stack)?emu->init_stack:emu->context->stack);
uintptr_t newst = (uintptr_t)((newemu->init_stack)?newemu->init_stack:newemu->context->stack);
newemu->regs[_SP].dword[0] = emu->regs[_SP].dword[0] + (intptr_t)(newst - oldst);
}
@@ -294,6 +270,14 @@ uint32_t GetESP(x86emu_t *emu)
{
return R_ESP;
}
void SetFS(x86emu_t *emu, uint16_t v)
{
emu->segs[_FS] = v;
}
uint16_t GetFS(x86emu_t *emu)
{
return emu->segs[_FS];
}
void ResetFlags(x86emu_t *emu)
+12 -11
View File
@@ -3,7 +3,6 @@
#include "regs.h"
typedef struct zydis_dec_s zydis_dec_t;
typedef struct box86context_s box86context_t;
typedef struct i386_ucontext_s i386_ucontext_t;
@@ -11,7 +10,10 @@ typedef struct i386_ucontext_s i386_ucontext_t;
#define ERR_DIVBY0 2
#define ERR_ILLEGAL 4
typedef struct cleanup_s cleanup_t;
#ifdef DYNAREC
#define CSTACK 32
#define CSTACKMASK 31
#endif
typedef struct forkpty_s {
void* amaster;
@@ -52,7 +54,9 @@ typedef struct x86emu_s {
uintptr_t prev2_ip, prev_ip;
#endif
// segments
uint32_t segs[6]; // only 32bits value?
uint32_t segs[6]; // only 32bits value?
uintptr_t segs_offs[6]; // computed offset associate with segment
int segs_clean[6]; // are seg offset clean (1) or does they need to be re-computed (0)?
// emu control
int quit;
int error;
@@ -61,22 +65,19 @@ typedef struct x86emu_s {
int exit;
int quitonlongjmp; // quit if longjmp is called
int longjmp; // if quit because of longjmp
// trace
zydis_dec_t *dec;
uintptr_t trace_start, trace_end;
#ifdef DYNAREC
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
// parent context
box86context_t *context;
// cpu helpers
reg32_t zero;
reg32_t *sbiidx[8];
// atexit and fini functions
cleanup_t *cleanups;
int clean_sz;
int clean_cap;
// scratch stack, used for alignement of double and 64bits ints on arm. 200 elements should be enough
uint32_t scratch[200];
// local stack, do be deleted when emu is freed
void* stack;
void* stack2free; // this is the stack to free (can be NULL)
void* init_stack; // initial stack (owned or not)
uint32_t size_stack; // stack size (owned or not)
+102 -53
View File
@@ -21,13 +21,18 @@
#include "box86context.h"
#include "librarian.h"
#include <elf.h>
#include "elfloader.h"
#include "elfs/elfloader_private.h"
typedef int32_t (*iFpppp_t)(void*, void*, void*, void*);
x86emu_t* x86emu_fork(x86emu_t* emu, int forktype)
{
// execute atforks prepare functions, in reverse order
for (int i=emu->context->atfork_sz-1; i>=0; --i)
EmuCall(emu, emu->context->atforks[i].prepare);
for (int i=my_context->atfork_sz-1; i>=0; --i)
if(my_context->atforks[i].prepare)
EmuCall(emu, my_context->atforks[i].prepare);
int v;
if(forktype==2) {
iFpppp_t forkpty = (iFpppp_t)emu->forkpty_info->f;
@@ -39,13 +44,15 @@ x86emu_t* x86emu_fork(x86emu_t* emu, int forktype)
// error...
} else if(v!=0) {
// execute atforks parent functions
for (int i=0; i<emu->context->atfork_sz; --i)
EmuCall(emu, emu->context->atforks[i].parent);
for (int i=0; i<my_context->atfork_sz; --i)
if(my_context->atforks[i].parent)
EmuCall(emu, my_context->atforks[i].parent);
} else if(v==0) {
// execute atforks child functions
for (int i=0; i<emu->context->atfork_sz; --i)
EmuCall(emu, emu->context->atforks[i].child);
for (int i=0; i<my_context->atfork_sz; --i)
if(my_context->atforks[i].child)
EmuCall(emu, my_context->atforks[i].child);
}
R_EAX = v;
return emu;
@@ -65,9 +72,13 @@ void x86Int3(x86emu_t* emu)
RESET_FLAGS(emu);
wrapper_t w = (wrapper_t)addr;
addr = Fetch32(emu);
if(box86_log>=LOG_DEBUG /*&& emu->trace_end==0 && !emu->context->x86trace*/) {
/* This party can be used to trace only 1 specific lib (but it is quite slow)
elfheader_t *h = FindElfAddress(my_context, *(uintptr_t*)(R_ESP));
int have_trace = 0;
if(h && strstr(ElfName(h), "libMiles")) have_trace = 1;*/
if(box86_log>=LOG_DEBUG /*|| have_trace*/) {
pthread_mutex_lock(&emu->context->mutex_trace);
int tid = syscall(SYS_gettid);
int tid = GetTID();
char buff[256] = "\0";
char buff2[64] = "\0";
char buff3[64] = "\0";
@@ -75,107 +86,138 @@ void x86Int3(x86emu_t* emu)
int post = 0;
int perr = 0;
uint32_t *pu32 = NULL;
const char *s = GetNativeName(emu, (void*)addr);
const char *s = GetNativeName((void*)addr);
if(addr==(uintptr_t)PltResolver) {
snprintf(buff, 256, "%s", " ... ");
} else
if(strstr(s, "SDL_RWFromFile")==s || strstr(s, "SDL_RWFromFile")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%s, %s)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
} else if(strstr(s, "glColor4f")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f, %f, %f)", tid, *(void**)(R_ESP), "glColor4f", *(float*)(R_ESP+4), *(float*)(R_ESP+8), *(float*)(R_ESP+12), *(float*)(R_ESP+16));
snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f, %f, %f)", tid, *(void**)(R_ESP), s, *(float*)(R_ESP+4), *(float*)(R_ESP+8), *(float*)(R_ESP+12), *(float*)(R_ESP+16));
} else if(strstr(s, "glTexCoord2f")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f)", tid, *(void**)(R_ESP), "glTexCoord2f", *(float*)(R_ESP+4), *(float*)(R_ESP+8));
snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f)", tid, *(void**)(R_ESP), s, *(float*)(R_ESP+4), *(float*)(R_ESP+8));
} else if(strstr(s, "glVertex2f")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f)", tid, *(void**)(R_ESP), "glVertex2f", *(float*)(R_ESP+4), *(float*)(R_ESP+8));
snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f)", tid, *(void**)(R_ESP), s, *(float*)(R_ESP+4), *(float*)(R_ESP+8));
} else if(strstr(s, "glVertex3f")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f, %f)", tid, *(void**)(R_ESP), "glVertex3f", *(float*)(R_ESP+4), *(float*)(R_ESP+8), *(float*)(R_ESP+12));
} else if(strstr(s, "__open64")==s || strstr(s, "open64")==s || strstr(s, "open64")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d, %d)", tid, *(void**)(R_ESP), "open64", *(char**)(R_ESP+4), *(int*)(R_ESP+8), *(int*)(R_ESP+12));
snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f, %f)", tid, *(void**)(R_ESP), s, *(float*)(R_ESP+4), *(float*)(R_ESP+8), *(float*)(R_ESP+12));
} else if(strstr(s, "__open64")==s || strcmp(s, "open64")==0) {
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d, %d)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(int*)(R_ESP+8), *(int*)(R_ESP+12));
perr = 1;
} else if(strstr(s, "__open")==s || strstr(s, "open")==s || strstr(s, "open")==s) {
} 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) {
tmp = *(char**)(R_ESP+4);
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d)", tid, *(void**)(R_ESP), s, (tmp)?tmp:"(nil)", *(int*)(R_ESP+8));
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;
} else if(strstr(s, "fopen")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)(R_ESP), "fopen", *(char**)(R_ESP+4), *(char**)(R_ESP+8));
} else if(!strcmp(s, "fopen")) {
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
perr = 1;
} else if(strstr(s, "chdir")==s) {
} else if(!strcmp(s, "fopen64")) {
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
perr = 2;
} else if(!strcmp(s, "chdir")) {
pu32=*(uint32_t**)(R_ESP+4);
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_ESP), "chdir", pu32?((pu32==(uint32_t*)1)?"/1/":(char*)pu32):"/0/");
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_ESP), s, pu32?((pu32==(uint32_t*)1)?"/1/":(char*)pu32):"/0/");
} else if(strstr(s, "getenv")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_ESP), "getenv", *(char**)(R_ESP+4));
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4));
post = 2;
} else if(strstr(s, "pread")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p, %u, %i)", tid, *(void**)(R_ESP), "pread", *(int32_t*)(R_ESP+4), *(void**)(R_ESP+8), *(uint32_t*)(R_ESP+12), *(int32_t*)(R_ESP+16));
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p, %u, %d)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(void**)(R_ESP+8), *(uint32_t*)(R_ESP+12), *(int32_t*)(R_ESP+16));
perr = 1;
} else if(strstr(s, "ioctl")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%d, 0x%x, %p)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(int32_t*)(R_ESP+8), *(void**)(R_ESP+12));
perr = 1;
} else if(strstr(s, "statvfs64")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"), %p)", tid, *(void**)(R_ESP), "statvfs64", *(void**)(R_ESP+4), *(char**)(R_ESP+4), *(void**)(R_ESP+8));
snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"), %p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(char**)(R_ESP+4), *(void**)(R_ESP+8));
} else if(strstr(s, "index")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"), %i(%c))", tid, *(void**)(R_ESP), "index", *(char**)(R_ESP+4), *(char**)(R_ESP+4), *(int32_t*)(R_ESP+8), *(int32_t*)(R_ESP+8));
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), "rindex", *(char**)(R_ESP+4), *(char**)(R_ESP+4), *(int32_t*)(R_ESP+8), *(int32_t*)(R_ESP+8));
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) {
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p(\"%s\"), %p)", tid, *(void**)(R_ESP), "__xstat64", *(int32_t*)(R_ESP+4), *(char**)(R_ESP+8), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
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) {
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p(\"%s\"), %p)", tid, *(void**)(R_ESP), "__lxstat64", *(int32_t*)(R_ESP+4), *(char**)(R_ESP+8), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
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), "sem_timedwait", *(void**)(R_ESP+4), *(void**)(R_ESP+8), pu32?pu32[0]:-1, pu32?pu32[1]:-1);
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, "clock_gettime")==s || strstr(s, "__clock_gettime")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p)", tid, *(void**)(R_ESP), "clock_gettime", *(uint32_t*)(R_ESP+4), *(void**)(R_ESP+8));
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));
perr = 1;
} else if(!strcmp(s, "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")) {
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) {
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)(R_ESP), "strcasecmp", *(char**)(R_ESP+4), *(char**)(R_ESP+8));
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, "gtk_signal_connect_full")) {
snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\", %p, %p, %p, %p, %d, %d)", tid, *(void**)(R_ESP), "gtk_signal_connect_full", *(void**)(R_ESP+4), *(char**)(R_ESP+8), *(void**)(R_ESP+12), *(void**)(R_ESP+16), *(void**)(R_ESP+20), *(void**)(R_ESP+24), *(int32_t*)(R_ESP+28), *(int32_t*)(R_ESP+32));
} else if(strstr(s, "strncasecmp")==s || strstr(s, "__strncasecmp")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\", %u)", tid, *(void**)(R_ESP), "strcasecmp", *(char**)(R_ESP+4), *(char**)(R_ESP+8), *(uint32_t*)(R_ESP+12));
} else if(strstr(s, "strcmp")==s || strstr(s, "__strcmp")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)(R_ESP), "strcmp", *(char**)(R_ESP+4), *(char**)(R_ESP+8));
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, "strstr")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)(R_ESP), "strstr", *(char**)(R_ESP+4), *(char**)(R_ESP+8));
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), "strlen", *(char**)(R_ESP+4), ((R_ESP+4))?(*(char**)(R_ESP+4)):"nil");
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) {
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, %u, %08X...)", tid, *(void**)(R_ESP), "vsnprintf", *(uint32_t*)(R_ESP+4), *(uint32_t*)(R_ESP+8), *(uint32_t*)(R_ESP+12));
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), "vsprintf", *(uint32_t*)(R_ESP+4), *(char**)(R_ESP+8));
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, \"%s\"...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(char**)(R_ESP+8));
pu32 = *(uint32_t**)(R_ESP+4);
post = 3;
} else if(strstr(s, "snprintf")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, %u, %08X...)", tid, *(void**)(R_ESP), "snprintf", *(uint32_t*)(R_ESP+4), *(uint32_t*)(R_ESP+8), *(uint32_t*)(R_ESP+12));
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) {
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, %08X...)", tid, *(void**)(R_ESP), "sprintf", *(uint32_t*)(R_ESP+4), *(uint32_t*)(R_ESP+8));
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, "fprintf")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, \"%s\", ...)", tid, *(void**)(R_ESP), "fprintf", *(uint32_t*)(R_ESP+4), *(char**)(R_ESP+8));
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, "sscanf")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\", ...)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
} else if(strstr(s, "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), "XCreateWindow", *(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));
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));
} else if(strstr(s, "XLoadQueryFont")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\")", tid, *(void**)(R_ESP), "XLoadQueryFont", *(void**)(R_ESP+4), *(char**)(R_ESP+8));
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, "pthread_mutex_lock")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%p)", tid, *(void**)(R_ESP), "pthread_mutex_lock", *(void**)(R_ESP+4));
} else if(strstr(s, "fmodf")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4));
} else if(!strcmp(s, "fmodf")) {
post = 4;
snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f)", tid, *(void**)(R_ESP), "fmodf", *(float*)(R_ESP+4), *(float*)(R_ESP+8));
} else if(strstr(s, "fmod")==s) {
snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f)", tid, *(void**)(R_ESP), s, *(float*)(R_ESP+4), *(float*)(R_ESP+8));
} else if(!strcmp(s, "fmod")) {
post = 4;
snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f)", tid, *(void**)(R_ESP), "fmod", *(double*)(R_ESP+4), *(double*)(R_ESP+12));
snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f)", tid, *(void**)(R_ESP), s, *(double*)(R_ESP+4), *(double*)(R_ESP+12));
} else if(strstr(s, "SDL_GetWindowSurface")==s) {
post = 5;
snprintf(buff, 255, "%04d|%p: Calling %s(%p)", tid, *(void**)(R_ESP), "SDL_GetWindowSurface", *(void**)(R_ESP+4));
snprintf(buff, 255, "%04d|%p: Calling %s(%p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4));
} 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")) {
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 {
snprintf(buff, 255, "%04d|%p: Calling %s (%08X, %08X, %08X...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(uint32_t*)(R_ESP+8), *(uint32_t*)(R_ESP+12));
}
printf_log(LOG_DEBUG, "%s =>", buff);
printf_log(LOG_NONE, "%s =>", buff);
pthread_mutex_unlock(&emu->context->mutex_trace);
w(emu, addr); // some function never come back, so unlock the mutex first!
pthread_mutex_lock(&emu->context->mutex_trace);
@@ -202,9 +244,11 @@ void x86Int3(x86emu_t* emu)
}
break;
}
if(perr && ((int)R_EAX)<0)
snprintf(buff3, 63, " (errno=%d)", errno);
printf_log(LOG_DEBUG, " return 0x%08X%s%s\n", R_EAX, buff2, buff3);
if(perr==1 && ((int)R_EAX)<0)
snprintf(buff3, 63, " (errno=%d:\"%s\")", errno, strerror(errno));
else if(perr==2 && R_EAX==0)
snprintf(buff3, 63, " (errno=%d:\"%s\")", errno, strerror(errno));
printf_log(LOG_NONE, " return 0x%08X%s%s\n", R_EAX, buff2, buff3);
pthread_mutex_unlock(&emu->context->mutex_trace);
} else
w(emu, addr);
@@ -214,3 +258,8 @@ void x86Int3(x86emu_t* emu)
printf_log(LOG_INFO, "Warning, ignoring unsupported Int 3 call\n");
//emu->quit = 1;
}
int GetTID()
{
return syscall(SYS_gettid);
}
+25 -22
View File
@@ -714,7 +714,7 @@ uint8_t rol8(x86emu_t *emu, uint8_t d, uint8_t s)
if((cnt = s % 8) != 0) {
d = (d << cnt) + ((d >> (8 - cnt)) & ((1 << cnt) - 1));
}
CHECK_FLAGS(emu);
RESET_FLAGS(emu);
/* OF flag is set if s == 1; OF = CF _XOR_ MSB of result */
if(s == 1) {
@@ -741,7 +741,7 @@ uint16_t rol16(x86emu_t *emu, uint16_t d, uint8_t s)
if((cnt = s % 16) != 0) {
d = (d << cnt) + ((d >> (16 - cnt)) & ((1 << cnt) - 1));
}
CHECK_FLAGS(emu);
RESET_FLAGS(emu);
/* OF flag is set if s == 1; OF = CF _XOR_ MSB of result */
if(s == 1) {
@@ -768,7 +768,7 @@ uint32_t rol32(x86emu_t *emu, uint32_t d, uint8_t s)
if((cnt = s % 32) != 0) {
d = (d << cnt) + ((d >> (32 - cnt)) & ((1 << cnt) - 1));
}
CHECK_FLAGS(emu);
RESET_FLAGS(emu);
/* OF flag is set if s == 1; OF = CF _XOR_ MSB of result */
if(s == 1) {
@@ -795,7 +795,7 @@ uint8_t ror8(x86emu_t *emu, uint8_t d, uint8_t s)
if((cnt = s % 8) != 0) {
d = (d << (8 - cnt)) + ((d >> (cnt)) & ((1 << (8 - cnt)) - 1));
}
CHECK_FLAGS(emu);
RESET_FLAGS(emu);
/* OF flag is set if s == 1; OF = MSB _XOR_ (M-1)SB of result */
if(s == 1) {
@@ -822,7 +822,7 @@ uint16_t ror16(x86emu_t *emu, uint16_t d, uint8_t s)
if((cnt = s % 16) != 0) {
d = (d << (16 - cnt)) + ((d >> (cnt)) & ((1 << (16 - cnt)) - 1));
}
CHECK_FLAGS(emu);
RESET_FLAGS(emu);
/* OF flag is set if s == 1; OF = MSB _XOR_ (M-1)SB of result */
if(s == 1) {
@@ -849,7 +849,7 @@ uint32_t ror32(x86emu_t *emu, uint32_t d, uint8_t s)
if((cnt = s % 32) != 0) {
d = (d << (32 - cnt)) + ((d >> (cnt)) & ((1 << (32 - cnt)) - 1));
}
CHECK_FLAGS(emu);
RESET_FLAGS(emu);
/* OF flag is set if s == 1; OF = MSB _XOR_ (M-1)SB of result */
if(s == 1) {
@@ -1153,7 +1153,7 @@ Implements the IDIV instruction and side effects.
****************************************************************************/
void idiv8(x86emu_t *emu, uint8_t s)
{
int32_t dvd, div, mod;
int32_t dvd, quot, mod;
RESET_FLAGS(emu);
dvd = (int16_t)R_AX;
@@ -1161,13 +1161,14 @@ void idiv8(x86emu_t *emu, uint8_t s)
INTR_RAISE_DIV0(emu);
return;
}
div = dvd / (int8_t)s;
mod = dvd % (int8_t)s;
if (abs(div) > 0x7f) {
div_t p = div(dvd, (int8_t)s);
quot = p.quot;
mod = p.rem;
if (abs(quot) > 0x7f) {
INTR_RAISE_DIV0(emu);
return;
}
R_AL = (int8_t) div;
R_AL = (int8_t) quot;
R_AH = (int8_t) mod;
}
@@ -1177,25 +1178,26 @@ Implements the IDIV instruction and side effects.
****************************************************************************/
void idiv16(x86emu_t *emu, uint16_t s)
{
int32_t dvd, div, mod;
int32_t dvd, quot, mod;
dvd = (((int32_t)R_DX) << 16) | R_AX;
if (s == 0) {
INTR_RAISE_DIV0(emu);
return;
}
div = dvd / (int16_t)s;
mod = dvd % (int16_t)s;
if (abs(div) > 0x7fff) {
div_t p = div(dvd, (int16_t)s);
quot = p.quot;
mod = p.rem;
if (abs(quot) > 0x7fff) {
INTR_RAISE_DIV0(emu);
return;
}
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_SF);
CONDITIONAL_SET_FLAG(div == 0, F_ZF);
CONDITIONAL_SET_FLAG(quot == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
R_AX = (uint16_t)div;
R_AX = (uint16_t)quot;
R_DX = (uint16_t)mod;
}
@@ -1205,7 +1207,7 @@ Implements the IDIV instruction and side effects.
****************************************************************************/
void idiv32(x86emu_t *emu, uint32_t s)
{
int64_t dvd, div, mod;
int64_t dvd, quot, mod;
RESET_FLAGS(emu);
dvd = (((int64_t)R_EDX) << 32) | R_EAX;
@@ -1213,9 +1215,10 @@ void idiv32(x86emu_t *emu, uint32_t s)
INTR_RAISE_DIV0(emu);
return;
}
div = dvd / (int32_t)s;
mod = dvd % (int32_t)s;
if (llabs(div) > 0x7fffffff) {
lldiv_t p = lldiv(dvd, (int32_t)s);
quot = p.quot;
mod = p.rem;
if (llabs(quot) > 0x7fffffff) {
INTR_RAISE_DIV0(emu);
return;
}
@@ -1225,7 +1228,7 @@ void idiv32(x86emu_t *emu, uint32_t s)
SET_FLAG(F_ZF);
CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
R_EAX = (uint32_t)div;
R_EAX = (uint32_t)quot;
R_EDX = (uint32_t)mod;
}
+17 -11
View File
@@ -81,8 +81,6 @@ Implements the AND instruction and side effects.
****************************************************************************/
static inline uint32_t and32(x86emu_t *emu, uint32_t d, uint32_t s)
{
register uint32_t res; /* all operands in native machine order */
emu->res = d & s;
emu->df = d_and32;
@@ -161,6 +159,14 @@ Implements the INC instruction and side effects.
****************************************************************************/
static inline uint32_t inc32(x86emu_t *emu, uint32_t d)
{
if(emu->df == d_shr32) {
// workaround for some wine trickery
uint32_t cnt = emu->op2;
if (cnt > 0) {
uint32_t cc = emu->op1 & (1 << (cnt - 1));
CONDITIONAL_SET_FLAG(cc, F_CF);
}
}
emu->res = d + 1;
emu->op1 = d;
emu->df = d_inc32;
@@ -507,7 +513,7 @@ static inline uint32_t xor32(x86emu_t *emu, uint32_t d, uint32_t s)
REMARKS:
Implements the IMUL instruction and side effects.
****************************************************************************/
static void imul8(x86emu_t *emu, uint8_t s)
static inline void imul8(x86emu_t *emu, uint8_t s)
{
emu->df = d_imul8;
R_AX = emu->res = (int16_t)(int8_t)R_AL * (int8_t)s;
@@ -516,7 +522,7 @@ static void imul8(x86emu_t *emu, uint8_t s)
REMARKS:
Implements the IMUL instruction and side effects.
****************************************************************************/
static void imul16_eax(x86emu_t *emu, uint16_t s)
static inline void imul16_eax(x86emu_t *emu, uint16_t s)
{
emu->df = d_imul16;
emu->res = (int32_t)(int16_t)R_AX * (int16_t)s;
@@ -527,7 +533,7 @@ static void imul16_eax(x86emu_t *emu, uint16_t s)
REMARKS:
Implements the IMUL instruction and side effects.
****************************************************************************/
static uint16_t imul16(x86emu_t *emu, uint16_t op1, uint16_t op2)
static inline uint16_t imul16(x86emu_t *emu, uint16_t op1, uint16_t op2)
{
emu->df = d_imul16;
emu->res = (int32_t)(int16_t)op1 * (int16_t)op2;
@@ -537,7 +543,7 @@ static uint16_t imul16(x86emu_t *emu, uint16_t op1, uint16_t op2)
REMARKS:
Implements the IMUL instruction and side effects.
****************************************************************************/
static void imul32_direct(uint32_t *res_lo, uint32_t* res_hi,uint32_t d, uint32_t s)
static inline void imul32_direct(uint32_t *res_lo, uint32_t* res_hi,uint32_t d, uint32_t s)
{
int64_t res = (int64_t)(int32_t)d * (int32_t)s;
@@ -548,7 +554,7 @@ static void imul32_direct(uint32_t *res_lo, uint32_t* res_hi,uint32_t d, uint32_
REMARKS:
Implements the IMUL instruction and side effects.
****************************************************************************/
static uint32_t imul32(x86emu_t *emu, uint32_t op1, uint32_t op2)
static inline uint32_t imul32(x86emu_t *emu, uint32_t op1, uint32_t op2)
{
emu->df = d_imul32;
imul32_direct(&emu->res,&emu->op1,op1,op2);
@@ -558,7 +564,7 @@ static uint32_t imul32(x86emu_t *emu, uint32_t op1, uint32_t op2)
REMARKS:
Implements the IMUL instruction and side effects.
****************************************************************************/
static void imul32_eax(x86emu_t *emu, uint32_t s)
static inline void imul32_eax(x86emu_t *emu, uint32_t s)
{
emu->df = d_imul32;
imul32_direct(&R_EAX,&R_EDX,R_EAX,s);
@@ -569,7 +575,7 @@ static void imul32_eax(x86emu_t *emu, uint32_t s)
REMARKS:
Implements the MUL instruction and side effects.
****************************************************************************/
static void mul8(x86emu_t *emu, uint8_t s)
static inline void mul8(x86emu_t *emu, uint8_t s)
{
emu->df = d_mul8;
R_AX = emu->res = (uint16_t)(R_AL) * s;
@@ -578,7 +584,7 @@ static void mul8(x86emu_t *emu, uint8_t s)
REMARKS:
Implements the MUL instruction and side effects.
****************************************************************************/
static void mul16(x86emu_t *emu, uint16_t s)
static inline void mul16(x86emu_t *emu, uint16_t s)
{
emu->df = d_mul16;
emu->res = (uint32_t)R_AX * s;
@@ -589,7 +595,7 @@ static void mul16(x86emu_t *emu, uint16_t s)
REMARKS:
Implements the MUL instruction and side effects.
****************************************************************************/
static void mul32_eax(x86emu_t *emu, uint32_t s)
static inline void mul32_eax(x86emu_t *emu, uint32_t s)
{
emu->df = d_mul32;
uint64_t res = (uint64_t)R_EAX * s;
+235 -81
View File
@@ -18,6 +18,7 @@
#include "x86trace.h"
#include "x87emu_private.h"
#include "box86context.h"
#include "my_cpuid.h"
int my_setcontext(x86emu_t* emu, void* ucp);
@@ -26,7 +27,6 @@ int Run(x86emu_t *emu, int step)
uint8_t opcode;
uint8_t nextop;
reg32_t *oped;
reg32_t ea1;
uint8_t tmp8u, tmp8u2;
int8_t tmp8s;
uint16_t tmp16u, tmp16u2;
@@ -35,7 +35,7 @@ int Run(x86emu_t *emu, int step)
int32_t tmp32s, tmp32s2;
uint64_t tmp64u;
int64_t tmp64s;
uintptr_t ip, old_ip;
uintptr_t ip;
double d;
float f;
int64_t ll;
@@ -45,8 +45,6 @@ int Run(x86emu_t *emu, int step)
if(emu->quit)
return 0;
old_ip = 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);
#define F8 *(uint8_t*)(ip++)
@@ -63,23 +61,23 @@ int Run(x86emu_t *emu, int step)
static const void* baseopcodes[256] ={
&&_0x00_0, &&_0x00_1, &&_0x00_2, &&_0x00_3, &&_0x00_4, &&_0x00_5, &&_0x06, &&_0x07, //0x00-0x07
&&_0x08_0, &&_0x08_1, &&_0x08_2, &&_0x08_3, &&_0x08_4, &&_0x08_5, &&_default, &&_0x0F, //0x08-0x0F
&&_0x10_0, &&_0x10_1, &&_0x10_2, &&_0x10_3, &&_0x10_4, &&_0x10_5, &&_default, &&_default, //0x10-0x17
&&_0x08_0, &&_0x08_1, &&_0x08_2, &&_0x08_3, &&_0x08_4, &&_0x08_5, &&_0x0E, &&_0x0F, //0x08-0x0F
&&_0x10_0, &&_0x10_1, &&_0x10_2, &&_0x10_3, &&_0x10_4, &&_0x10_5, &&_0x16, &&_0x17, //0x10-0x17
&&_0x18_0, &&_0x18_1, &&_0x18_2, &&_0x18_3, &&_0x18_4, &&_0x18_5, &&_0x1E, &&_0x1F, //0x18-0x1F
&&_0x20_0, &&_0x20_1, &&_0x20_2, &&_0x20_3, &&_0x20_4, &&_0x20_5, &&_0x26, &&_0x27, //0x20-0x27
&&_0x28_0, &&_0x28_1, &&_0x28_2, &&_0x28_3, &&_0x28_4, &&_0x28_5, &&_0x2E, &&_0x2F, //0x28-0x2F
&&_0x30_0, &&_0x30_1, &&_0x30_2, &&_0x30_3, &&_0x30_4, &&_0x30_5, &&_default, &&_0x37, //0x30-0x37
&&_0x38, &&_0x39, &&_0x3A, &&_0x3B, &&_0x3C, &&_0x3D, &&_default, &&_0x3F, //0x38-0x3F
&&_0x30_0, &&_0x30_1, &&_0x30_2, &&_0x30_3, &&_0x30_4, &&_0x30_5, &&_0x36, &&_0x37, //0x30-0x37
&&_0x38, &&_0x39, &&_0x3A, &&_0x3B, &&_0x3C, &&_0x3D, &&_0x3E, &&_0x3F, //0x38-0x3F
&&_0x40, &&_0x41, &&_0x42, &&_0x43, &&_0x44, &&_0x45, &&_0x46, &&_0x47,
&&_0x48, &&_0x49, &&_0x4A, &&_0x4B, &&_0x4C, &&_0x4D, &&_0x4E, &&_0x4F,
&&_0x50, &&_0x51, &&_0x52, &&_0x53, &&_0x54, &&_0x55, &&_0x56, &&_0x57,
&&_0x58, &&_0x59, &&_0x5A, &&_0x5B, &&_0x5C, &&_0x5D, &&_0x5E, &&_0x5F,
&&_0x60, &&_0x61, &&_default, &&_default, &&_0x64, &&_0x65, &&_0x66, &&_0x67,
&&_0x68, &&_0x69, &&_0x6A, &&_0x6B, &&_0x6C, &&_0x6D, &&_default, &&_default, //0x68-0x6F
&&_0x60, &&_0x61, &&_0x62, &&_default, &&_0x64, &&_0x65, &&_0x66, &&_0x67,
&&_0x68, &&_0x69, &&_0x6A, &&_0x6B, &&_0x6C, &&_0x6D, &&_0x6E, &&_0x6F, //0x68-0x6F
&&_0x70_0, &&_0x70_1, &&_0x70_2, &&_0x70_3, &&_0x70_4, &&_0x70_5, &&_0x70_6, &&_0x70_7, //0x70-0x77
&&_0x70_8, &&_0x70_9, &&_0x70_A, &&_0x70_B, &&_0x70_C, &&_0x70_D, &&_0x70_E, &&_0x70_F, //0x78-0x7F
&&_0x80, &&_0x81, &&_default, &&_0x83, &&_0x84, &&_0x85, &&_0x86, &&_0x87,
&&_0x88, &&_0x89, &&_0x8A, &&_0x8B, &&_default, &&_0x8D, &&_0x8E, &&_0x8F,
&&_0x80, &&_0x81, &&_0x82, &&_0x83, &&_0x84, &&_0x85, &&_0x86, &&_0x87,
&&_0x88, &&_0x89, &&_0x8A, &&_0x8B, &&_0x8C, &&_0x8D, &&_0x8E, &&_0x8F,
&&_0x90, &&_0x91, &&_0x92, &&_0x93, &&_0x94, &&_0x95, &&_0x96, &&_0x97,
&&_0x98, &&_0x99, &&_default, &&_0x9B, &&_0x9C, &&_0x9D, &&_0x9E, &&_0x9F,
&&_0xA0, &&_0xA1, &&_0xA2, &&_0xA3, &&_0xA4, &&_0xA5, &&_0xA6, &&_0xA7,
@@ -87,24 +85,24 @@ int Run(x86emu_t *emu, int step)
&&_0xB0, &&_0xB1, &&_0xB2, &&_0xB3, &&_0xB4, &&_0xB5, &&_0xB6, &&_0xB7,
&&_0xB8, &&_0xB9, &&_0xBA, &&_0xBB, &&_0xBC, &&_0xBD, &&_0xBE, &&_0xBF,
&&_0xC0, &&_0xC1, &&_0xC2, &&_0xC3, &&_default, &&_default, &&_0xC6, &&_0xC7,
&&_0xC8, &&_0xC9, &&_default, &&_default, &&_0xCC, &&_0xCD, &&_default, &&_default, //0xC8-0xCF
&&_0xC8, &&_0xC9, &&_default, &&_default, &&_0xCC, &&_0xCD, &&_default, &&_0xCF, //0xC8-0xCF
&&_0xD0, &&_0xD1, &&_0xD2, &&_0xD3, &&_0xD4, &&_0xD5, &&_default, &&_0xD7,
&&_0xD8, &&_0xD9, &&_0xDA, &&_0xDB, &&_0xDC, &&_0xDD, &&_0xDE, &&_0xDF,
&&_0xE0, &&_0xE1, &&_0xE2, &&_0xE3, &&_default, &&_0xE5, &&_default, &&_default,
&&_0xE8, &&_0xE9, &&_default, &&_0xEB, &&_default, &&_default, &&_default, &&_default,
&&_0xF0, &&_default, &&_0xF2, &&_0xF3, &&_default, &&_0xF5, &&_0xF6, &&_0xF7,
&&_0xF8, &&_0xF9, &&_default, &&_default, &&_0xFC, &&_0xFD, &&_0xFE, &&_0xFF
&&_0xE0, &&_0xE1, &&_0xE2, &&_0xE3, &&_0xE4, &&_0xE5, &&_0xE6, &&_0xE7,
&&_0xE8, &&_0xE9, &&_default, &&_0xEB, &&_0xEC, &&_0xED, &&_default, &&_default,
&&_0xF0, &&_0xF1, &&_0xF2, &&_0xF3, &&_default, &&_0xF5, &&_0xF6, &&_0xF7,
&&_0xF8, &&_0xF9, &&_0xFA, &&_0xFB, &&_0xFC, &&_0xFD, &&_0xFE, &&_0xFF
};
static const void* opcodes0f[256] = {
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x00-0x07
&&_0f_0x00, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x00-0x07
&&_default, &&_default, &&_default, &&_0f_0x0B, &&_default ,&&_default, &&_default, &&_default, //0x08-0x0F
&&_0f_0x10, &&_0f_0x11, &&_0f_0x12, &&_0f_0x13, &&_0f_0x14, &&_0f_0x15, &&_0f_0x16, &&_0f_0x17, //0x10-0x17
&&_0f_0x18, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_0f_0x1F, //0x18-0x1F
&&_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
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x38-0x3F
&&_0f_0x38, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //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
@@ -117,17 +115,17 @@ int Run(x86emu_t *emu, int step)
&&_0f_0x80_8, &&_0f_0x80_9, &&_0f_0x80_A, &&_0f_0x80_B, &&_0f_0x80_C, &&_0f_0x80_D, &&_0f_0x80_E, &&_0f_0x80_F,
&&_0f_0x90_0, &&_0f_0x90_1, &&_0f_0x90_2, &&_0f_0x90_3, &&_0f_0x90_4, &&_0f_0x90_5, &&_0f_0x90_6, &&_0f_0x90_7,
&&_0f_0x90_8, &&_0f_0x90_9, &&_0f_0x90_A, &&_0f_0x90_B, &&_0f_0x90_C, &&_0f_0x90_D, &&_0f_0x90_E, &&_0f_0x90_F,
&&_default, &&_default, &&_0f_0xA2, &&_0f_0xA3, &&_0f_0xA4, &&_0f_0xA5, &&_default, &&_default, //0xA0-0xA7
&&_default, &&_default, &&_default, &&_0f_0xAB, &&_0f_0xAC, &&_0f_0xAD, &&_0f_0xAE, &&_0f_0xAF,
&&_0f_0xA0, &&_0f_0xA1, &&_0f_0xA2, &&_0f_0xA3, &&_0f_0xA4, &&_0f_0xA5, &&_default, &&_default, //0xA0-0xA7
&&_0f_0xA8, &&_0f_0xA9, &&_default, &&_0f_0xAB, &&_0f_0xAC, &&_0f_0xAD, &&_0f_0xAE, &&_0f_0xAF,
&&_0f_0xB0, &&_0f_0xB1, &&_default, &&_0f_0xB3, &&_default, &&_default, &&_0f_0xB6, &&_0f_0xB7,
&&_default, &&_default, &&_0f_0xBA, &&_0f_0xBB, &&_0f_0xBC, &&_0f_0xBD, &&_0f_0xBE, &&_0f_0xBF,
&&_0f_0xC0, &&_0f_0xC1, &&_0f_0xC2, &&_default, &&_0f_0xC4, &&_0f_0xC5, &&_0f_0xC6, &&_0f_0xC7,
&&_0f_0xC8, &&_0f_0xC9, &&_0f_0xCA, &&_0f_0xCB, &&_0f_0xCC, &&_0f_0xCD, &&_0f_0xCE, &&_0f_0xCF, //0xC8-0xCF
&&_default, &&_0f_0xD1, &&_0f_0xD2, &&_0f_0xD3, &&_0f_0xD4 ,&&_0f_0xD5, &&_default, &&_default, //0xD0-0xD7
&&_default, &&_0f_0xD1, &&_0f_0xD2, &&_0f_0xD3, &&_0f_0xD4 ,&&_0f_0xD5, &&_default, &&_0f_0xD7, //0xD0-0xD7
&&_0f_0xD8, &&_0f_0xD9, &&_default, &&_0f_0xDB, &&_0f_0xDC ,&&_0f_0xDD, &&_default, &&_0f_0xDF, //0xD8-0xDF
&&_0f_0xE0, &&_0f_0xE1, &&_0f_0xE2, &&_0f_0xE3, &&_0f_0xE4 ,&&_0f_0xE5, &&_default, &&_default, //0xE0-0xE7
&&_0f_0xE8, &&_0f_0xE9, &&_default, &&_0f_0xEB, &&_0f_0xEC ,&&_0f_0xED, &&_default, &&_0f_0xEF, //0xE8-0xEF
&&_default, &&_0f_0xF1, &&_0f_0xF2, &&_0f_0xF3, &&_0f_0xF4 ,&&_0f_0xF5, &&_0f_0xF6, &&_default, //0xF0-0xF7
&&_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
};
@@ -138,20 +136,20 @@ int Run(x86emu_t *emu, int step)
&&_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, &&_default, &&_default, //0x30-0x37
&&_default, &&_66_0x30_1, &&_default, &&_66_0x30_3, &&_default ,&&_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
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_66_0x66, &&_default, //0x60-0x67
&&_66_0x60, &&_66_0x61, &&_default, &&_default, &&_default ,&&_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
&&_default, &&_66_0x81, &&_default, &&_66_0x83, &&_default, &&_66_0x85, &&_default, &&_66_0x87,
&&_default, &&_66_0x89, &&_default, &&_66_0x8B, &&_66_0x8C, &&_default, &&_66_0x8E, &&_66_0x8F,
&&_66_0x90, &&_default, &&_66_0x92, &&_default, &&_default, &&_default, &&_default, &&_default,
&&_66_0x98, &&_66_0x99, &&_default, &&_default, &&_66_0x9C, &&_default, &&_default, &&_default, //0x98-0x9F
&&_66_0x90, &&_66_0x91, &&_66_0x92, &&_66_0x93, &&_66_0x94, &&_66_0x95, &&_66_0x96, &&_66_0x97,
&&_66_0x98, &&_66_0x99, &&_default, &&_default, &&_66_0x9C, &&_66_0x9D, &&_default, &&_default, //0x98-0x9F
&&_default, &&_66_0xA1, &&_default, &&_66_0xA3, &&_default, &&_66_0xA5, &&_default, &&_66_0xA7,
&&_default, &&_66_0xA9, &&_default, &&_66_0xAB, &&_default, &&_66_0xAD, &&_default, &&_66_0xAF, //0xA8-0xAF
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xB0-0xB7
@@ -163,7 +161,7 @@ int Run(x86emu_t *emu, int step)
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xE0-0xE7
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xE8-0xEF
&&_default, &&_default, &&_66_0xF2, &&_66_0xF3, &&_default, &&_default, &&_default, &&_66_0xF7,
&&_default, &&_default, &&_default, &&_default, &&_default, &&_default, &&_default, &&_66_0xFF
&&_66_0xF8, &&_66_0xF9, &&_default, &&_default, &&_default, &&_default, &&_default, &&_66_0xFF
};
static const void* opcodes660f[256] = {
@@ -190,15 +188,15 @@ int Run(x86emu_t *emu, int step)
&&_default, &&_default, &&_default, &&_6f_0xA3, &&_6f_0xA4, &&_6f_0xA5, &&_default, &&_default,
&&_default, &&_default, &&_default, &&_6f_0xAB, &&_6f_0xAC, &&_6f_0xAD, &&_default, &&_6f_0xAF,
&&_default, &&_6f_0xB1, &&_default, &&_6f_0xB3, &&_default, &&_default, &&_6f_0xB6, &&_default,
&&_default, &&_default, &&_default, &&_6f_0xBB, &&_6f_0xBC, &&_6f_0xBD, &&_6f_0xBE, &&_default, //0xB8-0xBF
&&_default, &&_default, &&_6f_0xBA, &&_6f_0xBB, &&_6f_0xBC, &&_6f_0xBD, &&_6f_0xBE, &&_default, //0xB8-0xBF
&&_default, &&_6f_0xC1, &&_6f_0xC2, &&_default, &&_6f_0xC4, &&_6f_0xC5, &&_6f_0xC6, &&_default,
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xC8-0xCF
&&_default, &&_6f_0xD1, &&_6f_0xD2, &&_6f_0xD3, &&_6f_0xD4, &&_6f_0xD5, &&_6f_0xD6, &&_6f_0xD7,
&&_6f_0xD8, &&_6f_0xD9, &&_default, &&_6f_0xDB, &&_6f_0xDC, &&_default, &&_6f_0xDE, &&_6f_0xDF,
&&_default, &&_6f_0xE1, &&_6f_0xE2, &&_default, &&_default, &&_6f_0xE5, &&_6f_0xE6, &&_6f_0xE7,
&&_6f_0xE0, &&_6f_0xE1, &&_6f_0xE2, &&_6f_0xE3, &&_default, &&_6f_0xE5, &&_6f_0xE6, &&_6f_0xE7,
&&_6f_0xE8, &&_6f_0xE9, &&_6f_0xEA, &&_6f_0xEB, &&_6f_0xEC, &&_6f_0xED, &&_6f_0xEE, &&_6f_0xEF,
&&_default, &&_6f_0xF1, &&_6f_0xF2, &&_6f_0xF3, &&_6f_0xF4, &&_6f_0xF5, &&_6f_0xF6, &&_6f_0xF7,
&&_default, &&_6f_0xF9, &&_6f_0xFA, &&_6f_0xFB, &&_6f_0xFC, &&_6f_0xFD, &&_6f_0xFE, &&_default
&&_6f_0xF8, &&_6f_0xF9, &&_6f_0xFA, &&_6f_0xFB, &&_6f_0xFC, &&_6f_0xFD, &&_6f_0xFE, &&_default
};
x86emurun:
@@ -206,17 +204,18 @@ x86emurun:
// UnpackFlags(emu);
#ifdef HAVE_TRACE
_trace:
__builtin_prefetch((void*)ip, 0, 0);
emu->prev2_ip = emu->prev_ip;
emu->prev_ip = old_ip;
old_ip = ip;
if(emu->dec && (
(emu->trace_end == 0)
|| ((ip >= emu->trace_start) && (ip < emu->trace_end))) )
emu->prev_ip = R_EIP;
R_EIP=ip;
if(my_context->dec && (
(trace_end == 0)
|| ((ip >= trace_start) && (ip < trace_end))) )
PrintTrace(emu, ip, 0);
#define NEXT __builtin_prefetch((void*)ip, 0, 0); goto _trace;
#define NEXT goto _trace
#else
#define NEXT old_ip = ip; __builtin_prefetch((void*)ip, 0, 0); goto *baseopcodes[(opcode=F8)];
#define NEXT goto *baseopcodes[(R_EIP=ip, opcode=F8)]
#endif
#include "modrm.h"
@@ -295,17 +294,30 @@ _trace:
NEXT;
_0x07: /* POP ES */
emu->segs[_ES] = Pop(emu); // no check, no use....
emu->segs_clean[_ES] = 0;
NEXT;
_0x0E: /* PUSH CS */
Push(emu, emu->segs[_CS]);
NEXT;
_0x0F: /* More instructions */
#include "run0f.h"
NEXT;
_0x16: /* PUSH SS */
Push(emu, emu->segs[_SS]); // even if a segment is a 16bits, a 32bits push/pop is done
NEXT;
_0x17: /* POP SS */
emu->segs[_SS] = Pop(emu); // no check, no use....
emu->segs_clean[_SS] = 0;
NEXT;
_0x1E: /* PUSH DS */
Push(emu, emu->segs[_DS]); // even if a segment is a 16bits, a 32bits push/pop is done
NEXT;
_0x1F: /* POP DS */
emu->segs[_DS] = Pop(emu); // no check, no use....
emu->segs_clean[_DS] = 0;
NEXT;
_0x26: /* ES: */
@@ -315,18 +327,24 @@ _trace:
NEXT;
_0x2E: /* CS: */
// Can also happens before a condition branch: Branch Not Taken Hint
NEXT; //ignored...
_0x2F: /* DAS */
R_AL = das8(emu, R_AL);
NEXT;
_0x36: /* SS: */
NEXT;
_0x37: /* AAA */
R_AX = aaa16(emu, R_AX);
NEXT;
_0x3E: /* DS: */
// Can also happens before a condition branch: Branch Taken Hint
NEXT;
_0x3F: /* AAS */
R_AX = aas16(emu, R_AX);
NEXT;
_0x40:
_0x41:
_0x42:
@@ -395,28 +413,21 @@ _trace:
R_ECX = Pop(emu);
R_EAX = Pop(emu);
NEXT;
_0x62: /* BOUND Gd, Ed */
nextop = F8;
GET_ED;
// ignoring the test for now
NEXT;
_0x64: /* FS: */
switch(F8)
{
case 0xA1:
tmp32s = F32S;
R_EAX = *(uint32_t*)((emu->segs[_FS]) + tmp32s);
break;
case 0x89:
nextop = F8;
GET_ED_OFFS(emu->segs[_FS]);
ED->dword[0] = GD.dword[0];
break;
default:
UnimpOpcode(emu);
}
emu->old_ip = R_EIP;
R_EIP = ip-1;
RunFS(emu); // implemented in Run66.c
ip = R_EIP;
if(emu->quit) goto fini;
NEXT;
_0x65: /* GS: */
emu->old_ip = old_ip;
R_EIP = ip;
emu->old_ip = R_EIP;
R_EIP = ip-1;
RunGS(emu); // implemented in Run66.c
ip = R_EIP;
if(emu->quit) goto fini;
@@ -425,8 +436,8 @@ _trace:
_0x66: /* Prefix to change width of intructions, so here, down to 16bits */
#include "run66.h"
_0x67: /* Prefix to change width of registers */
emu->old_ip = old_ip;
R_EIP = ip;
emu->old_ip = R_EIP;
R_EIP = ip-1; // don't count 0x67 yet
Run67(emu); // implemented in Run66.c
ip = R_EIP;
if(emu->quit) goto fini;
@@ -452,19 +463,33 @@ _trace:
GD.dword[0] = imul32(emu, ED->dword[0], (uint32_t)tmp32s);
NEXT;
_0x6C: /* INSB */
*(int8_t*)R_EDI = 0; // faking port read
*(int8_t*)(R_EDI+GetESBaseEmu(emu)) = 0; // faking port read, using explicit ES segment
if(ACCESS_FLAG(F_DF))
R_EDI-=1;
else
R_EDI+=1;
NEXT;
_0x6D: /* INSD */
*(int32_t*)R_EDI = 0; // faking port read
*(int32_t*)(R_EDI+GetESBaseEmu(emu)) = 0; // faking port read, using explicit ES segment
if(ACCESS_FLAG(F_DF))
R_EDI-=4;
else
R_EDI+=4;
NEXT;
_0x6E: /* OUTSB */
// faking port write, using explicit ES segment
if(ACCESS_FLAG(F_DF))
R_ESI-=1;
else
R_ESI+=1;
NEXT;
_0x6F: /* OUTSD */
// faking port write, using explicit ES segment
if(ACCESS_FLAG(F_DF))
R_ESI-=4;
else
R_ESI+=4;
NEXT;
#define GOCOND(BASE, PREFIX, CONDITIONAL) \
_##BASE##_0: \
@@ -555,6 +580,7 @@ _trace:
_0x80: /* GRP Eb,Ib */
_0x82: // 0x82 and 0x80 are the same opcodes it seems?
nextop = F8;
GET_EB;
tmp8u = F8;
@@ -643,7 +669,11 @@ _trace:
GET_ED;
GD.dword[0] = ED->dword[0];
NEXT;
_0x8C: /* MOV Ed, Seg */
nextop = F8;
GET_ED;
ED->dword[0] = emu->segs[((nextop&0x38)>>3)];
NEXT;
_0x8D: /* LEA Gd,M */
nextop = F8;
GET_ED;
@@ -653,6 +683,7 @@ _trace:
nextop = F8;
GET_EW;
emu->segs[((nextop&0x38)>>3)] = EW->word[0];
emu->segs_clean[((nextop&0x38)>>3)] = 0;
NEXT;
_0x8F: /* POP Ed */
nextop = F8;
@@ -881,7 +912,7 @@ _trace:
NEXT;
_0xCC: /* INT 3 */
emu->old_ip = old_ip;
emu->old_ip = R_EIP;
R_EIP = ip;
x86Int3(emu);
ip = R_EIP;
@@ -890,14 +921,15 @@ _trace:
_0xCD: /* INT Ib */
nextop = F8;
if(nextop == 0x80) {
emu->old_ip = old_ip;
emu->old_ip = R_EIP;
R_EIP = ip;
x86Syscall(emu);
ip = R_EIP;
if(emu->quit) goto fini;
} else {
printf_log(LOG_NONE, "Unsupported Int %02Xh\n", nextop);
emu->old_ip = old_ip;
int tid = GetTID();
printf_log(LOG_NONE, "%04d|%p: Ignoring Unsupported Int %02Xh\n", tid, (void*)ip, nextop);
emu->old_ip = R_EIP;
R_EIP = ip;
emu->quit = 1;
emu->error |= ERR_UNIMPL;
@@ -905,6 +937,14 @@ _trace:
}
NEXT;
_0xCF: /* IRET */
ip = Pop(emu);
emu->segs[_CS] = Pop(emu);
emu->segs_clean[_CS] = 0;
emu->packed_eflags.x32 = ((Pop(emu) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1
UnpackFlags(emu);
RESET_FLAGS(emu);
NEXT;
_0xD0: /* GRP2 Eb,1 */
_0xD2: /* GRP2 Eb,CL */
nextop = F8;
@@ -1000,12 +1040,22 @@ _trace:
STEP
}
NEXT;
_0xE4: /* IN AL, Ib */
tmp32s = F8; // port address
R_AL = 0; // nothing... should do a warning maybe?
NEXT;
_0xE5: /* IN EAX, Ib */
tmp32s = F8; // port address
R_EAX = 0; // nothing... should do a warning maybe?
NEXT;
_0xE6: /* OUT Ib, AL */
tmp32s = F8; // port address
//nothing goes out...
NEXT;
_0xE7: /* OUT Ib, EAX */
tmp32s = F8; // port address
//nothing goes out...
NEXT;
_0xE8: /* CALL Id */
tmp32s = F32S; // call is relative
Push(emu, ip);
@@ -1023,15 +1073,23 @@ _trace:
ip += tmp32s;
STEP
NEXT;
_0xEC: /* IN AL, DX */
R_AL = 0; // nothing... should do a warning maybe?
NEXT;
_0xED: /* IN EAX, DX */
R_EAX = 0; // nothing... should do a warning maybe?
NEXT;
_0xF0: /* LOCK */
emu->old_ip = old_ip;
R_EIP = ip;
emu->old_ip = R_EIP;
R_EIP = ip-1; // dont't count F0 yet
RunLock(emu); // implemented in Run66.c
ip = R_EIP;
if(emu->quit) goto fini;
NEXT;
_0xF1: /* INT1 */
// does nothing for now
NEXT;
_0xF2: /* REPNZ prefix */
_0xF3: /* REPZ prefix */
nextop = F8;
@@ -1064,6 +1122,55 @@ _trace:
R_EDI += tmp8s;
}
break;
case 0xA7: /* REP(N)Z CMPSW */
tmp16u = 0;
tmp16u2 = 0;
tmp8s *= 2;
if(opcode==0xF2) {
while(tmp32u) {
--tmp32u;
tmp16u2 = *(uint16_t*)R_EDI;
tmp16u = *(uint16_t*)R_ESI;
R_EDI += tmp8s;
R_ESI += tmp8s;
if(tmp16u2==tmp16u)
break;
}
} else {
while(tmp32u) {
--tmp32u;
tmp16u2 = *(uint16_t*)R_EDI;
tmp16u = *(uint16_t*)R_ESI;
R_EDI += tmp8s;
R_ESI += tmp8s;
if(tmp16u2!=tmp16u)
break;
}
}
if(R_ECX) cmp16(emu, tmp16u, tmp16u2);
break;
case 0xAF: /* REP(N)Z SCASW */
tmp16u = 0;
tmp8s *= 2;
if(opcode==0xF2) {
while(tmp32u) {
--tmp32u;
tmp16u = *(uint16_t*)R_EDI;
R_EDI += tmp8s;
if(R_AX==tmp16u)
break;
}
} else {
while(tmp32u) {
--tmp32u;
tmp16u = *(uint16_t*)R_EDI;
R_EDI += tmp8s;
if(R_AX!=tmp16u)
break;
}
}
if(R_ECX) cmp16(emu, R_AX, tmp16u);
break;
default:
goto _default;
}
@@ -1072,6 +1179,48 @@ _trace:
tmp8s = ACCESS_FLAG(F_DF)?-1:+1;
tmp32u = R_ECX;
switch(nextop) {
case 0x18:
case 0x19:
case 0x1A:
case 0x1B:
case 0x1C:
case 0x1D:
case 0x40:
case 0x41:
case 0x42:
case 0x43:
case 0x44:
case 0x45:
case 0x46:
case 0x47:
case 0x48:
case 0x49:
case 0x4A:
case 0x4B:
case 0x4C:
case 0x4D:
case 0x4E:
case 0x4F:
case 0x70:
case 0x71:
case 0x72:
case 0x73:
case 0x74:
case 0x75:
case 0x76:
case 0x77:
case 0x78:
case 0x79:
case 0x7A:
case 0x7B:
case 0x7C:
case 0x7D:
case 0x7E:
case 0x7F: /* BND / NOP */
case 0xE8:
case 0xE9:
--ip;
NEXT;
case 0x90: /* PAUSE */
NEXT;
case 0xC3: /* REPZ RET... yup */
@@ -1297,7 +1446,12 @@ _trace:
CHECK_FLAGS(emu);
SET_FLAG(F_CF);
NEXT;
_0xFA: /* CLI */
CLEAR_FLAG(F_IF); //not really handled...
NEXT;
_0xFB: /* STI */
SET_FLAG(F_IF);
NEXT;
_0xFC: /* CLD */
CLEAR_FLAG(F_DF);
NEXT;
@@ -1315,7 +1469,7 @@ _trace:
EB->byte[0] = dec8(emu, EB->byte[0]);
break;
default:
emu->old_ip = old_ip;
emu->old_ip = R_EIP;
R_EIP = ip;
printf_log(LOG_NONE, "Illegal Opcode %02X %02X\n", opcode, nextop);
emu->quit=1;
@@ -1340,7 +1494,7 @@ _trace:
break;
case 3: /* CALL FAR Ed */
if(nextop>0xc0) {
emu->old_ip = old_ip;
emu->old_ip = R_EIP;
R_EIP = ip;
printf_log(LOG_NONE, "Illegal Opcode %02X %02X\n", opcode, nextop);
emu->quit=1;
@@ -1360,7 +1514,7 @@ _trace:
break;
case 5: /* JMP FAR Ed */
if(nextop>0xc0) {
emu->old_ip = old_ip;
emu->old_ip = R_EIP;
R_EIP = ip;
printf_log(LOG_NONE, "Illegal Opcode 0x%02X 0x%02X\n", opcode, nextop);
emu->quit=1;
@@ -1376,7 +1530,7 @@ _trace:
Push(emu, ED->dword[0]);
break;
default:
emu->old_ip = old_ip;
emu->old_ip = R_EIP;
R_EIP = ip;
printf_log(LOG_NONE, "Illegal Opcode 0x%02X 0x%02X\n", opcode, nextop);
emu->quit=1;
@@ -1386,13 +1540,13 @@ _trace:
NEXT;
_default:
emu->old_ip = old_ip;
emu->old_ip = R_EIP;
R_EIP = ip;
UnimpOpcode(emu);
goto fini;
#ifdef DYNAREC
stepout:
emu->old_ip = old_ip;
emu->old_ip = R_EIP;
R_EIP = ip;
return 0;
#endif
+379 -53
View File
@@ -13,33 +13,26 @@
#include "box86context.h"
#define F8 *(uint8_t*)(R_EIP++)
#define F8S *(int8_t*)(R_EIP++)
#define F16 *(uint16_t*)(R_EIP+=2, R_EIP-2)
#define F32 *(uint32_t*)(R_EIP+=4, R_EIP-4)
#define F32S *(int32_t*)(R_EIP+=4, R_EIP-4)
#define PK(a) *(uint8_t*)(R_EIP+a)
#define F8 *(uint8_t*)(ip++)
#define F8S *(int8_t*)(ip++)
#define F16 *(uint16_t*)(ip+=2, ip-2)
#define F16S *(int16_t*)(ip+=2, ip-2)
#define F32 *(uint32_t*)(ip+=4, ip-4)
#define F32S *(int32_t*)(ip+=4, ip-4)
#define PK(a) *(uint8_t*)(ip+a)
#include "modrm.h"
void Run6766(x86emu_t *emu)
{
uint8_t opcode = Fetch8(emu);
uintptr_t ip = R_EIP+2; //skip 67 66
uint8_t opcode = F8;
uint8_t nextop;
reg32_t *op1, *op2, *op3, *op4;
reg32_t ea1, ea2, ea3, ea4;
uint8_t tmp8u;
int8_t tmp8s;
uint16_t tmp16u, tmp16u2;
int16_t tmp16s;
uint32_t tmp32u;
int32_t tmp32s;
uint64_t tmp64u;
int64_t tmp64s;
reg32_t *op1, *op2;
switch(opcode) {
case 0x8D: /* LEA Gw,Ew */
nextop = Fetch8(emu);
nextop = F8;
op1=GetEw16(emu, nextop);
op2=GetG(emu, nextop);
op2->word[0] = (uint16_t)(uintptr_t)op1;
@@ -47,77 +40,79 @@ void Run6766(x86emu_t *emu)
default:
ip-=2; //unfetch
UnimpOpcode(emu);
}
R_EIP = ip;
}
void Run67(x86emu_t *emu)
{
uint8_t opcode = Fetch8(emu);
uint8_t nextop;
reg32_t *op1, *op2, *op3, *op4;
reg32_t ea1, ea2, ea3, ea4;
uint8_t tmp8u;
uintptr_t ip = R_EIP+1; //skip 67
uint8_t opcode = F8;
int8_t tmp8s;
uint16_t tmp16u;
int16_t tmp16s;
uint32_t tmp32u;
int32_t tmp32s;
uint64_t tmp64u;
int64_t tmp64s;
switch(opcode) {
case 0x66: /* MoooRE opcodes */
Run6766(emu);
break;
case 0x6C: /* INSB */
*(int8_t*)(R_DI+GetESBaseEmu(emu)) = 0; // faking port read, using actual segment ES, just in case
if(ACCESS_FLAG(F_DF))
R_DI-=1;
else
R_DI+=1;
break;
case 0xE0: /* LOOPNZ */
CHECK_FLAGS(emu);
tmp8s = Fetch8s(emu);
tmp8s = F8S;
--R_CX; // don't update flags
if(R_CX && !ACCESS_FLAG(F_ZF))
R_EIP += tmp8s;
break;
case 0xE1: /* LOOPZ */
CHECK_FLAGS(emu);
tmp8s = Fetch8s(emu);
tmp8s = F8S;
--R_CX; // don't update flags
if(R_CX && ACCESS_FLAG(F_ZF))
R_EIP += tmp8s;
break;
case 0xE2: /* LOOP */
tmp8s = Fetch8s(emu);
tmp8s = F8S;
--R_CX; // don't update flags
if(R_CX)
R_EIP += tmp8s;
break;
case 0xE3: /* JCXZ */
tmp8s = Fetch8s(emu);
tmp8s = F8S;
if(!R_CX)
R_EIP += tmp8s;
break;
case 0xE8: /* CALL Id */
tmp32s = F32S; // call is relative
Push(emu, R_EIP);
R_EIP += tmp32s;
break;
default:
UnimpOpcode(emu);
}
R_EIP = ip;
}
void RunLock(x86emu_t *emu)
{
uint8_t opcode = Fetch8(emu);
uintptr_t ip = R_EIP+1;
uint8_t opcode = F8;
uint8_t nextop;
reg32_t *oped;
reg32_t ea1;
sse_regs_t *opex, eax1;
mmx_regs_t *opem;
uint8_t tmp8u;
int8_t tmp8s;
uint16_t tmp16u;
int16_t tmp16s;
uint32_t tmp32u, tmp32u2;
int32_t tmp32s;
uint64_t tmp64u;
int64_t tmp64s;
pthread_mutex_lock(&emu->context->mutex_lock);
switch(opcode) {
#define GO(B, OP) \
@@ -231,7 +226,7 @@ void RunLock(x86emu_t *emu)
break;
default:
R_EIP -= 3; //unfetch
ip -= 3; //unfetch
break;
}
break;
@@ -283,7 +278,7 @@ void RunLock(x86emu_t *emu)
break;
default:
// trigger invalid lock?
R_EIP -= 2; // unfetch
ip -= 2; // unfetch
break;
}
break;
@@ -342,40 +337,100 @@ void RunLock(x86emu_t *emu)
default:
//UnimpOpcode(emu);
// should trigger invalid unlock ?
R_EIP--; // "unfetch" to use normal instruction
ip--; // "unfetch" to use normal instruction
}
R_EIP = ip;
pthread_mutex_unlock(&emu->context->mutex_lock);
}
void RunGS(x86emu_t *emu)
{
uint8_t opcode = Fetch8(emu);
uintptr_t ip = R_EIP+1;
uint8_t opcode = F8;
uint8_t nextop;
reg32_t *oped;
reg32_t ea1;
sse_regs_t *opex, eax1;
mmx_regs_t *opem;
uint8_t tmp8u;
int8_t tmp8s;
uint16_t tmp16u;
int16_t tmp16s;
uint32_t tmp32u;
int32_t tmp32s;
uint64_t tmp64u;
int64_t tmp64s;
uintptr_t tlsdata = GetGSBaseEmu(emu);
switch(opcode) {
case 0x01: /* ADD GS:Ed, Gd */
nextop = F8;
GET_ED_OFFS(tlsdata);
ED->dword[0] = add32(emu, ED->dword[0], GD.dword[0]);
break;
case 0x03: /* ADD Gd, GS:Ed */
nextop = F8;
GET_ED_OFFS(tlsdata);
GD.dword[0] = add32(emu, GD.dword[0], ED->dword[0]);
break;
case 0x11: /* ADC GS:Ed, Gd */
nextop = F8;
GET_ED_OFFS(tlsdata);
ED->dword[0] = adc32(emu, ED->dword[0], GD.dword[0]);
case 0x2B: /* SUB Gd, GS:Ed */
nextop = F8;
GET_ED_OFFS(tlsdata);
GD.dword[0] = sub32(emu, GD.dword[0], ED->dword[0]);
break;
case 0x33: /* XOR Gd,Ed */
nextop = F8;
GET_ED_OFFS(tlsdata);
GD.dword[0] = xor32(emu, GD.dword[0], ED->dword[0]);
break;
case 0x64: /* FS: */
// so just ignore that GS: prefix then
--ip; // put FS back
break;
case 0x69: /* IMUL Gd,Ed,Id */
nextop = F8;
GET_ED_OFFS(tlsdata);
tmp32u = F32;
GD.dword[0] = imul32(emu, ED->dword[0], tmp32u);
break;
case 0x70:
case 0x71:
case 0x72:
case 0x73:
case 0x74:
case 0x75:
case 0x76:
case 0x77:
case 0x78:
case 0x79:
case 0x7A:
case 0x7B:
case 0x7C:
case 0x7D:
case 0x7E:
case 0x7F:
// just ignore the prefix
--ip;
break;
case 0x80: /* GRP Eb,Ib */
case 0x82: // 0x82 and 0x80 are the same opcodes it seems?
nextop = F8;
GET_EB_OFFS(tlsdata);
tmp8u = F8;
switch((nextop>>3)&7) {
case 0: EB->byte[0] = add8(emu, EB->byte[0], tmp8u); break;
case 1: EB->byte[0] = or8(emu, EB->byte[0], tmp8u); break;
case 2: EB->byte[0] = adc8(emu, EB->byte[0], tmp8u); break;
case 3: EB->byte[0] = sbb8(emu, EB->byte[0], tmp8u); break;
case 4: EB->byte[0] = and8(emu, EB->byte[0], tmp8u); break;
case 5: EB->byte[0] = sub8(emu, EB->byte[0], tmp8u); break;
case 6: EB->byte[0] = xor8(emu, EB->byte[0], tmp8u); break;
case 7: cmp8(emu, EB->byte[0], tmp8u); break;
}
break;
case 0x81: /* GRP Ed,Id */
case 0x83: /* GRP Ed,Ib */
nextop = F8;
@@ -401,6 +456,11 @@ void RunGS(x86emu_t *emu)
GET_ED_OFFS(tlsdata);
ED->dword[0] = GD.dword[0];
break;
case 0x8A: /* MOV Gb,GS:Eb */
nextop = F8;
GET_EB_OFFS(tlsdata);
GB = EB->byte[0];
break;
case 0x8B: /* MOV Gd,Ed */
nextop = F8;
GET_ED_OFFS(tlsdata);
@@ -419,6 +479,27 @@ void RunGS(x86emu_t *emu)
*(uint32_t*)((tlsdata) + tmp32s) = R_EAX;
break;
case 0xC0: /* GRP2 Eb,Ib */
nextop = F8;
GET_EB_OFFS(tlsdata);
tmp8u = F8/* & 0x1f*/; // masking done in each functions
switch((nextop>>3)&7) {
case 0: EB->byte[0] = rol8(emu, EB->byte[0], tmp8u); break;
case 1: EB->byte[0] = ror8(emu, EB->byte[0], tmp8u); break;
case 2: EB->byte[0] = rcl8(emu, EB->byte[0], tmp8u); break;
case 3: EB->byte[0] = rcr8(emu, EB->byte[0], tmp8u); break;
case 4:
case 6: EB->byte[0] = shl8(emu, EB->byte[0], tmp8u); break;
case 5: EB->byte[0] = shr8(emu, EB->byte[0], tmp8u); break;
case 7: EB->byte[0] = sar8(emu, EB->byte[0], tmp8u); break;
}
break;
case 0xC6: /* MOV Eb,Ib */
nextop = F8;
GET_EB_OFFS(tlsdata);
EB->byte[0] = F8;
break;
case 0xC7: /* MOV Ed,Id */
nextop = F8;
GET_ED_OFFS(tlsdata);
@@ -474,6 +555,251 @@ void RunGS(x86emu_t *emu)
}
break;
default:
ip--;
UnimpOpcode(emu);
}
R_EIP = ip;
}
void RunFS(x86emu_t *emu)
{
uintptr_t ip = R_EIP+1;
uint8_t opcode = F8;
uint8_t nextop;
reg32_t *oped;
uint8_t tmp8u;
uint32_t tmp32u;
int32_t tmp32s;
int16_t tmp16s;
uintptr_t tlsdata = GetFSBaseEmu(emu);
switch(opcode) {
case 0x33: /* XOR Gd,Ed */
nextop = F8;
GET_ED_OFFS(tlsdata);
GD.dword[0] = xor32(emu, GD.dword[0], ED->dword[0]);
break;
case 0x3B: /* CMP GD, FS:Ed */
nextop = F8;
GET_ED_OFFS(tlsdata);
cmp32(emu, GD.dword[0], ED->dword[0]);
break;
case 0x54: /* PUSH ESP */
tmp32u = R_ESP;
R_ESP -= 4;
*((uint32_t*)(R_ESP+tlsdata)) = tmp32u; //Push(emu, tmp32u);
break;
case 0x50:
case 0x51:
case 0x52:
case 0x53:
case 0x55:
case 0x56:
case 0x57: /* PUSH Reg */
tmp8u = opcode&7;
*((uint32_t*)(R_ESP+tlsdata)) = emu->regs[tmp8u].dword[0]; //Push(emu, emu->regs[tmp8u].dword[0]);
break;
case 0x58:
case 0x59:
case 0x5A:
case 0x5B:
case 0x5C: /* POP ESP */
case 0x5D:
case 0x5E:
case 0x5F: /* POP Reg */
tmp8u = opcode&7;
emu->regs[tmp8u].dword[0] = *((uint32_t*)(R_ESP+tlsdata)); // Pop(emu);
R_ESP += 4;
break;
case 0x67:
opcode = F8;
switch(opcode) {
case 0x89: /* MOV ED16,Gd */
nextop = F8;
oped=GetEw16off(emu, nextop, tlsdata);
ED->dword[0] = GD.dword[0];
break;
case 0x8B: /* MOV Gd,Ed16 */
nextop = F8;
oped=GetEw16off(emu, nextop, tlsdata);
GD.dword[0] = ED->dword[0];
break;
case 0xA1: /* MOV EAX,Ov16 */
tmp16s = F16S;
R_EAX = *(uint32_t*)((tlsdata) + tmp16s);
break;
case 0xA3: /* MOV Ov16,EAX */
tmp16s = F16S;
*(uint32_t*)((tlsdata) + tmp16s) = R_EAX;
break;
case 0xFF: /* GRP 5 Ed */
nextop = F8;
switch((nextop>>3)&7) {
case 6: /* Push Ed */
oped=GetEw16off(emu, nextop, tlsdata);
Push(emu, ED->dword[0]);
break;
default:
ip-=2;
UnimpOpcode(emu);
}
break;
default:
ip-=2;
UnimpOpcode(emu);
}
break;
case 0x69: /* IMUL Gd,Ed,Id */
nextop = F8;
GET_ED_OFFS(tlsdata);
tmp32u = F32;
GD.dword[0] = imul32(emu, ED->dword[0], tmp32u);
break;
case 0x80: /* GRP Eb,Ib */
case 0x82: // 0x82 and 0x80 are the same opcodes it seems?
nextop = F8;
GET_EB_OFFS(tlsdata);
tmp8u = F8;
switch((nextop>>3)&7) {
case 0: EB->byte[0] = add8(emu, EB->byte[0], tmp8u); break;
case 1: EB->byte[0] = or8(emu, EB->byte[0], tmp8u); break;
case 2: EB->byte[0] = adc8(emu, EB->byte[0], tmp8u); break;
case 3: EB->byte[0] = sbb8(emu, EB->byte[0], tmp8u); break;
case 4: EB->byte[0] = and8(emu, EB->byte[0], tmp8u); break;
case 5: EB->byte[0] = sub8(emu, EB->byte[0], tmp8u); break;
case 6: EB->byte[0] = xor8(emu, EB->byte[0], tmp8u); break;
case 7: cmp8(emu, EB->byte[0], tmp8u); break;
}
break;
case 0x81: /* GRP Ed,Id */
case 0x83: /* GRP Ed,Ib */
nextop = F8;
GET_ED_OFFS(tlsdata);
if(opcode==0x83) {
tmp32s = F8S;
tmp32u = (uint32_t)tmp32s;
} else
tmp32u = F32;
switch((nextop>>3)&7) {
case 0: ED->dword[0] = add32(emu, ED->dword[0], tmp32u); break;
case 1: ED->dword[0] = or32(emu, ED->dword[0], tmp32u); break;
case 2: ED->dword[0] = adc32(emu, ED->dword[0], tmp32u); break;
case 3: ED->dword[0] = sbb32(emu, ED->dword[0], tmp32u); break;
case 4: ED->dword[0] = and32(emu, ED->dword[0], tmp32u); break;
case 5: ED->dword[0] = sub32(emu, ED->dword[0], tmp32u); break;
case 6: ED->dword[0] = xor32(emu, ED->dword[0], tmp32u); break;
case 7: cmp32(emu, ED->dword[0], tmp32u); break;
}
break;
case 0x89: /* MOV Ed,Gd */
nextop = F8;
GET_ED_OFFS(tlsdata);
ED->dword[0] = GD.dword[0];
break;
case 0x8B: /* MOV Gd,Ed */
nextop = F8;
GET_ED_OFFS(tlsdata);
GD.dword[0] = ED->dword[0];
break;
case 0x8F: /* POP Ed */
nextop = F8;
GET_ED_OFFS(tlsdata);
ED->dword[0] = Pop(emu);
break;
case 0xA1: /* MOV EAX,Ov */
tmp32s = F32S;
R_EAX = *(uint32_t*)((tlsdata) + tmp32s);
break;
case 0xA2: /* MOV Ob,AL */
tmp32s = F32S;
*(uint8_t*)((tlsdata) + tmp32s) = R_AL;
break;
case 0xA3: /* MOV Od,EAX */
tmp32s = F32S;
*(uint32_t*)((tlsdata) + tmp32s) = R_EAX;
break;
case 0xC0: /* GRP2 Eb,Ib */
nextop = F8;
GET_EB_OFFS(tlsdata);
tmp8u = F8/* & 0x1f*/; // masking done in each functions
switch((nextop>>3)&7) {
case 0: EB->byte[0] = rol8(emu, EB->byte[0], tmp8u); break;
case 1: EB->byte[0] = ror8(emu, EB->byte[0], tmp8u); break;
case 2: EB->byte[0] = rcl8(emu, EB->byte[0], tmp8u); break;
case 3: EB->byte[0] = rcr8(emu, EB->byte[0], tmp8u); break;
case 4:
case 6: EB->byte[0] = shl8(emu, EB->byte[0], tmp8u); break;
case 5: EB->byte[0] = shr8(emu, EB->byte[0], tmp8u); break;
case 7: EB->byte[0] = sar8(emu, EB->byte[0], tmp8u); break;
}
break;
case 0xC6: /* MOV Eb,Ib */
nextop = F8;
GET_EB_OFFS(tlsdata);
EB->byte[0] = F8;
break;
case 0xC7: /* MOV Ed,Id */
nextop = F8;
GET_ED_OFFS(tlsdata);
ED->dword[0] = F32;
break;
case 0xFF: /* GRP 5 Ed */
nextop = F8;
GET_ED_OFFS(tlsdata);
switch((nextop>>3)&7) {
case 0: /* INC Ed */
ED->dword[0] = inc32(emu, ED->dword[0]);
break;
case 1: /* DEC Ed */
ED->dword[0] = dec32(emu, ED->dword[0]);
break;
case 2: /* CALL NEAR Ed */
Push(emu, R_EIP);
R_EIP = ED->dword[0]; // should get value in temp var. in case ED use ESP?
break;
case 3: /* CALL FAR Ed */
if(nextop>0xc0) {
printf_log(LOG_NONE, "Illegal Opcode %02X %02X\n", opcode, nextop);
emu->quit=1;
emu->error |= ERR_ILLEGAL;
} else {
Push16(emu, R_CS);
Push(emu, R_EIP);
R_EIP = ED->dword[0];
R_CS = (ED+1)->word[0];
}
break;
case 4: /* JMP NEAR Ed */
R_EIP = ED->dword[0];
break;
case 5: /* JMP FAR Ed */
if(nextop>0xc0) {
printf_log(LOG_NONE, "Illegal Opcode 0x%02X 0x%02X\n", opcode, nextop);
emu->quit=1;
emu->error |= ERR_ILLEGAL;
} else {
R_EIP = ED->dword[0];
R_CS = (ED+1)->word[0];
}
break;
case 6: /* Push Ed */
Push(emu, ED->dword[0]);
break;
default:
printf_log(LOG_NONE, "Illegal Opcode 0x%02X 0x%02X\n", opcode, nextop);
ip-=2;
emu->quit=1;
emu->error |= ERR_ILLEGAL;
}
break;
default:
ip--;
UnimpOpcode(emu);
}
R_EIP = ip;
}
+222 -57
View File
@@ -22,6 +22,7 @@
#ifdef HAVE_TRACE
#include "x86trace.h"
#endif
#include "x86tls.h"
#define PARITY(x) (((emu->x86emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0)
#define XOR2(x) (((x) ^ ((x)>>1)) & 0x1)
@@ -31,9 +32,9 @@ int32_t EXPORT my___libc_start_main(x86emu_t* emu, int *(main) (int, char * *, c
//TODO: register rtld_fini
//TODO: register fini
// let's cheat and set all args...
Push(emu, (uint32_t)emu->context->envv);
Push(emu, (uint32_t)emu->context->argv);
Push(emu, (uint32_t)emu->context->argc);
Push(emu, (uint32_t)my_context->envv);
Push(emu, (uint32_t)my_context->argv);
Push(emu, (uint32_t)my_context->argc);
if(init) {
PushExit(emu);
R_EIP=(uint32_t)*init;
@@ -43,7 +44,7 @@ int32_t EXPORT my___libc_start_main(x86emu_t* emu, int *(main) (int, char * *, c
return 0;
emu->quit = 0;
}
printf_log(LOG_DEBUG, "Transfert to main(%d, %p, %p)=>%p from __libc_start_main\n", emu->context->argc, emu->context->argv, emu->context->envv, main);
printf_log(LOG_DEBUG, "Transfert to main(%d, %p, %p)=>%p from __libc_start_main\n", my_context->argc, my_context->argv, my_context->envv, main);
// call main and finish
PushExit(emu);
R_EIP=(uint32_t)main;
@@ -53,10 +54,10 @@ int32_t EXPORT my___libc_start_main(x86emu_t* emu, int *(main) (int, char * *, c
return 0;
}
const char* GetNativeName(x86emu_t* emu, void* p)
const char* GetNativeName(void* p)
{
static char unknown[10] = "???";
const char *ret = GetNameOffset(emu->context->maplib, p);
const char *ret = GetNameOffset(my_context->maplib, p);
if(ret)
return ret;
@@ -76,13 +77,6 @@ const char* GetNativeName(x86emu_t* emu, void* p)
return buff;
}
uintptr_t pltResolver = ~0;
void PltResolver(x86emu_t* emu, uint32_t id, uintptr_t ofs)
{
printf_log(LOG_INFO, "PltResolver: Ofs=%p, Id=%d (IP=%p, ESP+4=%p)", (void*)ofs, id, *(void**)(R_ESP), *(void**)(R_ESP+4));
emu->quit=1;
}
void UpdateFlags(x86emu_t *emu)
{
uint32_t cc;
@@ -537,6 +531,152 @@ void UpdateFlags(x86emu_t *emu)
CLEAR_FLAG(F_CF);
CLEAR_FLAG(F_AF);
break;
case d_cmp8:
CLEAR_FLAG(F_CF);
CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF);
CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2);
CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
break;
case d_cmp16:
CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF);
CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2);
CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
break;
case d_cmp32:
CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF);
CONDITIONAL_SET_FLAG(!emu->res, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2);
CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
break;
case d_tst8:
CLEAR_FLAG(F_OF);
CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF);
CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
CLEAR_FLAG(F_CF);
break;
case d_tst16:
CLEAR_FLAG(F_OF);
CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF);
CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
CLEAR_FLAG(F_CF);
break;
case d_tst32:
CLEAR_FLAG(F_OF);
CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF);
CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
CLEAR_FLAG(F_CF);
break;
case d_adc8:
CONDITIONAL_SET_FLAG(emu->res & 0x100, F_CF);
CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF);
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
cc = (emu->op1 & emu->op2) | ((~emu->res) & (emu->op1 | emu->op2));
CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF);
CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
break;
case d_adc16:
CONDITIONAL_SET_FLAG(emu->res & 0x10000, F_CF);
CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF);
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
cc = (emu->op1 & emu->op2) | ((~emu->res) & (emu->op1 | emu->op2));
CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF);
CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
break;
case d_adc32:
if(emu->res == (emu->op1+emu->op2)) {
lo = (emu->op1 & 0xFFFF) + (emu->op2 & 0xFFFF);
} else {
lo = 1 + (emu->op1 & 0xFFFF) + (emu->op2 & 0xFFFF);
}
hi = (lo >> 16) + (emu->op1 >> 16) + (emu->op2 >> 16);
CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF);
CONDITIONAL_SET_FLAG(!emu->res, F_ZF);
CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF);
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
cc = (emu->op2 & emu->op1) | ((~emu->res) & (emu->op2 | emu->op1));
CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF);
CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
break;
case d_sbb8:
CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF);
CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2);
CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
break;
case d_sbb16:
CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF);
CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2);
CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
break;
case d_sbb32:
CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF);
CONDITIONAL_SET_FLAG(!emu->res, F_ZF);
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2);
CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
break;
case d_rol8:
if(emu->op2 == 1) {
CONDITIONAL_SET_FLAG((emu->res + (emu->res >> 7)) & 1, F_OF);
}
CONDITIONAL_SET_FLAG(emu->res & 0x1, F_CF);
break;
case d_rol16:
if(emu->op2 == 1) {
CONDITIONAL_SET_FLAG((emu->res + (emu->res >> 15)) & 1, F_OF);
}
CONDITIONAL_SET_FLAG(emu->res & 0x1, F_CF);
break;
case d_rol32:
if(emu->op2 == 1) {
CONDITIONAL_SET_FLAG((emu->res + (emu->res >> 31)) & 1, F_OF);
}
CONDITIONAL_SET_FLAG(emu->res & 0x1, F_CF);
break;
case d_ror8:
if(emu->op2 == 1) {
CONDITIONAL_SET_FLAG(XOR2(emu->res >> 6), F_OF);
}
CONDITIONAL_SET_FLAG(emu->res & (1 << 7), F_CF);
break;
case d_ror16:
if(emu->op2 == 1) {
CONDITIONAL_SET_FLAG(XOR2(emu->res >> 14), F_OF);
}
CONDITIONAL_SET_FLAG(emu->res & (1 << 15), F_CF);
break;
case d_ror32:
if(emu->op2 == 1) {
CONDITIONAL_SET_FLAG(XOR2(emu->res >> 30), F_OF);
}
CONDITIONAL_SET_FLAG(emu->res & (1 << 31), F_CF);
break;
case d_unknown:
printf_log(LOG_NONE, "Box86: %p trying to evaluate Unknown defered Flags\n", (void*)R_EIP);
break;
@@ -548,12 +688,13 @@ void UpdateFlags(x86emu_t *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);
GO(res1);
GOC(res1, 1);
GO(PF);
GO(res2);
GOC(res2, 0);
GO(AF);
GO(res3);
GOC(res3, 0);
GO(ZF);
GO(SF);
GO(TF);
@@ -562,7 +703,7 @@ void PackFlags(x86emu_t* emu)
GO(OF);
GO(IOPL);
GO(NT);
GO(dummy);
GOC(dummy, 0);
GO(RF);
GO(VM);
GO(AC);
@@ -570,16 +711,18 @@ void PackFlags(x86emu_t* emu)
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);
GO(res1);
GOC(res1, 1);
GO(PF);
GO(res2);
GOC(res2, 0);
GO(AF);
GO(res3);
GOC(res3, 0);
GO(ZF);
GO(SF);
GO(TF);
@@ -588,7 +731,7 @@ void UnpackFlags(x86emu_t* emu)
GO(OF);
GO(IOPL);
GO(NT);
GO(dummy);
GOC(dummy, 0);
GO(RF);
GO(VM);
GO(AC);
@@ -596,80 +739,102 @@ void UnpackFlags(x86emu_t* emu)
GO(VIP);
GO(ID);
#undef GO
#undef GOC
}
uintptr_t GetGSBaseEmu(x86emu_t* emu)
uintptr_t GetSegmentBaseEmu(x86emu_t* emu, int seg)
{
return (uintptr_t)GetGSBase(emu->context);
if(!emu->segs_clean[seg] || seg==_GS) {
emu->segs_offs[seg] = (uintptr_t)GetSegmentBase(emu->segs[seg]);
emu->segs_clean[seg] = 1;
}
return emu->segs_offs[seg];
}
const char* getAddrFunctionName(uintptr_t addr)
{
static char ret[1000];
uint32_t sz = 0;
uintptr_t start = 0;
const char* symbname = FindNearestSymbolName(FindElfAddress(my_context, addr), (void*)addr, &start, &sz);
if(symbname && addr>=start && (addr<(start+sz) || !sz)) {
if(addr==start)
sprintf(ret, "%s/%s", ElfName(FindElfAddress(my_context, addr)), symbname);
else
sprintf(ret, "%s/%s + %d", ElfName(FindElfAddress(my_context, addr)), symbname, addr - start);
} else
sprintf(ret, "???");
return ret;
}
void printFunctionAddr(uintptr_t nextaddr, const char* text)
{
uint32_t sz = 0;
uintptr_t start = 0;
const char* symbname = FindNearestSymbolName(FindElfAddress(my_context, nextaddr), (void*)nextaddr, &start, &sz);
if(symbname && nextaddr>=start && (nextaddr<(start+sz) || !sz)) {
if(nextaddr==start)
printf_log(LOG_NONE, " (%s%s/%s)", text, ElfName(FindElfAddress(my_context, nextaddr)), symbname);
else
printf_log(LOG_NONE, " (%s%s/%s + %d)", text, ElfName(FindElfAddress(my_context, nextaddr)), symbname, nextaddr - start);
}
}
#ifdef HAVE_TRACE
extern uint64_t start_cnt;
#define PK(a) *(uint8_t*)(ip+a)
#define PK32(a) *(uint32_t*)(uint8_t*)(ip+a)
static void printFunctionAddr(x86emu_t* emu, uintptr_t nextaddr, const char* text)
{
uint32_t sz = 0;
uintptr_t start = 0;
const char* symbname = FindNearestSymbolName(FindElfAddress(emu->context, nextaddr), (void*)nextaddr, &start, &sz);
if(symbname && nextaddr>=start && nextaddr<(start+sz)) {
if(nextaddr==start)
printf_log(LOG_NONE, " (%s%s)", text, symbname);
else
printf_log(LOG_NONE, " (%s%s + 0x%x)", text, symbname, nextaddr - start);
}
}
#define PK(a) (*(uint8_t*)(ip+a))
#define PK32(a) (*(int32_t*)((uint8_t*)(ip+a)))
void PrintTrace(x86emu_t* emu, uintptr_t ip, int dynarec)
{
if(start_cnt) --start_cnt;
if(!start_cnt && emu->dec && (
(emu->trace_end == 0)
|| ((ip >= emu->trace_start) && (ip < emu->trace_end))) ) {
pthread_mutex_lock(&emu->context->mutex_trace);
if(!start_cnt && my_context->dec && (
(trace_end == 0)
|| ((ip >= trace_start) && (ip < trace_end))) ) {
pthread_mutex_lock(&my_context->mutex_trace);
int tid = syscall(SYS_gettid);
#ifdef DYNAREC
if((emu->context->trace_tid != tid) || (emu->context->trace_dynarec!=dynarec)) {
if((my_context->trace_tid != tid) || (my_context->trace_dynarec!=dynarec)) {
printf_log(LOG_NONE, "Thread %04d| (%s) |\n", tid, dynarec?"dyn":"int");
emu->context->trace_tid = tid;
emu->context->trace_dynarec = dynarec;
my_context->trace_tid = tid;
my_context->trace_dynarec = dynarec;
}
#else
if(emu->context->trace_tid != tid) {
if(my_context->trace_tid != tid) {
printf_log(LOG_NONE, "Thread %04d|\n", tid);
emu->context->trace_tid = tid;
my_context->trace_tid = tid;
}
#endif
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);
if(a==0) {
printf_log(LOG_NONE, "0x%p: Exit x86emu\n", (void*)ip);
printf_log(LOG_NONE, "%p: Exit x86emu\n", (void*)ip);
} else {
printf_log(LOG_NONE, "0x%p: Native call to %p => %s\n", (void*)ip, (void*)a, GetNativeName(emu, *(void**)(ip+7)));
printf_log(LOG_NONE, "%p: Native call to %p => %s\n", (void*)ip, (void*)a, GetNativeName(*(void**)(ip+7)));
}
} else {
printf_log(LOG_NONE, "%s", DecodeX86Trace(emu->dec, ip));
printf_log(LOG_NONE, "%s", DecodeX86Trace(my_context->dec, ip));
uint8_t peek = PK(0);
if(peek==0xC3 || peek==0xC2) {
printf_log(LOG_NONE, " => %p", *(void**)(R_ESP));
printFunctionAddr(emu, *(uintptr_t*)(R_ESP), "=> ");
printFunctionAddr(*(uintptr_t*)(R_ESP), "=> ");
} else if(peek==0x55) {
printf_log(LOG_NONE, " => STACK_TOP: %p", *(void**)(R_ESP));
printFunctionAddr(emu, ip, "here: ");
printFunctionAddr(ip, "here: ");
} else if(peek==0xE8) { // Call
uintptr_t nextaddr = ip + PK32(1);
printFunctionAddr(emu, nextaddr, "=> ");
uintptr_t nextaddr = ip + 5 + PK32(1);
printFunctionAddr(nextaddr, "=> ");
} else if(peek==0xFF) {
if(PK(1)==0x25) {
uintptr_t nextaddr = ip + PK32(2);
printFunctionAddr(emu, nextaddr, "=> ");
uintptr_t nextaddr = ip + 6 + PK32(2);
printFunctionAddr(nextaddr, "=> ");
}
}
printf_log(LOG_NONE, "\n");
}
pthread_mutex_unlock(&emu->context->mutex_trace);
pthread_mutex_unlock(&my_context->mutex_trace);
}
}
+33 -2
View File
@@ -122,6 +122,33 @@ static inline reg32_t* GetEw16(x86emu_t *emu, uint32_t v)
}
}
static inline reg32_t* GetEw16off(x86emu_t *emu, uint32_t v, uintptr_t offset)
{
uint32_t m = v&0xC7; // filter Ed
if(m>=0xC0) {
return &emu->regs[(m&0x07)];
} else {
uint32_t base = 0;
switch(m&7) {
case 0: base = R_BX+R_SI; break;
case 1: base = R_BX+R_DI; break;
case 2: base = R_BP+R_SI; break;
case 3: base = R_BP+R_DI; break;
case 4: base = R_SI; break;
case 5: base = R_DI; break;
case 6: base = R_BP; break;
case 7: base = R_BX; break;
}
switch((m>>6)&3) {
case 0: if(m==6) base = Fetch16(emu); break;
case 1: base += Fetch8s(emu); break;
case 2: base += Fetch16s(emu); break;
// case 3 is C0..C7, already dealt with
}
return (reg32_t*)(base+offset);
}
}
static inline mmx_regs_t* GetEm(x86emu_t *emu, uint32_t v)
{
uint32_t m = v&0xC7; // filter Ed
@@ -173,6 +200,7 @@ void Run660F(x86emu_t *emu);
void Run66D9(x86emu_t *emu); // x87
void Run6766(x86emu_t *emu);
void RunGS(x86emu_t *emu);
void RunFS(x86emu_t *emu);
void RunLock(x86emu_t *emu);
void x86Syscall(x86emu_t *emu);
@@ -182,9 +210,12 @@ x86emu_t* x86emu_fork(x86emu_t* e, int forktype);
void PackFlags(x86emu_t* emu);
void UnpackFlags(x86emu_t* emu);
uintptr_t GetGSBaseEmu(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)
const char* GetNativeName(x86emu_t* emu, void* p);
const char* GetNativeName(void* p);
#ifdef HAVE_TRACE
void PrintTrace(x86emu_t* emu, uintptr_t ip, int dynarec);
+106 -19
View File
@@ -35,22 +35,36 @@
#include "box86context.h"
#include "callback.h"
#include "signals.h"
#include "x86tls.h"
#ifndef __NR_socketcall
//#ifndef SYS_RECVMMSG
//#define SYS_RECVMMSG 19
//#endif
//#ifndef SYS_SENDMMSG
//#define SYS_SENDMMSG 20
//#endif
int32_t my_accept4(x86emu_t* emu, int32_t fd, void* a, void* l, int32_t flags); // not always present, so used wrapped version
#ifndef SYS_RECVMMSG
#define SYS_RECVMMSG 19
#endif
#ifndef SYS_SENDMMSG
#define SYS_SENDMMSG 20
#endif
int32_t my_accept4(x86emu_t* emu, int32_t fd, void* a, void* l, int32_t flags); // not always present, so used wrapped version
#ifdef SYS_RECVMMSG
int32_t my_recvmmsg(x86emu_t* emu, int32_t fd, void* msgvec, uint32_t vlen, uint32_t flags, void* timeout);
int32_t my___sendmmsg(x86emu_t* emu, int32_t fd, void* msgvec, uint32_t vlen, uint32_t flags);
#endif
#endif
typedef struct x86_sigaction_s x86_sigaction_t;
int32_t my_getrandom(x86emu_t* emu, void* buf, uint32_t buflen, uint32_t flags);
int of_convert(int flag);
int32_t my_open(x86emu_t* emu, void* pathname, int32_t flags, uint32_t mode);
#ifndef NOALIGN
int my_epoll_create(x86emu_t* emu, int size);
int my_epoll_create1(x86emu_t* emu, int flags);
int32_t my_epoll_ctl(x86emu_t* emu, int32_t epfd, int32_t op, int32_t fd, void* event);
int32_t my_epoll_wait(x86emu_t* emu, int32_t epfd, void* events, int32_t maxevents, int32_t timeout);
#endif
int my_sigaction(x86emu_t* emu, int signum, const x86_sigaction_t *act, x86_sigaction_t *oldact);
// cannot include <fcntl.h>, it conflict with some asm includes...
#ifndef O_NONBLOCK
#define O_NONBLOCK 04000
@@ -75,6 +89,7 @@ scwrap_t syscallwrap[] = {
{ 7, __NR_waitpid, 3 },
#endif
{ 10, __NR_unlink, 1 },
{ 12, __NR_chdir, 1 },
#ifdef __NR_time
{ 13, __NR_time, 1 },
#endif
@@ -93,11 +108,12 @@ scwrap_t syscallwrap[] = {
{ 47, __NR_getgid, 0 },
{ 49, __NR_geteuid, 0 },
{ 50, __NR_getegid, 0 },
//{ 54, __NR_ioctl, 5 }, // wrapped to allow SA_RESTART handling by libc
{ 54, __NR_ioctl, 3 }, // should be wrapped to allow SA_RESTART handling by libc, but syscall is only 3 arguments, ioctl can be 5
//{ 55, __NR_fcntl, 3 }, // wrapped to allow filter of F_SETFD
{ 60, __NR_umask, 1 },
{ 63, __NR_dup2, 2 },
{ 64, __NR_getppid, 0 },
{ 66, __NR_setsid, 0 },
{ 75, __NR_setrlimit, 2 },
#ifdef __NR_getrlimit
{ 76, __NR_getrlimit, 2 },
@@ -145,6 +161,7 @@ scwrap_t syscallwrap[] = {
//{ 119, __NR_sigreturn, 0},
//{ 120, __NR_clone, 5 }, // need works
//{ 122, __NR_uname, 1 },
//{ 123, __NR_modify_ldt },
{ 125, __NR_mprotect, 3 },
{ 136, __NR_personality, 1 },
{ 140, __NR__llseek, 5 },
@@ -171,6 +188,7 @@ scwrap_t syscallwrap[] = {
{ 191, __NR_ugetrlimit, 2 },
{ 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
{ 199, __NR_getuid32, 0 },
{ 200, __NR_getgid32, 0 },
@@ -182,10 +200,23 @@ scwrap_t syscallwrap[] = {
{ 224, __NR_gettid, 0 },
{ 240, __NR_futex, 6 },
{ 252, __NR_exit_group, 1 },
#ifdef NOALIGN
{ 254, __NR_epoll_create, 1 },
{ 255, __NR_epoll_ctl, 4 },
{ 256, __NR_epoll_wait, 4 },
#endif
{ 265, __NR_clock_gettime, 2 },
{ 266, __NR_clock_getres, 2 },
//{ 270, __NR_tgkill, 3 },
{ 271, __NR_utimes, 2 },
{ 311, __NR_set_robust_list, 2 },
{ 312, __NR_get_robust_list, 4 },
#ifdef NOALIGN
{ 329, __NR_epoll_create1, 1 },
#endif
#ifdef __NR_getrandom
{ 355, __NR_getrandom, 3 },
#endif
};
struct mmap_arg_struct {
@@ -300,7 +331,7 @@ void EXPORT x86Syscall(x86emu_t *emu)
R_EAX = (uint32_t)write((int)R_EBX, (void*)R_ECX, (size_t)R_EDX);
break;
case 5: // sys_open
if(s==5) {printf_log(LOG_DUMP, " => sys_open(\"%s\", %d, %d)", (char*)R_EBX, of_convert(R_ECX), R_EDX);};
if(s==5) {printf_log(LOG_DEBUG, " => sys_open(\"%s\", %d, %d)", (char*)R_EBX, of_convert(R_ECX), R_EDX);};
//R_EAX = (uint32_t)open((void*)R_EBX, of_convert(R_ECX), R_EDX);
R_EAX = (uint32_t)my_open(emu, (void*)R_EBX, of_convert(R_ECX), R_EDX);
break;
@@ -333,6 +364,11 @@ void EXPORT x86Syscall(x86emu_t *emu)
if(R_ECX==4) {
// filter out O_NONBLOCK so old stacally linked games that access X11 don't get EAGAIN error sometimes
int tmp = of_convert((int)R_EDX)&(~O_NONBLOCK);
if(R_EDX==0xFFFFF7FF) {
// special case for ~O_NONBLOCK...
int flags = fcntl(R_EBX, 3);
tmp = flags&~O_NONBLOCK;
}
R_EAX = (uint32_t)fcntl((int)R_EBX, (int)R_ECX, tmp);
} else
R_EAX = (uint32_t)fcntl((int)R_EBX, (int)R_ECX, R_EDX);
@@ -377,9 +413,8 @@ void EXPORT x86Syscall(x86emu_t *emu)
case SYS_RECVMSG: R_EAX = recvmsg(args[0], (void*)args[1], args[2]); break;
case SYS_ACCEPT4: R_EAX = my_accept4(emu, args[0], (void*)args[1], (void*)args[2], args[3]); break;
#ifdef SYS_RECVMMSG
// TODO: Create my_ version of recvmmsg and sendmmsg
case SYS_RECVMMSG: R_EAX = recvmmsg(args[0], (void*)args[1], args[2], args[3], (void*)args[4]); break;
case SYS_SENDMMSG: R_EAX = sendmmsg(args[0], (void*)args[1], args[2], args[3]); break;
case SYS_RECVMMSG: R_EAX = my_recvmmsg(emu, args[0], (void*)args[1], args[2], args[3], (void*)args[4]); break;
case SYS_SENDMMSG: R_EAX = my___sendmmsg(emu, args[0], (void*)args[1], args[2], args[3]); break;
#endif
default:
printf_log(LOG_DEBUG, "BOX86 Error on Syscall 102: Unknown Soket command %d\n", R_EBX);
@@ -462,6 +497,9 @@ void EXPORT x86Syscall(x86emu_t *emu)
}
}
break;
case 123: // SYS_modify_ldt
R_EAX = my_modify_ldt(emu, R_EBX, (thread_area_t*)R_ECX, R_EDX);
break;
case 168: // sys_poll
R_EAX = (uint32_t)poll((void*)R_EBX, R_ECX, (int)R_EDX);
break;
@@ -487,6 +525,15 @@ void EXPORT x86Syscall(x86emu_t *emu)
R_EAX = r;
}
break;
case 196: // lstat64
{
struct stat64 st;
unsigned int r = syscall(__NR_lstat64, R_EBX, &st);
UnalignStat64(&st, (void*)R_ECX);
R_EAX = r;
}
break;
case 197: // fstat64
{
struct stat64 st;
@@ -503,12 +550,33 @@ void EXPORT x86Syscall(x86emu_t *emu)
} else
R_EAX = (uint32_t)fcntl((int)R_EBX, (int)R_ECX, R_EDX);
break;
case 243: // set_thread_area
R_EAX = my_set_thread_area((thread_area_t*)R_EBX);
break;
#ifndef NOALIGN
case 254: // epoll_create
R_EAX = my_epoll_create(emu, (int)R_EBX);
break;
case 255: // epoll_ctl
R_EAX = my_epoll_ctl(emu, (int)R_EBX, (int)R_ECX, (int)R_EDX, (void*)R_ESI);
break;
case 256: // epoll_wait
R_EAX = my_epoll_wait(emu, (int)R_EBX, (void*)R_ECX, (int)R_EDX, (int)R_ESI);
break;
#endif
case 270: // tgkill
R_EAX = syscall(__NR_tgkill, R_EBX, R_ECX, R_EDX);
break;
case 355: // get_random
#ifndef NOALIGN
case 329: // epoll_create1
R_EAX = my_epoll_create1(emu, of_convert(R_EBX));
break;
#endif
#ifndef __NR_getrandom
case 355: // getrandom
R_EAX = my_getrandom(emu, (void*)R_EBX, R_ECX, R_EDX);
break;
#endif
default:
printf_log(LOG_INFO, "Error: Unsupported Syscall 0x%02Xh (%d)\n", s, s);
emu->quit = 1;
@@ -553,25 +621,44 @@ uint32_t EXPORT my_syscall(x86emu_t *emu)
return u32(4); // faking the syscall here, we don't want to really terminate the program now
case 3: // sys_read
return (uint32_t)read(i32(4), p(8), u32(12));
break;
case 4: // sys_write
return (uint32_t)write(i32(4), p(8), u32(12));
break;
case 5: // sys_open
return my_open(emu, p(4), of_convert(u32(8)), u32(12));
case 6: // sys_close
return (uint32_t)close(i32(4));
break;
case 123: // SYS_modify_ldt
return my_modify_ldt(emu, i32(4), (thread_area_t*)p(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 243: // set_thread_area
return my_set_thread_area((thread_area_t*)p(4));
#ifndef NOALIGN
case 254: // epoll_create
return my_epoll_create(emu, i32(4));
case 255: // epoll_ctl
return my_epoll_ctl(emu, i32(4), i32(8), i32(12), p(16));
case 256: // epoll_wait
return my_epoll_wait(emu, i32(4), p(8), i32(12), i32(16));
#endif
case 270: //_NR_tgkill
if(!u32(12)) {
/*if(!u32(12))*/ {
//printf("tgkill(%u, %u, %u) => ", u32(4), u32(8), u32(12));
uint32_t ret = (uint32_t)syscall(__NR_tgkill, u32(4), u32(8), u32(12));
//printf("%u (errno=%d)\n", ret, (ret==(uint32_t)-1)?errno:0);
return ret;
} else {
}/* else {
printf_log(LOG_INFO, "Warning: ignoring libc Syscall tgkill (%u, %u, %u)\n", u32(4), u32(8), u32(12));
}
}*/
return 0;
#ifndef NOALIGN
case 329: // epoll_create1
return my_epoll_create1(emu, of_convert(i32(4)));
#endif
#ifndef __NR_getrandom
case 355: // getrandom
return (uint32_t)my_getrandom(emu, p(4), u32(8), u32(12));
#endif
default:
printf_log(LOG_INFO, "Error: Unsupported libc Syscall 0x%02X (%d)\n", s, s);
emu->quit = 1;
+209
View File
@@ -0,0 +1,209 @@
// Handling of TLS calls, include x86 specifi set_thread_area
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include "debug.h"
#include "box86context.h"
#include "x86emu.h"
#include "x86tls.h"
#include "elfloader.h"
typedef struct thread_area_s
{
int entry_number;
uintptr_t base_addr;
unsigned int limit;
unsigned int seg_32bit:1;
unsigned int contents:2;
unsigned int read_exec_only:1;
unsigned int limit_in_pages:1;
unsigned int seg_not_present:1;
unsigned int useable:1;
} thread_area_t;
static pthread_once_t thread_key_once0 = PTHREAD_ONCE_INIT;
static pthread_once_t thread_key_once1 = PTHREAD_ONCE_INIT;
static pthread_once_t thread_key_once2 = PTHREAD_ONCE_INIT;
static void thread_key_alloc0() {
pthread_key_create(&my_context->segtls[0].key, NULL);
}
static void thread_key_alloc1() {
pthread_key_create(&my_context->segtls[1].key, NULL);
}
static void thread_key_alloc2() {
pthread_key_create(&my_context->segtls[2].key, NULL);
}
uint32_t my_set_thread_area(thread_area_t* td)
{
printf_log(LOG_DEBUG, "set_thread_area(%p[%d/base=%p/limit=%u/32bits:%u/%u/%u...])\n", td, td->entry_number, (void*)td->base_addr, td->limit_in_pages, td->seg_32bit, td->contents, td->read_exec_only);
int isempty = 0;
// first, check if the "user_desc", here td, is "empty"
if(td->read_exec_only==1 && td->seg_not_present==1)
if( !td->base_addr
&& !td->limit
&& !td->seg_32bit
&& !td->contents
&& !td->limit_in_pages
&& !td->useable)
isempty = 1;
int idx = td->entry_number;
if(idx==-1) {
// find a free one
for (int i=0; i<3 && idx==-1; ++i)
if(!my_context->segtls[i].present)
idx=i;
if(idx==-1) {
errno = ESRCH;
return (uint32_t)-1;
}
idx+=7;
td->entry_number = idx;
}
if(isempty && (td->entry_number<7 || td->entry_number>7+2)) {
errno = EINVAL;
return (uint32_t)-1;
}
if(isempty) {
memset(&my_context->segtls[td->entry_number-7], 0, sizeof(base_segment_t));
return 0;
}
if((idx<7 || idx>7+2)) {
errno = EINVAL;
return (uint32_t)-1;
}
my_context->segtls[idx-7].base = td->base_addr;
my_context->segtls[idx-7].limit = td->limit;
my_context->segtls[idx-7].present = 1;
switch (idx-7) {
case 0: pthread_once(&thread_key_once0, thread_key_alloc0); break;
case 1: pthread_once(&thread_key_once1, thread_key_alloc1); break;
case 2: pthread_once(&thread_key_once2, thread_key_alloc2); break;
}
pthread_setspecific(my_context->segtls[idx-7].key, (void*)my_context->segtls[idx-7].base);
return 0;
}
uint32_t my_modify_ldt(x86emu_t* emu, int op, thread_area_t* td, int size)
{
printf_log(/*LOG_DEBUG*/LOG_INFO, "modify_ldt(0x%x, %p[0x%x/base=%p/limit=%u/32bits:%u/%u/%u...], %d)\n", op, td, td->entry_number, (void*)td->base_addr, td->limit_in_pages, td->seg_32bit, td->contents, td->read_exec_only, size);
if(!td) {
errno = EFAULT;
return (uint32_t)-1;
}
if(op!=0x11) {
errno = ENOSYS;
return (uint32_t)-1;
}
if(!td->seg_32bit) {
// not handling 16bits segments for now
errno = EINVAL;
return (uint32_t)-1;
}
int idx = td->entry_number - 7;
if(idx<0 || idx>2) {
errno = EINVAL;
return (uint32_t)-1;
}
/*
my_context->segtls[idx].base = td->base_addr;
my_context->segtls[idx].limit = td->limit;
pthread_setspecific(my_context->segtls[idx].key, (void*)my_context->segtls[idx].base);
*/
return 0;
}
#define POS_TLS 0x50
static tlsdatasize_t* setupTLSData(box86context_t* context)
{
// Setup the GS segment:
int dtsize = context->elfsize*8;
void *ptr = (char*)malloc(context->tlssize+4+POS_TLS+dtsize);
memcpy(ptr, context->tlsdata, context->tlssize);
tlsdatasize_t *data = (tlsdatasize_t*)calloc(1, sizeof(tlsdatasize_t));
data->tlsdata = ptr;
data->tlssize = context->tlssize;
pthread_setspecific(context->tlskey, data);
// copy canary...
memset((void*)((uintptr_t)ptr+context->tlssize), 0, POS_TLS+dtsize); // set to 0 remining bytes
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x14), context->canary, 4); // put canary in place
uintptr_t tlsptr = (uintptr_t)ptr+context->tlssize;
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x0), &tlsptr, 4);
uintptr_t dtp = (uintptr_t)ptr+context->tlssize+POS_TLS;
memcpy((void*)(tlsptr+0x4), &dtp, 4);
if(dtsize) {
for (int i=0; i<context->elfsize; ++i) {
// set pointer
dtp = (uintptr_t)ptr + (context->tlssize + GetTLSBase(context->elfs[i]));
memcpy((void*)((uintptr_t)ptr+context->tlssize+POS_TLS+i*8), &dtp, 4);
memcpy((void*)((uintptr_t)ptr+context->tlssize+POS_TLS+i*8+4), &i, 4); // index
}
}
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x10), &context->vsyscall, 4); // address of vsyscall
return data;
}
void* fillTLSData(box86context_t *context)
{
pthread_mutex_lock(&context->mutex_lock);
tlsdatasize_t *data = setupTLSData(context);
pthread_mutex_unlock(&context->mutex_lock);
return data;
}
void* resizeTLSData(box86context_t *context, void* oldptr)
{
pthread_mutex_lock(&context->mutex_lock);
tlsdatasize_t* oldata = (tlsdatasize_t*)oldptr;
tlsdatasize_t *data = setupTLSData(context);
// copy the relevent old part, in case something changed
memcpy((void*)((uintptr_t)data->tlsdata+(context->tlssize-oldata->tlssize)), oldata->tlsdata, oldata->tlssize);
// all done, update new size, free old pointer and exit
pthread_mutex_unlock(&context->mutex_lock);
free_tlsdatasize(oldptr);
return data;
}
static void* GetSeg33Base()
{
tlsdatasize_t* ptr;
if ((ptr = (tlsdatasize_t*)pthread_getspecific(my_context->tlskey)) == NULL) {
ptr = (tlsdatasize_t*)fillTLSData(my_context);
}
if(ptr->tlssize != my_context->tlssize)
ptr = (tlsdatasize_t*)resizeTLSData(my_context, ptr);
return ptr->tlsdata+ptr->tlssize;
}
void* GetSegmentBase(uint32_t desc)
{
if(!desc) {
printf_log(LOG_NONE, "Warning, accessing segment NULL\n");
return NULL;
}
int base = desc>>3;
if(base==0xe || base==0xf)
return NULL; // regular value...
if(base==0x6)
return GetSeg33Base();
if(base>6 && base<10 && my_context->segtls[base-7].present) {
void* ptr = pthread_getspecific(my_context->segtls[base-7].key);
return ptr;
}
printf_log(LOG_NONE, "Warning, accessing segment unknown 0x%x or unset\n", desc);
return NULL;
}
+2
View File
@@ -58,6 +58,8 @@ int InitX86Trace(box86context_t *context)
GO(ZydisFormatterFormatInstruction);
#undef GO
context->dec = InitX86TraceDecoder(context);
return 0;
}
+7 -7
View File
@@ -17,6 +17,8 @@ void reset_fpu(x86emu_t* emu)
emu->sw.x16 = 0x0000;
emu->top = 0;
emu->fpu_stack = 0;
for(int i=0; i<9; ++i)
emu->p_regs[i].tag = 0b11; // STx is empty
}
void fpu_fbst(x86emu_t* emu, uint8_t* d) {
@@ -226,11 +228,10 @@ void fpu_loadenv(x86emu_t* emu, char* p, int b16)
emu->top = emu->sw.f.F87_TOP;
p+=(b16)?2:4;
// tagword: 2bits*8
// simplied tags... just reading back the top pointer
// tags... (only full = 0b11 / free = 0b00)
uint16_t tags = *(uint16_t*)p;
for (emu->fpu_stack=0; emu->fpu_stack<8; ++emu->fpu_stack)
if(tags & (3<<(emu->fpu_stack*2)))
break;
for(int i=0; i<8; ++i)
emu->p_regs[i].tag = (tags>>(i*2))&0b11;
// intruction pointer: 16bits
// data (operand) pointer: 16bits
// last opcode: 11bits save: 16bits restaured (1st and 2nd opcode only)
@@ -246,11 +247,10 @@ void fpu_savenv(x86emu_t* emu, char* p, int b16)
p+=2;
if(!b16) {*(uint16_t*)p = 0; p+=2;}
// tagword: 2bits*8
// simplied tags...
// tags...
uint16_t tags = 0;
for (int i=0; i<8; ++i)
if(i>=emu->fpu_stack)
tags |= (3)<<(i*2);
tags |= (emu->p_regs[i].tag)<<(i*2);
*(uint16_t*)p = tags;
// other stuff are not pushed....
}
+31 -12
View File
@@ -27,25 +27,41 @@ void RunDF(x86emu_t *emu);
static inline void fpu_do_push(x86emu_t* emu)
{
++emu->fpu_stack;
if(emu->fpu_stack == 9) {// overflow
printf_log(LOG_NONE, "Error: %p: FPU Stack overflow\n", (void*)emu->old_ip); // probably better to raise something
emu->quit = 1;
int newtop = (emu->top-1)&7;
/*if(emu->p_regs[newtop].tag!=0b11) {// not empty, overflow!
printf_log(LOG_NONE, "Warning: %p: FPU Stack overflow\n", (void*)emu->old_ip); // probably better to raise something
//emu->quit = 1;
return;
}
emu->top = (emu->top-1)&7;
}*/
if(emu->fpu_stack<8)
++emu->fpu_stack;
emu->p_regs[newtop].tag = 0; // full
emu->top = newtop;
}
static inline void fpu_do_pop(x86emu_t* emu)
{
emu->top = (emu->top+1)&7;
--emu->fpu_stack;
if(emu->fpu_stack < 0) {// underflow
printf_log(LOG_NONE, "Error: %p: FPU Stack underflow\n", (void*)emu->old_ip); // probably better to raise something
emu->quit = 1;
int curtop = (emu->top)&7;
/*if(emu->p_regs[(emu->top)&7].tag==0b11) {// underflow
printf_log(LOG_NONE, "Warning: %p: FPU Stack underflow\n", (void*)emu->old_ip); // probably better to raise something
//emu->quit = 1;
return;
}
}*/
if(emu->fpu_stack>0)
--emu->fpu_stack;
emu->p_regs[curtop].tag = 0b11; // empty
emu->top = (emu->top+1)&7;
}
static inline void fpu_do_free(x86emu_t* emu, int i)
{
emu->p_regs[(emu->top+i)&7].tag = 0b11; // empty
// check if all empty
for(int i=0; i<8; ++i)
if(emu->p_regs[i].tag != 0b11)
return;
emu->fpu_stack = 0;
}
void reset_fpu(x86emu_t* emu);
@@ -100,6 +116,9 @@ static inline void fpu_fcomi(x86emu_t* emu, double b)
#endif
{
RESET_FLAGS(emu);
emu->flags[F_AF] = 0;
emu->flags[F_OF] = 0;
emu->flags[F_SF] = 0;
emu->sw.f.F87_C1 = 0;
#ifdef USE_FLOAT
if(isnan(ST0.f) || isnan(b)) {
+2 -11
View File
@@ -19,12 +19,7 @@
void Run66D9(x86emu_t *emu)
{
uint8_t nextop;
reg32_t *op1, *op2;
reg32_t ea1, ea2;
float f;
double d;
long double ld;
int64_t ll;
reg32_t *op1;
nextop = Fetch8(emu);
switch (nextop) {
case 0xC0:
@@ -94,11 +89,7 @@ void Run66D9(x86emu_t *emu)
void Run66DD(x86emu_t *emu)
{
uint8_t nextop;
reg32_t *op1, *op2;
reg32_t ea1, ea2;
float f;
double d;
long double ld;
reg32_t *op1;
nextop = Fetch8(emu);
switch(nextop) {
+13
View File
@@ -0,0 +1,13 @@
#ifndef __AUXVAL_H__
#define __AUXVAL_H__
typedef struct x86emu_s x86emu_t;
#ifndef BUILD_LIB
int init_auxval(int argc, const char **argv, const char **env);
#endif
unsigned long real_getauxval(unsigned long type);
unsigned long my_getauxval(x86emu_t* emu, unsigned long type);
#endif //__AUXVAL_H__
+63 -7
View File
@@ -5,7 +5,7 @@
#include "pathcoll.h"
typedef struct elfheader_s elfheader_t;
typedef struct cleanup_s cleanup_t;
typedef struct x86emu_s x86emu_t;
typedef struct zydis_s zydis_t;
typedef struct lib_s lib_t;
@@ -15,14 +15,21 @@ typedef struct kh_symbolmap_s kh_symbolmap_t;
typedef struct callbacklist_s callbacklist_t;
typedef struct library_s library_t;
typedef struct kh_fts_s kh_fts_t;
typedef struct kh_threadstack_s kh_threadstack_t;
typedef struct kh_cancelthread_s kh_cancelthread_t;
typedef struct zydis_dec_s zydis_dec_t;
typedef struct atfork_fnc_s {
uintptr_t prepare;
uintptr_t parent;
uintptr_t child;
void* handle;
} atfork_fnc_t;
#ifdef DYNAREC
typedef struct dynablocklist_s dynablocklist_t;
typedef struct mmaplist_s mmaplist_t;
typedef struct mmaplist_s mmaplist_t;
typedef struct dynmap_s {
dynablocklist_t* dynablocks; // the dynabockist of the block
} dynmap_t;
#endif
typedef void* (*procaddess_t)(const char* name);
@@ -36,6 +43,22 @@ typedef struct tlsdatasize_s {
void free_tlsdatasize(void* p);
typedef struct needed_libs_s {
int cap;
int size;
library_t **libs;
} needed_libs_t;
void add_neededlib(needed_libs_t* needed, library_t* lib);
void free_neededlib(needed_libs_t* needed);
typedef struct base_segment_s {
uintptr_t base;
uint32_t limit;
int present;
pthread_key_t key;
} base_segment_t;
typedef struct box86context_s {
path_collection_t box86_path; // PATH env. variable
path_collection_t box86_ld_lib; // LD_LIBRARY_PATH env. variable
@@ -67,19 +90,24 @@ typedef struct box86context_s {
int elfcap;
int elfsize; // number of elf loaded
needed_libs_t neededlibs; // needed libs for main elf
uintptr_t ep; // entry point
x86emu_t *emu; // CPU / FPU / MMX&SSE regs
lib_t *maplib; // lib and symbols handling
lib_t *local_maplib; // libs and symbols openned has local (only collection of libs, no symbols)
kh_threadstack_t *stacksizes; // stack sizes attributes for thread (temporary)
kh_cancelthread_t *cancelthread; // thread cancel mecanism is bit complex, create a map to ease it
bridge_t *threads; // threads
bridge_t *system; // other bridges
uintptr_t vsyscall; // vsyscall bridge value
dlprivate_t *dlprivate; // dlopen library map
kh_symbolmap_t *glwrappers; // the map of wrapper for glProcs (for GLX or SDL1/2)
kh_symbolmap_t *glmymap; // link to the mysymbolmap of libGL
procaddess_t glxprocaddress;
kh_symbolmap_t *alwrappers; // the map of wrapper for alGetProcAddress
kh_symbolmap_t *almymap; // link to the mysymbolmap if libOpenAL
callbacklist_t *callbacks; // all callbacks
@@ -87,6 +115,7 @@ typedef struct box86context_s {
pthread_mutex_t mutex_once2;
pthread_mutex_t mutex_trace;
pthread_mutex_t mutex_lock;
pthread_mutex_t mutex_thread;
library_t *libclib; // shortcut to libc library (if loaded, so probably yes)
library_t *sdl1lib; // shortcut to SDL1 library (if loaded)
@@ -102,11 +131,12 @@ typedef struct box86context_s {
library_t *sdl2imagelib;
library_t *sdl2ttflib;
library_t *x11lib;
library_t *libxcb;
library_t *zlib;
library_t *vorbisfile;
library_t *vorbis;
library_t *asound;
library_t *monounity;
library_t *pulse;
int deferedInit;
elfheader_t **deferedInitList;
@@ -116,17 +146,25 @@ typedef struct box86context_s {
pthread_key_t tlskey; // then tls key to have actual tlsdata
void* tlsdata; // the initial global tlsdata
int32_t tlssize; // wanted size of tlsdata
base_segment_t segtls[3]; // only handling 0/1/2 descriptors
uintptr_t *auxval_start;
cleanup_t *cleanups; // atexit functions
int clean_sz;
int clean_cap;
#ifdef DYNAREC
pthread_mutex_t mutex_blocks;
pthread_mutex_t mutex_mmap;
dynablocklist_t *dynablocks;
mmaplist_t *mmaplist;
int mmapsize;
dynmap_t* dynmap[65536]; // 4G of memory mapped by 64K block
#endif
#ifndef NOALIGN
kh_fts_t *ftsmap;
#endif
zydis_dec_t *dec; // trace
int forked; // how many forks... cleanup only when < 0
@@ -138,8 +176,13 @@ typedef struct box86context_s {
uintptr_t signals[MAX_SIGNAL];
uintptr_t restorer[MAX_SIGNAL];
int is_sigaction[MAX_SIGNAL];
x86emu_t *emu_sig; // the emu with stack used for signal handling (must be separated from main ones)
int no_sigsegv;
int no_sigill;
#ifdef BUILD_DYNAMIC
int count; // number of instances
#endif
} box86context_t;
box86context_t *NewBox86Context(int argc);
@@ -152,7 +195,20 @@ int AddElfHeader(box86context_t* ctx, elfheader_t* head);
int AddTLSPartition(box86context_t* context, int tlssize);
#ifdef DYNAREC
uintptr_t AllocDynarecMap(box86context_t *context, int size);
// the nolinker specified if static map or dynamic (can be deleted) has to be used
uintptr_t AllocDynarecMap(int size, int nolinker);
void FreeDynarecMap(uintptr_t addr, uint32_t size);
dynablocklist_t* getDBFromAddress(uintptr_t addr);
void addDBFromAddressRange(uintptr_t addr, uintptr_t size);
void cleanDBFromAddressRange(uintptr_t addr, uintptr_t size, int destroy);
void protectDB(uintptr_t addr, uintptr_t size);
void unprotectDB(uintptr_t addr, uintptr_t size);
#endif
// defined in fact in threads.c
void thread_set_emu(x86emu_t* emu);
x86emu_t* thread_get_emu();
#endif //__BOX86CONTEXT_H_
+10
View File
@@ -3,11 +3,21 @@
typedef struct path_collection_s path_collection_t;
typedef struct box86context_s box86context_t;
typedef struct x86emu_s x86emu_t;
void LoadLogEnv();
void LoadEnvPath(path_collection_t *col, const char* defpath, const char* env);
int CountEnv(const char** env);
int GatherEnv(char*** dest, const char** env, const char* prog);
void LoadEnvVars(box86context_t *context);
void setupTraceInit(box86context_t* context);
void setupTrace(box86context_t* context);
void initAllHelpers(box86context_t* context);
void finiAllHelpers();
#ifdef BUILD_DYNAMIC
box86context_t* GetBox86Context();
x86emu_t* GetX86Emu();
#endif
#endif //_BOX86LIB_H_
+1 -1
View File
@@ -7,7 +7,7 @@ typedef struct box86context_s box86context_t;
typedef struct x86emu_s x86emu_t;
int CalcStackSize(box86context_t *context);
void SetupInitialStack(box86context_t *context);
void SetupInitialStack(x86emu_t *emu);
uint16_t Pop16(x86emu_t *emu);
void Push16(x86emu_t *emu, uint16_t v);
+10 -4
View File
@@ -17,14 +17,20 @@ x86emu_t* GetCallback1Arg(x86emu_t* emu, uintptr_t fnc, int nb_args, void* arg1)
x86emu_t* FreeCallback(x86emu_t* emu);
uint32_t RunCallback(x86emu_t* emu);
void SetCallbackArg(x86emu_t* emu, int arg, void* val);
void SetCallbackArgs(x86emu_t* emu, int nargs, ...); // set args starting from 0
void SetCallbackNArgs(x86emu_t* emu, int N, int nargs, ...); // set args starting from N
// set args starting from 0
void SetCallbackArgs(x86emu_t* emu, int nargs, ...);
// set args starting from N
void SetCallbackNArgs(x86emu_t* emu, int N, int nargs, ...);
void* GetCallbackArg(x86emu_t* emu, int arg);
void SetCallbackNArg(x86emu_t* emu, int narg);
void SetCallbackAddress(x86emu_t* emu, uintptr_t address);
uintptr_t GetCallbackAddress(x86emu_t* emu);
int IsCallback(box86context_t* context, x86emu_t* cb);
uint32_t RunFunction(box86context_t *context, uintptr_t fnc, int nargs, ...); // use a local stack from the stack of 128K
uint32_t RunFunctionWithEmu(x86emu_t *emu, uintptr_t fnc, int nargs, ...);
// use thread local emu to run the function (context is unused now)
uint32_t RunFunction(box86context_t *context, uintptr_t fnc, int nargs, ...);
// use emu state to run function
uint32_t RunFunctionWithEmu(x86emu_t *emu, int QuitOnLongJump, uintptr_t fnc, int nargs, ...);
// Find a cb using FNC address and argN as a key
x86emu_t* FindCallbackFnc1Arg(x86emu_t* emu, uintptr_t fnc, int argn, void* arg);
#endif //__CALLBACK_H__
+23 -4
View File
@@ -1,18 +1,34 @@
#ifndef __DEBUG_H_
#define __DEBUG_H_
#include <stdint.h>
typedef struct box86context_s box86context_t;
extern int box86_log; // log level
#ifdef DYNAREC
extern int box86_dynarec_log;
extern int box86_dynarec;
extern int box86_pagesize;
#ifdef DYNAREC
extern int box86_dynarec_dump;
extern int box86_dynarec_linker;
extern int box86_dynarec_trace;
extern int box86_dynarec_forced;
extern int box86_dynarec_largest;
#ifdef ARM
extern int arm_vfp; // vfp version (3 or 4), with 32 registers is mendatory
extern int arm_swap;
extern int arm_div;
#endif
#endif
extern int dlsym_error; // log dlsym error
extern int trace_xmm; // include XMM reg in trace?
extern int trace_emm; // include EMM reg in trace?
extern int allow_missing_libs;
extern int box86_steam;
extern uintptr_t trace_start, trace_end;
extern box86context_t *my_context; // global context
extern char* trace_func;
extern uintptr_t fmod_smc_start, fmod_smc_end; // to handle libfmod (from Unreal) SMC (self modifying code)
extern uint16_t default_fs;
#define LOG_NONE 0
#define LOG_INFO 1
#define LOG_DEBUG 2
@@ -22,10 +38,13 @@ extern FILE* ftrace;
#define printf_log(L, ...) do {if(L<=box86_log) {fprintf(ftrace, __VA_ARGS__); fflush(ftrace);}} while(0)
#ifdef DYNAREC
#define dynarec_log(L, ...) do {if(L<=box86_dynarec_log) {fprintf(ftrace, __VA_ARGS__); fflush(ftrace);}} while(0)
#endif
#define EXPORT __attribute__((visibility("default")))
#ifdef BUILD_DYNAMIC
#define EXPORTDYN __attribute__((visibility("default")))
#else
#define EXPORTDYN
#endif
#endif //__DEBUG_H_
#endif //__DEBUG_H_
+26 -2
View File
@@ -7,11 +7,35 @@ typedef struct dynablock_s dynablock_t;
typedef struct dynablocklist_s dynablocklist_t;
dynablocklist_t* NewDynablockList(uintptr_t base, uintptr_t text, int textsz);
uint32_t X31_hash_code(void* addr, int len);
dynablocklist_t* NewDynablockList(uintptr_t base, uintptr_t text, int textsz, int nolinker, int direct);
void FreeDynablockList(dynablocklist_t** dynablocks);
void FreeDynablock(dynablock_t* db);
void MarkDynablock(dynablock_t* db);
void MarkDynablockList(dynablocklist_t** dynablocks);
void ProtectDynablock(dynablock_t* db);
void ProtectkDynablockList(dynablocklist_t** dynablocks);
void ProtectDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
void FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
// for debugging purpose
dynablock_t* FindDynablockFromNativeAddress(void* addr);
uintptr_t StartDynablockList(dynablocklist_t* db);
uintptr_t EndDynablockList(dynablocklist_t* db);
void FreeDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
// Handling of Dynarec block (i.e. an exectable chunk of x86 translated code)
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t* current); // return NULL if block is not found / cannot be created. Don't create if create==0
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t** current); // return NULL if block is not found / cannot be created. Don't create if create==0
// source is linked to dest (i.e. source->table[x] = dest->block), so add a "mark" in dest, add a "linked" info to source
void AddMark(dynablock_t* source, dynablock_t* dest, void** table);
// remove a Table mark (and also remove lined info from other dynablock, if any)
void RemoveMark(void** table);
// Create and Add an new dynablock in the list, handling direct/map
dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int with_marks, int* created);
#endif //__DYNABLOCK_H_
+1 -1
View File
@@ -4,6 +4,6 @@
typedef struct dynablock_s dynablock_t;
typedef struct x86emu_s x86emu_t;
void FillBlock(x86emu_t* emu, dynablock_t* block, uintptr_t addr);
void* FillBlock(dynablock_t* block);
#endif //__DYNAREC_ARM_H_
+1
View File
@@ -14,6 +14,7 @@ void DumpMainHeader(Elf32_Ehdr *header, elfheader_t *h);
void DumpSymTab(elfheader_t *h);
void DumpDynamicSections(elfheader_t *h);
void DumpDynamicNeeded(elfheader_t *h);
void DumpDynamicRPath(elfheader_t *h);
void DumpDynSym(elfheader_t *h);
void DumpRelTable(elfheader_t *h, int cnt, Elf32_Rel *rel, const char* name);
void DumpRelATable(elfheader_t *h, int cnt, Elf32_Rela *rela, const char* name);
+8 -5
View File
@@ -8,6 +8,7 @@ typedef struct library_s library_t;
typedef struct kh_mapsymbols_s kh_mapsymbols_t;
typedef struct box86context_s box86context_t;
typedef struct x86emu_s x86emu_t;
typedef struct needed_libs_s needed_libs_t;
#ifdef DYNAREC
typedef struct dynablocklist_s dynablocklist_t;
#endif
@@ -15,6 +16,7 @@ typedef struct dynablocklist_s dynablocklist_t;
elfheader_t* LoadAndCheckElfHeader(FILE* f, const char* name, int exec); // exec : 0 = lib, 1 = exec
void FreeElfHeader(elfheader_t** head);
const char* ElfName(elfheader_t* head);
void ElfAttachLib(elfheader_t* head, library_t* lib);
// return 0 if OK
int CalcLoadAddr(elfheader_t* head);
@@ -22,33 +24,34 @@ int AllocElfMemory(box86context_t* context, elfheader_t* head, int mainbin);
void FreeElfMemory(elfheader_t* head);
int LoadElfMemory(FILE* f, box86context_t* context, elfheader_t* head);
int ReloadElfMemory(FILE* f, box86context_t* context, elfheader_t* head);
int RelocateElf(lib_t *maplib, elfheader_t* head);
int RelocateElfPlt(box86context_t* context, lib_t *maplib, elfheader_t* head);
int RelocateElf(lib_t *maplib, lib_t* local_maplib, elfheader_t* head);
int RelocateElfPlt(lib_t *maplib, lib_t* local_maplib, elfheader_t* head);
void CalcStack(elfheader_t* h, uint32_t* stacksz, int* stackalign);
uintptr_t GetEntryPoint(lib_t* maplib, elfheader_t* h);
uintptr_t GetLastByte(elfheader_t* h);
void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* weaksymbols, kh_mapsymbols_t* localsymbols, elfheader_t* h);
int LoadNeededLibs(elfheader_t* h, lib_t *maplib, library_t* parent, box86context_t* box86, x86emu_t* emu);
int FinalizeNeededLibs(elfheader_t* h, lib_t *maplib, box86context_t *box86, x86emu_t* emu);
int LoadNeededLibs(elfheader_t* h, lib_t *maplib, needed_libs_t* neededlibs, int local, box86context_t *box86, x86emu_t* emu);
uintptr_t GetElfInit(elfheader_t* h);
uintptr_t GetElfFini(elfheader_t* h);
void RunElfInit(elfheader_t* h, x86emu_t *emu);
void RunElfFini(elfheader_t* h, x86emu_t *emu);
void RunDeferedElfInit(x86emu_t *emu);
void* GetBaseAddress(elfheader_t* h);
void* GetElfDelta(elfheader_t* h);
uint32_t GetBaseSize(elfheader_t* h);
int IsAddressInElfSpace(elfheader_t* h, uintptr_t addr);
elfheader_t* FindElfAddress(box86context_t *context, uintptr_t addr);
const char* FindNearestSymbolName(elfheader_t* h, void* p, uintptr_t* start, uint32_t* sz);
void* GetGSBase(box86context_t *context);
int32_t GetTLSBase(elfheader_t* h);
uint32_t GetTLSSize(elfheader_t* h);
void* GetTLSPointer(box86context_t* context, elfheader_t* h);
void* GetDTatOffset(box86context_t* context, int index, int offset);
#ifdef DYNAREC
dynablocklist_t* GetDynablocksFromAddress(box86context_t *context, uintptr_t addr);
dynablocklist_t* GetDynablocksFromElf(elfheader_t* h);
#endif
void ResetSpecialCaseMainElf(elfheader_t* h);
void CreateMemorymapFile(box86context_t* context, int fd);
#endif //__ELF_LOADER_H_
+6 -3
View File
@@ -177,7 +177,7 @@ my_GTypeValueTable_t* findFreeGTypeValueTable(my_GTypeValueTable_t* fcts);
my_GTypeInfo_t* findFreeGTypeInfo(my_GTypeInfo_t* fcts, int parent);
my_GtkTypeInfo_t* findFreeGtkTypeInfo(my_GtkTypeInfo_t* fcts, int parent);
void InitGTKClass(box86context_t* context, bridge_t *bridge);
void InitGTKClass(bridge_t *bridge);
void FiniGTKClass();
void SetGObjectID(int id);
@@ -188,8 +188,11 @@ void SetGTypeName(void* f);
void* wrapCopyGTKClass(void* class, int type);
void my_checkGlobalGdkDisplay(box86context_t* context);
void my_setGlobalGThreadsInit(box86context_t* context);
void my_checkGlobalGdkDisplay();
void my_setGlobalGThreadsInit();
void** my_GetGTKDisplay();
void** my_GetGthreadsGotInitialized();
typedef struct my_signal_s {
uint32_t sign; // signature
+13
View File
@@ -552,6 +552,19 @@ static kh_inline khint_t __ac_Wang_hash(khint_t key)
code; \
} }
/*! @function
@abstract Iterate over the entries in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@param kvar Variable to which key will be assigned
@param code Block of code to execute
*/
#define kh_foreach_key(h, kvar, code) { khint_t __i; \
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
if (!kh_exist(h,__i)) continue; \
(kvar) = kh_key(h,__i); \
code; \
} }
/*! @function
@abstract Iterate over the values in the hash table
@param h Pointer to the hash table [khash_t(name)*]
+6 -4
View File
@@ -11,10 +11,11 @@ typedef struct box86context_s box86context_t;
typedef struct x86emu_s x86emu_t;
typedef struct elfheader_s elfheader_t;
typedef struct box86context_s box86context_t;
typedef struct needed_libs_s needed_libs_t;
typedef struct kh_mapoffsets_s kh_mapoffsets_t;
typedef char* cstr_t;
lib_t *NewLibrarian(box86context_t* context);
lib_t *NewLibrarian(box86context_t* context, int ownlibs);
void FreeLibrarian(lib_t **maplib);
dlprivate_t *NewDLPrivate();
void FreeDLPrivate(dlprivate_t **lib);
@@ -23,11 +24,12 @@ box86context_t* GetLibrarianContext(lib_t* maplib);
kh_mapsymbols_t* GetMapSymbol(lib_t* maplib);
kh_mapsymbols_t* GetWeakSymbol(lib_t* maplib);
kh_mapsymbols_t* GetLocalSymbol(lib_t* maplib);
int AddNeededLib(lib_t* maplib, library_t* parent, const char* path, box86context_t* box86, x86emu_t* emu); // 0=success, 1=error
int FinalizeNeededLib(lib_t* maplib, const char* path, box86context_t* box86, x86emu_t* emu);
library_t* GetLib(lib_t* maplib, const char* name);
int AddNeededLib(lib_t* maplib, needed_libs_t* neededlibs, int local, const char* path, box86context_t* box86, x86emu_t* emu); // 0=success, 1=error
library_t* GetLibMapLib(lib_t* maplib, const char* name);
library_t* GetLibInternal(const char* name);
uintptr_t FindGlobalSymbol(lib_t *maplib, const char* name);
int GetNoSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t* self);
int GetSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self);
int GetGlobalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end);
int GetGlobalNoWeakSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end);
int GetLocalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self);
+11 -5
View File
@@ -3,13 +3,15 @@
#include <stdint.h>
typedef struct library_s library_t;
typedef struct lib_s lib_t;
typedef struct kh_symbolmap_s kh_symbolmap_t;
typedef struct box86context_s box86context_t;
typedef struct x86emu_s x86emu_t;
typedef struct needed_libs_s needed_libs_t;
library_t *NewLibrary(const char* path, box86context_t* box86);
int AddSymbolsLibrary(library_t* lib, x86emu_t* emu);
int FinalizeLibrary(library_t* lib, x86emu_t* emu);
int AddSymbolsLibrary(lib_t* maplib, library_t* lib, x86emu_t* emu);
int FinalizeLibrary(library_t* lib, lib_t* local_maplib, x86emu_t* emu);
int ReloadLibrary(library_t* lib, x86emu_t* emu);
void InactiveLibrary(library_t* lib);
void Free1Library(library_t **lib);
@@ -19,12 +21,16 @@ int IsSameLib(library_t* lib, const char* path); // check if lib is same (pat
int GetLibSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end);
int GetLibNoWeakSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end);
int GetLibLocalSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end);
kh_symbolmap_t * fillGLProcWrapper();
void freeProcWrapper(kh_symbolmap_t** symbolmap);
void LibAddNeededLib(library_t* lib, library_t* needed);
void fillGLProcWrapper(box86context_t* context);
void freeGLProcWrapper(box86context_t* context);
void fillALProcWrapper(box86context_t* context);
void freeALProcWrapper(box86context_t* context);
needed_libs_t* GetNeededLibs(library_t* lib);
int GetNeededLibN(library_t* lib);
library_t* GetNeededLib(library_t* lib, int idx);
lib_t* GetMaplib(library_t* lib);
int GetElfIndex(library_t* lib); // -1 if no elf (i.e. native)
void* GetHandle(library_t* lib); // NULL if not native
#endif //__LIBRARY_H_
Loaded 100 of 258 files, more files were not shown because too many files have changed in this diff. Show more